From f94800dbbb6c4adbda0298060873d945938a00ce Mon Sep 17 00:00:00 2001 From: David Dal Busco Date: Wed, 21 Feb 2024 18:44:07 +0100 Subject: [PATCH] feat: add support for index canister --- cli/src/declarations/icp_index.d.ts | 119 ++++++++++++++++++++++++++ cli/src/declarations/icp_index.did | 80 +++++++++++++++++ cli/src/declarations/icp_index.idl.js | 107 +++++++++++++++++++++++ cli/src/modules/icp-index.ts | 37 ++++++++ cli/src/modules/modules.ts | 3 +- modules.json | 11 ++- 6 files changed, 355 insertions(+), 2 deletions(-) create mode 100644 cli/src/declarations/icp_index.d.ts create mode 100644 cli/src/declarations/icp_index.did create mode 100644 cli/src/declarations/icp_index.idl.js create mode 100644 cli/src/modules/icp-index.ts diff --git a/cli/src/declarations/icp_index.d.ts b/cli/src/declarations/icp_index.d.ts new file mode 100644 index 0000000..790b050 --- /dev/null +++ b/cli/src/declarations/icp_index.d.ts @@ -0,0 +1,119 @@ +import type {ActorMethod} from '@dfinity/agent'; +import type {IDL} from '@dfinity/candid'; +import type {Principal} from '@dfinity/principal'; + +export interface Account { + owner: Principal; + subaccount: [] | [Uint8Array | number[]]; +} +export interface GetAccountIdentifierTransactionsArgs { + max_results: bigint; + start: [] | [bigint]; + account_identifier: string; +} +export interface GetAccountIdentifierTransactionsError { + message: string; +} +export interface GetAccountIdentifierTransactionsResponse { + balance: bigint; + transactions: Array; + oldest_tx_id: [] | [bigint]; +} +export type GetAccountIdentifierTransactionsResult = + | { + Ok: GetAccountIdentifierTransactionsResponse; + } + | {Err: GetAccountIdentifierTransactionsError}; +export interface GetAccountTransactionsArgs { + max_results: bigint; + start: [] | [bigint]; + account: Account; +} +export interface GetBlocksRequest { + start: bigint; + length: bigint; +} +export interface GetBlocksResponse { + blocks: Array; + chain_length: bigint; +} +export interface HttpRequest { + url: string; + method: string; + body: Uint8Array | number[]; + headers: Array<[string, string]>; +} +export interface HttpResponse { + body: Uint8Array | number[]; + headers: Array<[string, string]>; + status_code: number; +} +export interface InitArg { + ledger_id: Principal; +} +export type Operation = + | { + Approve: { + fee: Tokens; + from: string; + allowance: Tokens; + expires_at: [] | [TimeStamp]; + spender: string; + }; + } + | {Burn: {from: string; amount: Tokens}} + | {Mint: {to: string; amount: Tokens}} + | { + Transfer: { + to: string; + fee: Tokens; + from: string; + amount: Tokens; + }; + } + | { + TransferFrom: { + to: string; + fee: Tokens; + from: string; + amount: Tokens; + spender: string; + }; + }; +export interface Status { + num_blocks_synced: bigint; +} +export interface TimeStamp { + timestamp_nanos: bigint; +} +export interface Tokens { + e8s: bigint; +} +export interface Transaction { + memo: bigint; + icrc1_memo: [] | [Uint8Array | number[]]; + operation: Operation; + created_at_time: [] | [TimeStamp]; +} +export interface TransactionWithId { + id: bigint; + transaction: Transaction; +} +export interface _SERVICE { + get_account_identifier_balance: ActorMethod<[string], bigint>; + get_account_identifier_transactions: ActorMethod< + [GetAccountIdentifierTransactionsArgs], + GetAccountIdentifierTransactionsResult + >; + get_account_transactions: ActorMethod< + [GetAccountTransactionsArgs], + GetAccountIdentifierTransactionsResult + >; + get_blocks: ActorMethod<[GetBlocksRequest], GetBlocksResponse>; + http_request: ActorMethod<[HttpRequest], HttpResponse>; + icrc1_balance_of: ActorMethod<[Account], bigint>; + ledger_id: ActorMethod<[], Principal>; + status: ActorMethod<[], Status>; +} +export declare const idlFactory: IDL.InterfaceFactory; +export declare const init: ({IDL}: {IDL: IDL}) => IDL.Type[]; diff --git a/cli/src/declarations/icp_index.did b/cli/src/declarations/icp_index.did new file mode 100644 index 0000000..a89348e --- /dev/null +++ b/cli/src/declarations/icp_index.did @@ -0,0 +1,80 @@ +type Account = record { owner : principal; subaccount : opt vec nat8 }; +type GetAccountIdentifierTransactionsArgs = record { + max_results : nat64; + start : opt nat64; + account_identifier : text; +}; +type GetAccountTransactionsArgs = record { + account : Account; + // The txid of the last transaction seen by the client. + // If None then the results will start from the most recent + // txid. + start : opt nat; + // Maximum number of transactions to fetch. + max_results : nat; +}; +type GetAccountIdentifierTransactionsError = record { message : text }; +type GetAccountIdentifierTransactionsResponse = record { + balance : nat64; + transactions : vec TransactionWithId; + oldest_tx_id : opt nat64; +}; +type GetBlocksRequest = record { start : nat; length : nat }; +type GetBlocksResponse = record { blocks : vec vec nat8; chain_length : nat64 }; +type HttpRequest = record { + url : text; + method : text; + body : vec nat8; + headers : vec record { text; text }; +}; +type HttpResponse = record { + body : vec nat8; + headers : vec record { text; text }; + status_code : nat16; +}; +type InitArg = record { ledger_id : principal }; +type Operation = variant { + Approve : record { + fee : Tokens; + from : text; + allowance : Tokens; + expires_at : opt TimeStamp; + spender : text; + }; + Burn : record { from : text; amount : Tokens }; + Mint : record { to : text; amount : Tokens }; + Transfer : record { to : text; fee : Tokens; from : text; amount : Tokens }; + TransferFrom : record { + to : text; + fee : Tokens; + from : text; + amount : Tokens; + spender : text; + }; +}; +type GetAccountIdentifierTransactionsResult = variant { + Ok : GetAccountIdentifierTransactionsResponse; + Err : GetAccountIdentifierTransactionsError; +}; +type Status = record { num_blocks_synced : nat64 }; +type TimeStamp = record { timestamp_nanos : nat64 }; +type Tokens = record { e8s : nat64 }; +type Transaction = record { + memo : nat64; + icrc1_memo : opt vec nat8; + operation : Operation; + created_at_time : opt TimeStamp; +}; +type TransactionWithId = record { id : nat64; transaction : Transaction }; +service : (InitArg) -> { + get_account_identifier_balance : (text) -> (nat64) query; + get_account_identifier_transactions : ( + GetAccountIdentifierTransactionsArgs, + ) -> (GetAccountIdentifierTransactionsResult) query; + get_account_transactions : (GetAccountTransactionsArgs) -> (GetAccountIdentifierTransactionsResult) query; + get_blocks : (GetBlocksRequest) -> (GetBlocksResponse) query; + http_request : (HttpRequest) -> (HttpResponse) query; + ledger_id : () -> (principal) query; + status : () -> (Status) query; + icrc1_balance_of : (Account) -> (nat64) query; +} \ No newline at end of file diff --git a/cli/src/declarations/icp_index.idl.js b/cli/src/declarations/icp_index.idl.js new file mode 100644 index 0000000..5926884 --- /dev/null +++ b/cli/src/declarations/icp_index.idl.js @@ -0,0 +1,107 @@ +export const idlFactory = ({IDL}) => { + const InitArg = IDL.Record({ledger_id: IDL.Principal}); + const GetAccountIdentifierTransactionsArgs = IDL.Record({ + max_results: IDL.Nat64, + start: IDL.Opt(IDL.Nat64), + account_identifier: IDL.Text + }); + const Tokens = IDL.Record({e8s: IDL.Nat64}); + const TimeStamp = IDL.Record({timestamp_nanos: IDL.Nat64}); + const Operation = IDL.Variant({ + Approve: IDL.Record({ + fee: Tokens, + from: IDL.Text, + allowance: Tokens, + expires_at: IDL.Opt(TimeStamp), + spender: IDL.Text + }), + Burn: IDL.Record({from: IDL.Text, amount: Tokens}), + Mint: IDL.Record({to: IDL.Text, amount: Tokens}), + Transfer: IDL.Record({ + to: IDL.Text, + fee: Tokens, + from: IDL.Text, + amount: Tokens + }), + TransferFrom: IDL.Record({ + to: IDL.Text, + fee: Tokens, + from: IDL.Text, + amount: Tokens, + spender: IDL.Text + }) + }); + const Transaction = IDL.Record({ + memo: IDL.Nat64, + icrc1_memo: IDL.Opt(IDL.Vec(IDL.Nat8)), + operation: Operation, + created_at_time: IDL.Opt(TimeStamp) + }); + const TransactionWithId = IDL.Record({ + id: IDL.Nat64, + transaction: Transaction + }); + const GetAccountIdentifierTransactionsResponse = IDL.Record({ + balance: IDL.Nat64, + transactions: IDL.Vec(TransactionWithId), + oldest_tx_id: IDL.Opt(IDL.Nat64) + }); + const GetAccountIdentifierTransactionsError = IDL.Record({ + message: IDL.Text + }); + const GetAccountIdentifierTransactionsResult = IDL.Variant({ + Ok: GetAccountIdentifierTransactionsResponse, + Err: GetAccountIdentifierTransactionsError + }); + const Account = IDL.Record({ + owner: IDL.Principal, + subaccount: IDL.Opt(IDL.Vec(IDL.Nat8)) + }); + const GetAccountTransactionsArgs = IDL.Record({ + max_results: IDL.Nat, + start: IDL.Opt(IDL.Nat), + account: Account + }); + const GetBlocksRequest = IDL.Record({ + start: IDL.Nat, + length: IDL.Nat + }); + const GetBlocksResponse = IDL.Record({ + blocks: IDL.Vec(IDL.Vec(IDL.Nat8)), + chain_length: IDL.Nat64 + }); + const HttpRequest = IDL.Record({ + url: IDL.Text, + method: IDL.Text, + body: IDL.Vec(IDL.Nat8), + headers: IDL.Vec(IDL.Tuple(IDL.Text, IDL.Text)) + }); + const HttpResponse = IDL.Record({ + body: IDL.Vec(IDL.Nat8), + headers: IDL.Vec(IDL.Tuple(IDL.Text, IDL.Text)), + status_code: IDL.Nat16 + }); + const Status = IDL.Record({num_blocks_synced: IDL.Nat64}); + return IDL.Service({ + get_account_identifier_balance: IDL.Func([IDL.Text], [IDL.Nat64], ['query']), + get_account_identifier_transactions: IDL.Func( + [GetAccountIdentifierTransactionsArgs], + [GetAccountIdentifierTransactionsResult], + ['query'] + ), + get_account_transactions: IDL.Func( + [GetAccountTransactionsArgs], + [GetAccountIdentifierTransactionsResult], + ['query'] + ), + get_blocks: IDL.Func([GetBlocksRequest], [GetBlocksResponse], ['query']), + http_request: IDL.Func([HttpRequest], [HttpResponse], ['query']), + icrc1_balance_of: IDL.Func([Account], [IDL.Nat64], ['query']), + ledger_id: IDL.Func([], [IDL.Principal], ['query']), + status: IDL.Func([], [Status], ['query']) + }); +}; +export const init = ({IDL}) => { + const InitArg = IDL.Record({ledger_id: IDL.Principal}); + return [InitArg]; +}; diff --git a/cli/src/modules/icp-index.ts b/cli/src/modules/icp-index.ts new file mode 100644 index 0000000..54e9d7d --- /dev/null +++ b/cli/src/modules/icp-index.ts @@ -0,0 +1,37 @@ +import {IDL} from '@dfinity/candid'; +import {Principal} from '@dfinity/principal'; +import {assertNonNullish} from '@dfinity/utils'; +import {init} from '../declarations/icp_index.idl'; +import {Module} from '../services/modules.services'; +import type {ModuleDescription, ModuleInstallParams} from '../types/module'; + +export const ICP_INDEX: ModuleDescription = { + key: 'icp_index', + name: 'ICP Index', + canisterId: 'qhbym-qaaaa-aaaaa-aaafq-cai' +}; + +export class IcpIndexModule extends Module { + override async install(context: ModuleInstallParams): Promise { + const {state, ...rest} = context; + + const canisterId = state.getModule('icp_ledger')?.canisterId; + + assertNonNullish( + canisterId, + 'Cannot configure ICP index because the ICP ledger id is unknown.' + ); + + // Type definitions generated by Candid are not clean enough. + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + const arg = IDL.encode(init({IDL}), [{ledger_id: Principal.fromText(canisterId)}]); + + await super.install({ + state, + ...rest, + arg + }); + } +} + +export const icpIndex = new IcpIndexModule(ICP_INDEX); diff --git a/cli/src/modules/modules.ts b/cli/src/modules/modules.ts index badd968..0acc45e 100644 --- a/cli/src/modules/modules.ts +++ b/cli/src/modules/modules.ts @@ -1,5 +1,6 @@ +import {icpIndex} from './icp-index'; import {icpLedger} from './icp-ledger'; import {internetIdentity} from './internet-identity'; import {satellite} from './satellite'; -export const modules = [internetIdentity, icpLedger, satellite]; +export const modules = [internetIdentity, icpLedger, icpIndex, satellite]; diff --git a/modules.json b/modules.json index 1efd080..bc40dd9 100644 --- a/modules.json +++ b/modules.json @@ -20,10 +20,19 @@ "icp_ledger": { "commit": "d87954601e4b22972899e9957e800406a0a6b929", "sha256": "55accf02dfef466476372874daa9395545f932d2a114d999f8965928b36833ec", - "repo": "https://github.com/junobuild/juno", + "repo": "https://github.com/dfinity/ic", "url": "https://download.dfinity.systems/ic/{commit}/canisters/ledger-canister.wasm.gz", "candid": [ "https://raw.githubusercontent.com/dfinity/ic/{commit}/rs/rosetta-api/icp_ledger/ledger.did" ] + }, + "icp_index": { + "commit": "d87954601e4b22972899e9957e800406a0a6b929", + "sha256": "e6aeca9c32d0b66d38966bf7a552ac34ea4b52f113b39a0449b95bef450e63b7", + "repo": "https://github.com/dfinity/ic", + "url": "https://download.dfinity.systems/ic/{commit}/canisters/ic-icp-index-canister.wasm.gz", + "candid": [ + "https://raw.githubusercontent.com/dfinity/ic/{commit}/rs/rosetta-api/icp_ledger/index/index.did" + ] } }