Skip to content

Commit

Permalink
Uncommitted work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
dskloetd committed Nov 1, 2024
1 parent 9168785 commit 07d436b
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 9 deletions.
21 changes: 12 additions & 9 deletions packages/nns/src/governance.canister.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ import type {
ProposalId,
ProposalInfo,
} from "./types/governance_converters";
import {
getRandomMemo,
memoToNeuronAccountIdentifier,
} from "./utils/neurons.utils";

export class GovernanceCanister {
private constructor(
Expand Down Expand Up @@ -208,7 +212,7 @@ export class GovernanceCanister {
* Returns the latest reward event.
*
* If `certified` is true, the request is fetched as an update call, otherwise
* it's fetched using a query call.
* its fetched using a query call.
*
*/
public getLastestRewardEvent = async (
Expand Down Expand Up @@ -267,17 +271,16 @@ export class GovernanceCanister {
throw new InsufficientAmountError(stake);
}

const nonceBytes = new Uint8Array(randomBytes(8));
const nonce = uint8ArrayToBigInt(nonceBytes);
const toSubAccount = this.buildNeuronStakeSubAccount(nonceBytes, principal);
const accountIdentifier = AccountIdentifier.fromPrincipal({
principal: this.canisterId,
subAccount: toSubAccount,
const memo = getRandomMemo();
const accountIdentifier = memoToNeuronAccountIdentifier({
controller: principal,
memo,
governanceCanisterId: this.canisterId,
});

// Send amount to the ledger.
await ledgerCanister.transfer({
memo: nonce,
memo,
amount: stake,
fromSubAccount,
to: accountIdentifier,
Expand All @@ -289,7 +292,7 @@ export class GovernanceCanister {
const neuronId: NeuronId | undefined =
await this.claimOrRefreshNeuronFromAccount({
controller: principal,
memo: nonce,
memo,
});

// Typescript was complaining with `neuronId || new NeuronNotFound()`:
Expand Down
53 changes: 53 additions & 0 deletions packages/nns/src/utils/neurons.utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
import { AccountIdentifier, SubAccount } from "@dfinity/ledger-icp";
import type { Principal } from "@dfinity/principal";
import {
arrayOfNumberToUint8Array,
asciiStringToByteArray,
bigIntToUint8Array,
uint8ArrayToBigInt,
} from "@dfinity/utils";
import { sha256 } from "@noble/hashes/sha256";
import randomBytes from "randombytes";
import { Vote } from "../enums/governance.enums";
import type {
Ballot,
Expand Down Expand Up @@ -89,3 +99,46 @@ export const votedNeurons = ({
(neuron: NeuronInfo) =>
getNeuronVoteForProposal({ proposal, neuron }) !== Vote.Unspecified,
);

export const getRandomMemo = (): bigint => {
const bytes = randomBytes(8);
return uint8ArrayToBigInt(bytes);
};

export const memoToNeuronSubaccount = ({
controller,
memo,
}: {
controller: Principal;
memo: bigint;
}): SubAccount => {
const padding = asciiStringToByteArray("neuron-stake");
const shaObj = sha256.create();
shaObj.update(
arrayOfNumberToUint8Array([
0x0c, // Should be padding.length
...padding,
...controller.toUint8Array(),
...bigIntToUint8Array(memo),
]),
);

const ret = SubAccount.fromBytes(shaObj.digest());
return ret as SubAccount;
};

export const memoToNeuronAccountIdentifier = ({
controller,
memo,
governanceCanisterId,
}: {
controller: Principal;
memo: bigint;
governanceCanisterId: Principal;
}): AccountIdentifier => {
const subAccount = memoToNeuronSubaccount({ controller, memo });
return AccountIdentifier.fromPrincipal({
principal: governanceCanisterId,
subAccount,
});
};

0 comments on commit 07d436b

Please sign in to comment.