Skip to content
Closed
2 changes: 1 addition & 1 deletion dfx.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"dfx": "0.24.0",
"dfx": "0.24.1",
"networks": {
"local": {
"bind": "127.0.0.1:8080",
Expand Down
290 changes: 182 additions & 108 deletions package-lock.json

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@
},
"homepage": "https://github.com/dfinity/hardware-wallet-cli#readme",
"dependencies": {
"@dfinity/agent": "^2.1.2",
"@dfinity/ledger-icrc": "^2.6.0",
"@dfinity/nns": "^7.0.0",
"@dfinity/agent": "^2.1.3",
"@dfinity/ledger-icrc": "^2.6.2",
"@dfinity/nns": "^7.0.2",
"@dfinity/principal": "^2.1.2",
"@dfinity/sns": "^3.2.1",
"@dfinity/utils": "^2.5.0",
"@dfinity/sns": "^3.2.3",
"@dfinity/utils": "^2.6.0",
"@ledgerhq/hw-transport-node-hid-noevents": "^6.3.0",
"@ledgerhq/hw-transport-webhid": "^6.27.1",
"@zondax/ledger-icp": "^0.6.0",
"@zondax/ledger-icp": "^3.2.4",
"chalk": "^4.1.2",
"commander": "^9.0.0",
"node-fetch": "^2.6.1",
Expand Down
74 changes: 74 additions & 0 deletions src/bls-test/ledger-icp/icrc21.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import type { Principal } from "@dfinity/principal";
import type { ActorMethod } from "@dfinity/agent";
import type { IDL } from "@dfinity/candid";

export interface DurationSeconds {
amount: bigint;
}
export interface TextValue {
content: string;
}
export interface TimestampSeconds {
amount: bigint;
}
export interface TokenAmount {
decimals: number;
amount: bigint;
symbol: string;
}
export type Value =
| { Text: TextValue }
| { TokenAmount: TokenAmount }
| { TimestampSeconds: TimestampSeconds }
| { DurationSeconds: DurationSeconds };
export interface icrc21_consent_info {
metadata: icrc21_consent_message_metadata;
consent_message: icrc21_consent_message;
}
export type icrc21_consent_message =
| {
FieldsDisplayMessage: {
fields: Array<[string, Value]>;
intent: string;
};
}
| { GenericDisplayMessage: string };
export interface icrc21_consent_message_metadata {
utc_offset_minutes: [] | [number];
language: string;
}
export interface icrc21_consent_message_request {
arg: Uint8Array | number[];
method: string;
user_preferences: icrc21_consent_message_spec;
}
export type icrc21_consent_message_response =
| { Ok: icrc21_consent_info }
| { Err: icrc21_error };
export interface icrc21_consent_message_spec {
metadata: icrc21_consent_message_metadata;
device_spec: [] | [{ GenericDisplay: null } | { FieldsDisplay: null }];
}
export type icrc21_error =
| {
GenericError: { description: string; error_code: bigint };
}
| { InsufficientPayment: icrc21_error_info }
| { UnsupportedCanisterCall: icrc21_error_info }
| { ConsentMessageUnavailable: icrc21_error_info };
export interface icrc21_error_info {
description: string;
}
export interface _SERVICE {
greet: ActorMethod<[string], string>;
icrc10_supported_standards: ActorMethod<
[],
Array<{ url: string; name: string }>
>;
icrc21_canister_call_consent_message: ActorMethod<
[icrc21_consent_message_request],
icrc21_consent_message_response
>;
}
export declare const idlFactory: IDL.InterfaceFactory;
export declare const init: (args: { IDL: typeof IDL }) => IDL.Type[];
139 changes: 139 additions & 0 deletions src/bls-test/ledger-icp/icrc21.idl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import { IDL } from "@dfinity/candid";
const icrc21_consent_message_metadata = IDL.Record({
utc_offset_minutes: IDL.Opt(IDL.Int16),
language: IDL.Text,
});
const icrc21_consent_message_spec = IDL.Record({
metadata: icrc21_consent_message_metadata,
device_spec: IDL.Opt(
IDL.Variant({ GenericDisplay: IDL.Null, FieldsDisplay: IDL.Null })
),
});
export const icrc21_consent_message_request = IDL.Record({
arg: IDL.Vec(IDL.Nat8),
method: IDL.Text,
user_preferences: icrc21_consent_message_spec,
});
const TextValue = IDL.Record({ content: IDL.Text });
const TokenAmount = IDL.Record({
decimals: IDL.Nat8,
amount: IDL.Nat64,
symbol: IDL.Text,
});
const TimestampSeconds = IDL.Record({ amount: IDL.Nat64 });
const DurationSeconds = IDL.Record({ amount: IDL.Nat64 });
const Value = IDL.Variant({
Text: TextValue,
TokenAmount: TokenAmount,
TimestampSeconds: TimestampSeconds,
DurationSeconds: DurationSeconds,
});
export const icrc21_consent_message = IDL.Variant({
FieldsDisplayMessage: IDL.Record({
fields: IDL.Vec(IDL.Tuple(IDL.Text, Value)),
intent: IDL.Text,
}),
GenericDisplayMessage: IDL.Text,
});
const icrc21_consent_info = IDL.Record({
metadata: icrc21_consent_message_metadata,
consent_message: icrc21_consent_message,
});
const icrc21_error_info = IDL.Record({ description: IDL.Text });
const icrc21_error = IDL.Variant({
GenericError: IDL.Record({
description: IDL.Text,
error_code: IDL.Nat,
}),
InsufficientPayment: icrc21_error_info,
UnsupportedCanisterCall: icrc21_error_info,
ConsentMessageUnavailable: icrc21_error_info,
});
export const icrc21_consent_message_response = IDL.Variant({
Ok: icrc21_consent_info,
Err: icrc21_error,
});
export const greetFunction = IDL.Func([IDL.Text], [IDL.Text], ["query"]);
export const icrc10SupportedStandardsFunction = IDL.Func(
[],
[IDL.Vec(IDL.Record({ url: IDL.Text, name: IDL.Text }))],
["query"]
);
export const icrc21CanisterCallConsentMessageFunction = IDL.Func(
[icrc21_consent_message_request],
[icrc21_consent_message_response],
[]
);

export const idlFactory = ({ IDL }) => {
const icrc21_consent_message_metadata = IDL.Record({
utc_offset_minutes: IDL.Opt(IDL.Int16),
language: IDL.Text,
});
const icrc21_consent_message_spec = IDL.Record({
metadata: icrc21_consent_message_metadata,
device_spec: IDL.Opt(
IDL.Variant({ GenericDisplay: IDL.Null, FieldsDisplay: IDL.Null })
),
});
const icrc21_consent_message_request = IDL.Record({
arg: IDL.Vec(IDL.Nat8),
method: IDL.Text,
user_preferences: icrc21_consent_message_spec,
});
const TextValue = IDL.Record({ content: IDL.Text });
const TokenAmount = IDL.Record({
decimals: IDL.Nat8,
amount: IDL.Nat64,
symbol: IDL.Text,
});
const TimestampSeconds = IDL.Record({ amount: IDL.Nat64 });
const DurationSeconds = IDL.Record({ amount: IDL.Nat64 });
const Value = IDL.Variant({
Text: TextValue,
TokenAmount: TokenAmount,
TimestampSeconds: TimestampSeconds,
DurationSeconds: DurationSeconds,
});
const icrc21_consent_message = IDL.Variant({
FieldsDisplayMessage: IDL.Record({
fields: IDL.Vec(IDL.Tuple(IDL.Text, Value)),
intent: IDL.Text,
}),
GenericDisplayMessage: IDL.Text,
});
const icrc21_consent_info = IDL.Record({
metadata: icrc21_consent_message_metadata,
consent_message: icrc21_consent_message,
});
const icrc21_error_info = IDL.Record({ description: IDL.Text });
const icrc21_error = IDL.Variant({
GenericError: IDL.Record({
description: IDL.Text,
error_code: IDL.Nat,
}),
InsufficientPayment: icrc21_error_info,
UnsupportedCanisterCall: icrc21_error_info,
ConsentMessageUnavailable: icrc21_error_info,
});
const icrc21_consent_message_response = IDL.Variant({
Ok: icrc21_consent_info,
Err: icrc21_error,
});
return IDL.Service({
greet: IDL.Func([IDL.Text], [IDL.Text], []),
icrc10_supported_standards: IDL.Func(
[],
[IDL.Vec(IDL.Record({ url: IDL.Text, name: IDL.Text }))],
["query"]
),
icrc21_canister_call_consent_message: IDL.Func(
[icrc21_consent_message_request],
[icrc21_consent_message_response],
[]
),
});
};
export const init = ({ IDL }) => {
return [];
};
71 changes: 68 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,14 @@ import {
isCurrentVersionSmallerThanFullCandidParser,
} from "./utils";
import { CANDID_PARSER_VERSION, HOTKEY_PERMISSIONS } from "./constants";
import { AnonymousIdentity, Identity } from "@dfinity/agent";
import { Actor, AnonymousIdentity, Identity } from "@dfinity/agent";
import { SnsGovernanceCanister, SnsNeuronId } from "@dfinity/sns";
import { TokenAmountV2, fromNullable, toNullable } from "@dfinity/utils";
import {
TokenAmountV2,
fromNullable,
jsonReplacer,
toNullable,
} from "@dfinity/utils";
import {
encodeIcrcAccount,
IcrcAccount,
Expand All @@ -57,6 +62,7 @@ import "node-window-polyfill/register";
// @ts-ignore (no types are available)
import fetch from "node-fetch";
import { Secp256k1PublicKey } from "./ledger/secp256k1";
import { idlFactory } from "./bls-test/ledger-icp/icrc21.idl";

(global as any).fetch = fetch;
// Add polyfill for `window.fetch` for agent-js to work.
Expand Down Expand Up @@ -758,6 +764,58 @@ async function setNodeProviderAccount(account: AccountIdentifier) {
ok();
}

async function callIcrc21() {
const identity = await getIdentity();
// await assertLedgerVersion({ identity, minVersion: CANDID_PARSER_VERSION });
const spenderOwner = Principal.fromText("rdmx6-jaaaa-aaaaa-aaadq-cai");
// const hwLedger = LedgerCanister.create({
// agent: await getCurrentAgent(identity),
// });
// await hwLedger.icrc2Approve({
// spender: { owner: spenderOwner, subaccount: [] },
// amount: 100_000_000n,
// expires_at: BigInt(Date.now() * 1_000_000 + 1_000_000_000 * 60 * 60 * 24),
// });
const ledgerCanister = IcrcLedgerCanister.create({
agent: await getCurrentAgent(identity),
// CHAT
// canisterId: Principal.fromText("ekfwe-siaaa-aaaaf-qapta-cai"),
// ckBTC
// canisterId: Principal.fromText("mxzaz-hqaaa-aaaar-qaada-cai"),
// Test canister id
// canisterId: Principal.fromText("suje7-zaaaa-aaaad-abnzq-cai"),
// TESTICP Ledger canister id
canisterId: Principal.fromText("xafvr-biaaa-aaaai-aql5q-cai"),
});

// const anonymousIdentity = new AnonymousIdentityWrapper();

// const actor = Actor.createActor(idlFactory, {
// agent: await getCurrentAgent(identity),
// // agent: await getCurrentAgent(anonymousIdentity),
// canisterId: Principal.fromText("suje7-zaaaa-aaaad-abnzq-cai"),
// });

try {
// const response = await actor.greet("Hello, world!");
// console.log(`Response from ICRC21 canister: ${response}`);

const response = await ledgerCanister.approve({
spender: { owner: spenderOwner, subaccount: [] },
amount: 100_000_000n,
expires_at: BigInt(Date.now() * 1_000_000 + 1_000_000_000 * 60 * 60 * 24),
});

console.log(`Response from approve canister: ${response}`);

ok("Approved 1 token for spending.");
} catch (error: any) {
console.log("in da catch");
console.log(error);
err(error);
}
}

/**
* Fetches the balance of the main account on the wallet.
*/
Expand Down Expand Up @@ -785,6 +843,7 @@ async function run(f: () => void) {
try {
await f();
} catch (error: any) {
err(JSON.stringify(error, jsonReplacer));
err(error);
}
}
Expand Down Expand Up @@ -1306,6 +1365,11 @@ async function main() {
)
.action((args) => run(() => setNodeProviderAccount(args.account)))
);

const icrc21 = new Command("icrc-21")
.description("Commands for making ICRC 21 calls.")
.showSuggestionAfterError()
.addCommand(new Command("call").action((args) => run(() => callIcrc21())));
program
.description("A CLI for the Ledger hardware wallet.")
.enablePositionalOptions()
Expand Down Expand Up @@ -1333,7 +1397,8 @@ async function main() {
.addCommand(neuron)
.addCommand(sns)
.addCommand(icrc)
.addCommand(nodeProvider);
.addCommand(nodeProvider)
.addCommand(icrc21);

await program.parseAsync(process.argv);
}
Expand Down
Loading