diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index d46cae2af..5f2b012df 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -2,10 +2,41 @@ ## [Unreleased] +### Added + +* feat: adds support for verified queries against management canister + * includes support for `fetch_canister_logs` in the actor provided by `getManagementCanister` + * also includes support for bitcoin queries + +Logging + +```ts +// Agent should not use an anonymous identity for this call, and should ideally be a canister controller +const management = await getManagementCanister({ agent }); +const logs = await management.fetch_canister_logs({ canister_id: canisterId }); +``` + +Bitcoin + +```ts +// For now, the verifyQuerySignatures option must be set to false +const agent = await makeAgent({ host: 'https://icp-api.io', verifyQuerySignatures: false }); +const management = getManagementCanister({ + agent +}); + +const result = await management.bitcoin_get_balance_query({ + address: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh', + network: { mainnet: null }, + min_confirmations: [6], +}); +``` + ### Changed * fix: pads date numbers in changelog automation. E.G. 2024-3-1 -> 2024-03-01 * feat: allow passing `DBCreateOptions` to `IdbStorage` constructor +* updated management canister interface ## [1.1.1] - 2024-03-19 diff --git a/e2e/node/basic/logging.test.ts b/e2e/node/basic/logging.test.ts new file mode 100644 index 000000000..2be54acbc --- /dev/null +++ b/e2e/node/basic/logging.test.ts @@ -0,0 +1,31 @@ +import { bufFromBufLike, getManagementCanister } from '@dfinity/agent'; +import { describe, it, expect } from 'vitest'; +import logsActor from '../canisters/logs'; +import { makeAgent } from '../utils/agent'; + +describe('canister logs', () => { + it('should make requests to the management canister', async () => { + const { canisterId } = await logsActor(); + + const management = await getManagementCanister({ agent: await makeAgent() }); + const logs = await management.fetch_canister_logs({ canister_id: canisterId }); + + expect(logs.canister_log_records.length).toBe(1); + const content = bufFromBufLike(logs.canister_log_records[0].content); + + expect(new TextDecoder().decode(content).trim()).toBe('Hello, first call!'); + }); + it('should show additional logs', async () => { + const { canisterId, actor } = await logsActor(); + + await actor.hello('second call'); + + const management = await getManagementCanister({ agent: await makeAgent() }); + const logs = await management.fetch_canister_logs({ canister_id: canisterId }); + + expect(logs.canister_log_records.length).toBe(2); + const content = bufFromBufLike(logs.canister_log_records[1].content); + + expect(new TextDecoder().decode(content).trim()).toBe('Hello, second call!'); + }); +}, 10_000); diff --git a/e2e/node/basic/mainnet.test.ts b/e2e/node/basic/mainnet.test.ts index 2a42b9a29..0c4d7bc4f 100644 --- a/e2e/node/basic/mainnet.test.ts +++ b/e2e/node/basic/mainnet.test.ts @@ -1,4 +1,11 @@ -import { Actor, AnonymousIdentity, HttpAgent, Identity, CanisterStatus } from '@dfinity/agent'; +import { + Actor, + AnonymousIdentity, + HttpAgent, + Identity, + CanisterStatus, + getManagementCanister, +} from '@dfinity/agent'; import { IDL } from '@dfinity/candid'; import { Ed25519KeyIdentity } from '@dfinity/identity'; import { Principal } from '@dfinity/principal'; @@ -161,3 +168,21 @@ describe('controllers', () => { `); }); }); + +describe('bitcoin query', async () => { + it('should return the balance of a bitcoin address', async () => { + // TODO - verify node signature for bitcoin once supported + const agent = await makeAgent({ host: 'https://icp-api.io', verifyQuerySignatures: false }); + const management = getManagementCanister({ + agent, + }); + + const result = await management.bitcoin_get_balance_query({ + address: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh', + network: { mainnet: null }, + min_confirmations: [6], + }); + console.log(`balance for address: ${result}`); + expect(result).toBeGreaterThan(0n); + }); +}); diff --git a/e2e/node/basic/mitm.test.ts b/e2e/node/basic/mitm.test.ts index a1171e00f..16de92f3a 100644 --- a/e2e/node/basic/mitm.test.ts +++ b/e2e/node/basic/mitm.test.ts @@ -12,6 +12,7 @@ mitmTest( const counter = await createActor('tnnnb-2yaaa-aaaab-qaiiq-cai', { agent: await makeAgent({ host: 'http://127.0.0.1:8888', + verifyQuerySignatures: false, }), }); await expect(counter.greet('counter')).rejects.toThrow(/Invalid certificate/); diff --git a/e2e/node/canisters/logs.ts b/e2e/node/canisters/logs.ts new file mode 100644 index 000000000..556a8ea23 --- /dev/null +++ b/e2e/node/canisters/logs.ts @@ -0,0 +1,52 @@ +import { Principal } from '@dfinity/principal'; +import agent from '../utils/agent'; +import { readFileSync } from 'fs'; +import path from 'path'; +import { Actor, ActorMethod, ActorSubclass } from '@dfinity/agent'; +import { IDL } from '@dfinity/candid'; + +export interface _SERVICE { + hello: ActorMethod<[string], undefined>; +} +export declare const init: (args: { IDL: typeof IDL }) => IDL.Type[]; + +export const idlFactory = ({ IDL }) => { + return IDL.Service({ hello: IDL.Func([IDL.Text], [], []) }); +}; + +let cache: { + canisterId: Principal; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + actor: any; +} | null = null; + +/** + * Create a counter Actor + canisterId + */ +export default async function (): Promise<{ + canisterId: Principal; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + actor: any; +}> { + if (!cache) { + const module = readFileSync(path.join(__dirname, 'logs.wasm')); + + const canisterId = await Actor.createCanister({ agent: await agent }); + await Actor.install({ module }, { canisterId, agent: await agent }); + + const actor = Actor.createActor(idlFactory, { + canisterId, + agent: await agent, + }) as ActorSubclass<_SERVICE>; + + await actor.hello('first call'); + + cache = { + canisterId, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + actor, + }; + } + + return cache; +} diff --git a/e2e/node/canisters/logs.wasm b/e2e/node/canisters/logs.wasm new file mode 100644 index 000000000..f382d09a3 Binary files /dev/null and b/e2e/node/canisters/logs.wasm differ diff --git a/e2e/node/utils/agent.ts b/e2e/node/utils/agent.ts index 718bab5d9..4eef883ae 100644 --- a/e2e/node/utils/agent.ts +++ b/e2e/node/utils/agent.ts @@ -12,8 +12,6 @@ if (Number.isNaN(port)) { export const makeAgent = async (options?: HttpAgentOptions) => { const agent = new HttpAgent({ host: `http://127.0.0.1:${process.env.REPLICA_PORT ?? 4943}`, - // TODO - remove this when the dfx replica supports it - verifyQuerySignatures: false, ...options, }); try { diff --git a/packages/agent/src/actor.ts b/packages/agent/src/actor.ts index a7fd26823..428343391 100644 --- a/packages/agent/src/actor.ts +++ b/packages/agent/src/actor.ts @@ -278,6 +278,8 @@ export class Actor { compute_allocation: settings.compute_allocation ? [settings.compute_allocation] : [], freezing_threshold: settings.freezing_threshold ? [settings.freezing_threshold] : [], memory_allocation: settings.memory_allocation ? [settings.memory_allocation] : [], + reserved_cycles_limit: [], + log_visibility: [], }, ]; } @@ -429,7 +431,11 @@ function _createActorMethod( const cid = Principal.from(options.canisterId || actor[metadataSymbol].config.canisterId); const arg = IDL.encode(func.argTypes, args); - const result = await agent.query(cid, { methodName, arg }); + const result = await agent.query(cid, { + methodName, + arg, + effectiveCanisterId: options.effectiveCanisterId, + }); switch (result.status) { case QueryResponseStatus.Rejected: @@ -517,6 +523,9 @@ export function getManagementCanister(config: CallConfig): ActorSubclass & { canister_id: string }[], ) { + if (config.effectiveCanisterId) { + return { effectiveCanisterId: Principal.from(config.effectiveCanisterId) }; + } const first = args[0]; let effectiveCanisterId = Principal.fromHex(''); if (first && typeof first === 'object' && first.canister_id) { diff --git a/packages/agent/src/agent/api.ts b/packages/agent/src/agent/api.ts index 7fdbba41e..ab46c29ac 100644 --- a/packages/agent/src/agent/api.ts +++ b/packages/agent/src/agent/api.ts @@ -88,6 +88,11 @@ export interface QueryFields { * A binary encoded argument. This is already encoded and will be sent as is. */ arg: ArrayBuffer; + + /** + * Overrides canister id for path to fetch. This is used for management canister calls. + */ + effectiveCanisterId?: Principal; } /** diff --git a/packages/agent/src/agent/http/index.ts b/packages/agent/src/agent/http/index.ts index e8ca5a1d0..f4bb30acd 100644 --- a/packages/agent/src/agent/http/index.ts +++ b/packages/agent/src/agent/http/index.ts @@ -52,12 +52,14 @@ export enum RequestStatusResponseStatus { const DEFAULT_INGRESS_EXPIRY_DELTA_IN_MSECS = 5 * 60 * 1000; // Root public key for the IC, encoded as hex -const IC_ROOT_KEY = +export const IC_ROOT_KEY = '308182301d060d2b0601040182dc7c0503010201060c2b0601040182dc7c05030201036100814' + 'c0e6ec71fab583b08bd81373c255c3c371b2e84863c98a4f1e08b74235d14fb5d9c0cd546d968' + '5f913a0c0b2cc5341583bf4b4392e467db96d65b9bb4cb717112f8472e0d5a4d14505ffd7484' + 'b01291091c5f87b98883463f98091a0baaae'; +export const MANAGEMENT_CANISTER_ID = 'aaaaa-aa'; + // IC0 domain info const IC0_DOMAIN = 'ic0.app'; const IC0_SUB_DOMAIN = '.ic0.app'; @@ -396,6 +398,8 @@ export class HttpAgent implements Agent { const body = cbor.encode(transformedRequest.body); + this.log(`fetching "/api/v2/canister/${ecid.toText()}/call" with request:`, transformedRequest); + // Run both in parallel. The fetch is quite expensive, so we have plenty of time to // calculate the requestId locally. const request = this._requestAndRetry(() => @@ -427,36 +431,50 @@ export class HttpAgent implements Agent { async #requestAndRetryQuery( args: { - canister: string; + ecid: Principal; transformedRequest: HttpAgentRequest; body: ArrayBuffer; requestId: RequestId; }, tries = 0, ): Promise { - const { canister, transformedRequest, body, requestId } = args; + const { ecid, transformedRequest, body, requestId } = args; let response: ApiQueryResponse; // Make the request and retry if it throws an error try { const fetchResponse = await this._fetch( - '' + new URL(`/api/v2/canister/${canister}/query`, this._host), + '' + new URL(`/api/v2/canister/${ecid.toString()}/query`, this._host), { ...this._fetchOptions, ...transformedRequest.request, body, }, ); - const queryResponse: QueryResponse = cbor.decode(await fetchResponse.arrayBuffer()); - response = { - ...queryResponse, - httpDetails: { - ok: fetchResponse.ok, - status: fetchResponse.status, - statusText: fetchResponse.statusText, - headers: httpHeadersTransform(fetchResponse.headers), - }, - requestId, - }; + if (fetchResponse.status === 200) { + const queryResponse: QueryResponse = cbor.decode(await fetchResponse.arrayBuffer()); + response = { + ...queryResponse, + httpDetails: { + ok: fetchResponse.ok, + status: fetchResponse.status, + statusText: fetchResponse.statusText, + headers: httpHeadersTransform(fetchResponse.headers), + }, + requestId, + }; + } else { + throw new AgentHTTPResponseError( + `Server returned an error:\n` + + ` Code: ${fetchResponse.status} (${fetchResponse.statusText})\n` + + ` Body: ${await fetchResponse.text()}\n`, + { + ok: fetchResponse.ok, + status: fetchResponse.status, + statusText: fetchResponse.statusText, + headers: httpHeadersTransform(fetchResponse.headers), + }, + ); + } } catch (error) { if (tries < this._retryTimes) { this.log.warn( @@ -553,7 +571,12 @@ export class HttpAgent implements Agent { fields: QueryFields, identity?: Identity | Promise, ): Promise { - this.log(`making query to canister ${canisterId} with fields:`, fields); + const ecid = fields.effectiveCanisterId + ? Principal.from(fields.effectiveCanisterId) + : Principal.from(canisterId); + + this.log(`ecid ${ecid.toString()}`); + this.log(`canisterId ${canisterId.toString()}`); const makeQuery = async () => { const id = await (identity !== undefined ? await identity : await this._identity); if (!id) { @@ -597,6 +620,7 @@ export class HttpAgent implements Agent { const args = { canister: canister.toText(), + ecid, transformedRequest, body, requestId, @@ -609,12 +633,12 @@ export class HttpAgent implements Agent { if (!this.#verifyQuerySignatures) { return undefined; } - const subnetStatus = this.#subnetKeys.get(canisterId.toString()); + const subnetStatus = this.#subnetKeys.get(ecid.toString()); if (subnetStatus) { return subnetStatus; } - await this.fetchSubnetKeys(canisterId.toString()); - return this.#subnetKeys.get(canisterId.toString()); + await this.fetchSubnetKeys(ecid.toString()); + return this.#subnetKeys.get(ecid.toString()); }; // Attempt to make the query i=retryTimes times // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -633,7 +657,7 @@ export class HttpAgent implements Agent { // In case the node signatures have changed, refresh the subnet keys and try again this.log.warn('Query response verification failed. Retrying with fresh subnet keys.'); this.#subnetKeys.delete(canisterId.toString()); - await this.fetchSubnetKeys(canisterId.toString()); + await this.fetchSubnetKeys(ecid.toString()); const updatedSubnetStatus = this.#subnetKeys.get(canisterId.toString()); if (!updatedSubnetStatus) { @@ -767,6 +791,10 @@ export class HttpAgent implements Agent { const transformedRequest = request ?? (await this.createReadStateRequest(fields, identity)); const body = cbor.encode(transformedRequest.body); + this.log( + `fetching "/api/v2/canister/${canister}/read_state" with request:`, + transformedRequest, + ); // TODO - https://dfinity.atlassian.net/browse/SDK-1092 const response = await this._requestAndRetry(() => this._fetch('' + new URL(`/api/v2/canister/${canister}/read_state`, this._host), { @@ -858,6 +886,7 @@ export class HttpAgent implements Agent { } : {}; + this.log(`fetching "/api/v2/status"`); const response = await this._requestAndRetry(() => this._fetch('' + new URL(`/api/v2/status`, this._host), { headers, ...this._fetchOptions }), ); diff --git a/packages/agent/src/canisters/management.did b/packages/agent/src/canisters/management.did new file mode 100644 index 000000000..33db98ba6 --- /dev/null +++ b/packages/agent/src/canisters/management.did @@ -0,0 +1,388 @@ +// https://github.com/dfinity/interface-spec/blob/master/spec/_attachments/ic.did +type canister_id = principal; +type wasm_module = blob; + +type log_visibility = variant { + controllers; + public; +}; + +type canister_settings = record { + controllers : opt vec principal; + compute_allocation : opt nat; + memory_allocation : opt nat; + freezing_threshold : opt nat; + reserved_cycles_limit : opt nat; + log_visibility : opt log_visibility; +}; + +type definite_canister_settings = record { + controllers : vec principal; + compute_allocation : nat; + memory_allocation : nat; + freezing_threshold : nat; + reserved_cycles_limit : nat; + log_visibility : log_visibility; +}; + +type change_origin = variant { + from_user : record { + user_id : principal; + }; + from_canister : record { + canister_id : principal; + canister_version : opt nat64; + }; +}; + +type change_details = variant { + creation : record { + controllers : vec principal; + }; + code_uninstall; + code_deployment : record { + mode : variant { install; reinstall; upgrade }; + module_hash : blob; + }; + controllers_change : record { + controllers : vec principal; + }; +}; + +type change = record { + timestamp_nanos : nat64; + canister_version : nat64; + origin : change_origin; + details : change_details; +}; + +type chunk_hash = blob; + +type http_header = record { + name : text; + value : text; +}; + +type http_request_result = record { + status : nat; + headers : vec http_header; + body : blob; +}; + +type ecdsa_curve = variant { + secp256k1; +}; + +type satoshi = nat64; + +type bitcoin_network = variant { + mainnet; + testnet; +}; + +type bitcoin_address = text; + +type block_hash = blob; + +type outpoint = record { + txid : blob; + vout : nat32; +}; + +type utxo = record { + outpoint : outpoint; + value : satoshi; + height : nat32; +}; + +type bitcoin_get_utxos_args = record { + address : bitcoin_address; + network : bitcoin_network; + filter : opt variant { + min_confirmations : nat32; + page : blob; + }; +}; + +type bitcoin_get_utxos_query_args = record { + address : bitcoin_address; + network : bitcoin_network; + filter : opt variant { + min_confirmations : nat32; + page : blob; + }; +}; + +type bitcoin_get_current_fee_percentiles_args = record { + network : bitcoin_network; +}; + +type bitcoin_get_utxos_result = record { + utxos : vec utxo; + tip_block_hash : block_hash; + tip_height : nat32; + next_page : opt blob; +}; + +type bitcoin_get_utxos_query_result = record { + utxos : vec utxo; + tip_block_hash : block_hash; + tip_height : nat32; + next_page : opt blob; +}; + +type bitcoin_get_balance_args = record { + address : bitcoin_address; + network : bitcoin_network; + min_confirmations : opt nat32; +}; + +type bitcoin_get_balance_query_args = record { + address : bitcoin_address; + network : bitcoin_network; + min_confirmations : opt nat32; +}; + +type bitcoin_send_transaction_args = record { + transaction : blob; + network : bitcoin_network; +}; + +type millisatoshi_per_byte = nat64; + +type node_metrics = record { + node_id : principal; + num_blocks_total : nat64; + num_block_failures_total : nat64; +}; + +type create_canister_args = record { + settings : opt canister_settings; + sender_canister_version : opt nat64; +}; + +type create_canister_result = record { + canister_id : canister_id; +}; + +type update_settings_args = record { + canister_id : principal; + settings : canister_settings; + sender_canister_version : opt nat64; +}; + +type upload_chunk_args = record { + canister_id : principal; + chunk : blob; +}; + +type clear_chunk_store_args = record { + canister_id : canister_id; +}; + +type stored_chunks_args = record { + canister_id : canister_id; +}; + +type install_code_args = record { + mode : variant { + install; + reinstall; + upgrade : opt record { + skip_pre_upgrade : opt bool; + }; + }; + canister_id : canister_id; + wasm_module : wasm_module; + arg : blob; + sender_canister_version : opt nat64; +}; + +type install_chunked_code_args = record { + mode : variant { + install; + reinstall; + upgrade : opt record { + skip_pre_upgrade : opt bool; + }; + }; + target_canister : canister_id; + storage_canister : opt canister_id; + chunk_hashes_list : vec chunk_hash; + wasm_module_hash : blob; + arg : blob; + sender_canister_version : opt nat64; +}; + +type uninstall_code_args = record { + canister_id : canister_id; + sender_canister_version : opt nat64; +}; + +type start_canister_args = record { + canister_id : canister_id; +}; + +type stop_canister_args = record { + canister_id : canister_id; +}; + +type canister_status_args = record { + canister_id : canister_id; +}; + +type canister_status_result = record { + status : variant { running; stopping; stopped }; + settings : definite_canister_settings; + module_hash : opt blob; + memory_size : nat; + cycles : nat; + reserved_cycles : nat; + idle_cycles_burned_per_day : nat; +}; + +type canister_info_args = record { + canister_id : canister_id; + num_requested_changes : opt nat64; +}; + +type canister_info_result = record { + total_num_changes : nat64; + recent_changes : vec change; + module_hash : opt blob; + controllers : vec principal; +}; + +type delete_canister_args = record { + canister_id : canister_id; +}; + +type deposit_cycles_args = record { + canister_id : canister_id; +}; + +type http_request_args = record { + url : text; + max_response_bytes : opt nat64; + method : variant { get; head; post }; + headers : vec http_header; + body : opt blob; + transform : opt record { + function : func(record { response : http_request_result; context : blob }) -> (http_request_result) query; + context : blob; + }; +}; + +type ecdsa_public_key_args = record { + canister_id : opt canister_id; + derivation_path : vec blob; + key_id : record { curve : ecdsa_curve; name : text }; +}; + +type ecdsa_public_key_result = record { + public_key : blob; + chain_code : blob; +}; + +type sign_with_ecdsa_args = record { + message_hash : blob; + derivation_path : vec blob; + key_id : record { curve : ecdsa_curve; name : text }; +}; + +type sign_with_ecdsa_result = record { + signature : blob; +}; + +type node_metrics_history_args = record { + subnet_id : principal; + start_at_timestamp_nanos : nat64; +}; + +type node_metrics_history_result = vec record { + timestamp_nanos : nat64; + node_metrics : vec node_metrics; +}; + +type provisional_create_canister_with_cycles_args = record { + amount : opt nat; + settings : opt canister_settings; + specified_id : opt canister_id; + sender_canister_version : opt nat64; +}; + +type provisional_create_canister_with_cycles_result = record { + canister_id : canister_id; +}; + +type provisional_top_up_canister_args = record { + canister_id : canister_id; + amount : nat; +}; + +type raw_rand_result = blob; + +type stored_chunks_result = vec chunk_hash; + +type upload_chunk_result = chunk_hash; + +type bitcoin_get_balance_result = satoshi; + +type bitcoin_get_balance_query_result = satoshi; + +type bitcoin_get_current_fee_percentiles_result = vec millisatoshi_per_byte; + +type fetch_canister_logs_args = record { + canister_id : canister_id; +}; + +type canister_log_record = record { + idx : nat64; + timestamp_nanos : nat64; + content : blob; +}; + +type fetch_canister_logs_result = record { + canister_log_records : vec canister_log_record; +}; + +service ic : { + create_canister : (create_canister_args) -> (create_canister_result); + update_settings : (update_settings_args) -> (); + upload_chunk : (upload_chunk_args) -> (upload_chunk_result); + clear_chunk_store : (clear_chunk_store_args) -> (); + stored_chunks : (stored_chunks_args) -> (stored_chunks_result); + install_code : (install_code_args) -> (); + install_chunked_code : (install_chunked_code_args) -> (); + uninstall_code : (uninstall_code_args) -> (); + start_canister : (start_canister_args) -> (); + stop_canister : (stop_canister_args) -> (); + canister_status : (canister_status_args) -> (canister_status_result); + canister_info : (canister_info_args) -> (canister_info_result); + delete_canister : (delete_canister_args) -> (); + deposit_cycles : (deposit_cycles_args) -> (); + raw_rand : () -> (raw_rand_result); + http_request : (http_request_args) -> (http_request_result); + + // Threshold ECDSA signature + ecdsa_public_key : (ecdsa_public_key_args) -> (ecdsa_public_key_result); + sign_with_ecdsa : (sign_with_ecdsa_args) -> (sign_with_ecdsa_result); + + // bitcoin interface + bitcoin_get_balance : (bitcoin_get_balance_args) -> (bitcoin_get_balance_result); + bitcoin_get_balance_query : (bitcoin_get_balance_query_args) -> (bitcoin_get_balance_query_result) query; + bitcoin_get_utxos : (bitcoin_get_utxos_args) -> (bitcoin_get_utxos_result); + bitcoin_get_utxos_query : (bitcoin_get_utxos_query_args) -> (bitcoin_get_utxos_query_result) query; + bitcoin_send_transaction : (bitcoin_send_transaction_args) -> (); + bitcoin_get_current_fee_percentiles : (bitcoin_get_current_fee_percentiles_args) -> (bitcoin_get_current_fee_percentiles_result); + + // metrics interface + node_metrics_history : (node_metrics_history_args) -> (node_metrics_history_result); + + // provisional interfaces for the pre-ledger world + provisional_create_canister_with_cycles : (provisional_create_canister_with_cycles_args) -> (provisional_create_canister_with_cycles_result); + provisional_top_up_canister : (provisional_top_up_canister_args) -> (); + + // canister logging + fetch_canister_logs : (fetch_canister_logs_args) -> (fetch_canister_logs_result) query; +}; diff --git a/packages/agent/src/canisters/management_idl.ts b/packages/agent/src/canisters/management_idl.ts index 8a2875e38..bad5b8ea3 100644 --- a/packages/agent/src/canisters/management_idl.ts +++ b/packages/agent/src/canisters/management_idl.ts @@ -11,17 +11,25 @@ export default ({ IDL }) => { testnet: IDL.Null, }); const bitcoin_address = IDL.Text; - const get_balance_request = IDL.Record({ + const bitcoin_get_balance_args = IDL.Record({ network: bitcoin_network, address: bitcoin_address, min_confirmations: IDL.Opt(IDL.Nat32), }); const satoshi = IDL.Nat64; - const get_current_fee_percentiles_request = IDL.Record({ + const bitcoin_get_balance_result = satoshi; + const bitcoin_get_balance_query_args = IDL.Record({ + network: bitcoin_network, + address: bitcoin_address, + min_confirmations: IDL.Opt(IDL.Nat32), + }); + const bitcoin_get_balance_query_result = satoshi; + const bitcoin_get_current_fee_percentiles_args = IDL.Record({ network: bitcoin_network, }); const millisatoshi_per_byte = IDL.Nat64; - const get_utxos_request = IDL.Record({ + const bitcoin_get_current_fee_percentiles_result = IDL.Vec(millisatoshi_per_byte); + const bitcoin_get_utxos_args = IDL.Record({ network: bitcoin_network, filter: IDL.Opt( IDL.Variant({ @@ -41,17 +49,37 @@ export default ({ IDL }) => { value: satoshi, outpoint: outpoint, }); - const get_utxos_response = IDL.Record({ + const bitcoin_get_utxos_result = IDL.Record({ + next_page: IDL.Opt(IDL.Vec(IDL.Nat8)), + tip_height: IDL.Nat32, + tip_block_hash: block_hash, + utxos: IDL.Vec(utxo), + }); + const bitcoin_get_utxos_query_args = IDL.Record({ + network: bitcoin_network, + filter: IDL.Opt( + IDL.Variant({ + page: IDL.Vec(IDL.Nat8), + min_confirmations: IDL.Nat32, + }), + ), + address: bitcoin_address, + }); + const bitcoin_get_utxos_query_result = IDL.Record({ next_page: IDL.Opt(IDL.Vec(IDL.Nat8)), tip_height: IDL.Nat32, tip_block_hash: block_hash, utxos: IDL.Vec(utxo), }); - const send_transaction_request = IDL.Record({ + const bitcoin_send_transaction_args = IDL.Record({ transaction: IDL.Vec(IDL.Nat8), network: bitcoin_network, }); const canister_id = IDL.Principal; + const canister_info_args = IDL.Record({ + canister_id: canister_id, + num_requested_changes: IDL.Opt(IDL.Nat64), + }); const change_origin = IDL.Variant({ from_user: IDL.Record({ user_id: IDL.Principal }), from_canister: IDL.Record({ @@ -80,254 +108,234 @@ export default ({ IDL }) => { origin: change_origin, details: change_details, }); + const canister_info_result = IDL.Record({ + controllers: IDL.Vec(IDL.Principal), + module_hash: IDL.Opt(IDL.Vec(IDL.Nat8)), + recent_changes: IDL.Vec(change), + total_num_changes: IDL.Nat64, + }); + const canister_status_args = IDL.Record({ canister_id: canister_id }); + const log_visibility = IDL.Variant({ + controllers: IDL.Null, + public: IDL.Null, + }); const definite_canister_settings = IDL.Record({ freezing_threshold: IDL.Nat, controllers: IDL.Vec(IDL.Principal), + reserved_cycles_limit: IDL.Nat, + log_visibility: log_visibility, memory_allocation: IDL.Nat, compute_allocation: IDL.Nat, }); + const canister_status_result = IDL.Record({ + status: IDL.Variant({ + stopped: IDL.Null, + stopping: IDL.Null, + running: IDL.Null, + }), + memory_size: IDL.Nat, + cycles: IDL.Nat, + settings: definite_canister_settings, + idle_cycles_burned_per_day: IDL.Nat, + module_hash: IDL.Opt(IDL.Vec(IDL.Nat8)), + reserved_cycles: IDL.Nat, + }); + const clear_chunk_store_args = IDL.Record({ canister_id: canister_id }); const canister_settings = IDL.Record({ freezing_threshold: IDL.Opt(IDL.Nat), controllers: IDL.Opt(IDL.Vec(IDL.Principal)), + reserved_cycles_limit: IDL.Opt(IDL.Nat), + log_visibility: IDL.Opt(log_visibility), memory_allocation: IDL.Opt(IDL.Nat), compute_allocation: IDL.Opt(IDL.Nat), }); + const create_canister_args = IDL.Record({ + settings: IDL.Opt(canister_settings), + sender_canister_version: IDL.Opt(IDL.Nat64), + }); + const create_canister_result = IDL.Record({ canister_id: canister_id }); + const delete_canister_args = IDL.Record({ canister_id: canister_id }); + const deposit_cycles_args = IDL.Record({ canister_id: canister_id }); const ecdsa_curve = IDL.Variant({ secp256k1: IDL.Null }); + const ecdsa_public_key_args = IDL.Record({ + key_id: IDL.Record({ name: IDL.Text, curve: ecdsa_curve }), + canister_id: IDL.Opt(canister_id), + derivation_path: IDL.Vec(IDL.Vec(IDL.Nat8)), + }); + const ecdsa_public_key_result = IDL.Record({ + public_key: IDL.Vec(IDL.Nat8), + chain_code: IDL.Vec(IDL.Nat8), + }); + const fetch_canister_logs_args = IDL.Record({ canister_id: canister_id }); + const canister_log_record = IDL.Record({ + idx: IDL.Nat64, + timestamp_nanos: IDL.Nat64, + content: IDL.Vec(IDL.Nat8), + }); + const fetch_canister_logs_result = IDL.Record({ + canister_log_records: IDL.Vec(canister_log_record), + }); const http_header = IDL.Record({ value: IDL.Text, name: IDL.Text }); - const http_response = IDL.Record({ + const http_request_result = IDL.Record({ status: IDL.Nat, body: IDL.Vec(IDL.Nat8), headers: IDL.Vec(http_header), }); + const http_request_args = IDL.Record({ + url: IDL.Text, + method: IDL.Variant({ + get: IDL.Null, + head: IDL.Null, + post: IDL.Null, + }), + max_response_bytes: IDL.Opt(IDL.Nat64), + body: IDL.Opt(IDL.Vec(IDL.Nat8)), + transform: IDL.Opt( + IDL.Record({ + function: IDL.Func( + [ + IDL.Record({ + context: IDL.Vec(IDL.Nat8), + response: http_request_result, + }), + ], + [http_request_result], + ['query'], + ), + context: IDL.Vec(IDL.Nat8), + }), + ), + headers: IDL.Vec(http_header), + }); const chunk_hash = IDL.Vec(IDL.Nat8); + const install_chunked_code_args = IDL.Record({ + arg: IDL.Vec(IDL.Nat8), + wasm_module_hash: IDL.Vec(IDL.Nat8), + mode: IDL.Variant({ + reinstall: IDL.Null, + upgrade: IDL.Opt(IDL.Record({ skip_pre_upgrade: IDL.Opt(IDL.Bool) })), + install: IDL.Null, + }), + chunk_hashes_list: IDL.Vec(chunk_hash), + target_canister: canister_id, + sender_canister_version: IDL.Opt(IDL.Nat64), + storage_canister: IDL.Opt(canister_id), + }); const wasm_module = IDL.Vec(IDL.Nat8); + const install_code_args = IDL.Record({ + arg: IDL.Vec(IDL.Nat8), + wasm_module: wasm_module, + mode: IDL.Variant({ + reinstall: IDL.Null, + upgrade: IDL.Opt(IDL.Record({ skip_pre_upgrade: IDL.Opt(IDL.Bool) })), + install: IDL.Null, + }), + canister_id: canister_id, + sender_canister_version: IDL.Opt(IDL.Nat64), + }); + const node_metrics_history_args = IDL.Record({ + start_at_timestamp_nanos: IDL.Nat64, + subnet_id: IDL.Principal, + }); const node_metrics = IDL.Record({ num_block_failures_total: IDL.Nat64, node_id: IDL.Principal, num_blocks_total: IDL.Nat64, }); + const node_metrics_history_result = IDL.Vec( + IDL.Record({ + timestamp_nanos: IDL.Nat64, + node_metrics: IDL.Vec(node_metrics), + }), + ); + const provisional_create_canister_with_cycles_args = IDL.Record({ + settings: IDL.Opt(canister_settings), + specified_id: IDL.Opt(canister_id), + amount: IDL.Opt(IDL.Nat), + sender_canister_version: IDL.Opt(IDL.Nat64), + }); + const provisional_create_canister_with_cycles_result = IDL.Record({ + canister_id: canister_id, + }); + const provisional_top_up_canister_args = IDL.Record({ + canister_id: canister_id, + amount: IDL.Nat, + }); + const raw_rand_result = IDL.Vec(IDL.Nat8); + const sign_with_ecdsa_args = IDL.Record({ + key_id: IDL.Record({ name: IDL.Text, curve: ecdsa_curve }), + derivation_path: IDL.Vec(IDL.Vec(IDL.Nat8)), + message_hash: IDL.Vec(IDL.Nat8), + }); + const sign_with_ecdsa_result = IDL.Record({ + signature: IDL.Vec(IDL.Nat8), + }); + const start_canister_args = IDL.Record({ canister_id: canister_id }); + const stop_canister_args = IDL.Record({ canister_id: canister_id }); + const stored_chunks_args = IDL.Record({ canister_id: canister_id }); + const stored_chunks_result = IDL.Vec(chunk_hash); + const uninstall_code_args = IDL.Record({ + canister_id: canister_id, + sender_canister_version: IDL.Opt(IDL.Nat64), + }); + const update_settings_args = IDL.Record({ + canister_id: IDL.Principal, + settings: canister_settings, + sender_canister_version: IDL.Opt(IDL.Nat64), + }); + const upload_chunk_args = IDL.Record({ + chunk: IDL.Vec(IDL.Nat8), + canister_id: IDL.Principal, + }); + const upload_chunk_result = chunk_hash; return IDL.Service({ - bitcoin_get_balance: IDL.Func([get_balance_request], [satoshi], []), - bitcoin_get_balance_query: IDL.Func([get_balance_request], [satoshi], ['query']), - bitcoin_get_current_fee_percentiles: IDL.Func( - [get_current_fee_percentiles_request], - [IDL.Vec(millisatoshi_per_byte)], - [], + bitcoin_get_balance: IDL.Func([bitcoin_get_balance_args], [bitcoin_get_balance_result], []), + bitcoin_get_balance_query: IDL.Func( + [bitcoin_get_balance_query_args], + [bitcoin_get_balance_query_result], + ['query'], ), - bitcoin_get_utxos: IDL.Func([get_utxos_request], [get_utxos_response], []), - bitcoin_get_utxos_query: IDL.Func([get_utxos_request], [get_utxos_response], ['query']), - bitcoin_send_transaction: IDL.Func([send_transaction_request], [], []), - canister_info: IDL.Func( - [ - IDL.Record({ - canister_id: canister_id, - num_requested_changes: IDL.Opt(IDL.Nat64), - }), - ], - [ - IDL.Record({ - controllers: IDL.Vec(IDL.Principal), - module_hash: IDL.Opt(IDL.Vec(IDL.Nat8)), - recent_changes: IDL.Vec(change), - total_num_changes: IDL.Nat64, - }), - ], - [], - ), - canister_status: IDL.Func( - [IDL.Record({ canister_id: canister_id })], - [ - IDL.Record({ - status: IDL.Variant({ - stopped: IDL.Null, - stopping: IDL.Null, - running: IDL.Null, - }), - memory_size: IDL.Nat, - cycles: IDL.Nat, - settings: definite_canister_settings, - idle_cycles_burned_per_day: IDL.Nat, - module_hash: IDL.Opt(IDL.Vec(IDL.Nat8)), - }), - ], - [], - ), - clear_chunk_store: IDL.Func([IDL.Record({ canister_id: canister_id })], [], []), - create_canister: IDL.Func( - [ - IDL.Record({ - settings: IDL.Opt(canister_settings), - sender_canister_version: IDL.Opt(IDL.Nat64), - }), - ], - [IDL.Record({ canister_id: canister_id })], - [], - ), - delete_canister: IDL.Func([IDL.Record({ canister_id: canister_id })], [], []), - deposit_cycles: IDL.Func([IDL.Record({ canister_id: canister_id })], [], []), - ecdsa_public_key: IDL.Func( - [ - IDL.Record({ - key_id: IDL.Record({ name: IDL.Text, curve: ecdsa_curve }), - canister_id: IDL.Opt(canister_id), - derivation_path: IDL.Vec(IDL.Vec(IDL.Nat8)), - }), - ], - [ - IDL.Record({ - public_key: IDL.Vec(IDL.Nat8), - chain_code: IDL.Vec(IDL.Nat8), - }), - ], - [], - ), - http_request: IDL.Func( - [ - IDL.Record({ - url: IDL.Text, - method: IDL.Variant({ - get: IDL.Null, - head: IDL.Null, - post: IDL.Null, - }), - max_response_bytes: IDL.Opt(IDL.Nat64), - body: IDL.Opt(IDL.Vec(IDL.Nat8)), - transform: IDL.Opt( - IDL.Record({ - function: IDL.Func( - [ - IDL.Record({ - context: IDL.Vec(IDL.Nat8), - response: http_response, - }), - ], - [http_response], - ['query'], - ), - context: IDL.Vec(IDL.Nat8), - }), - ), - headers: IDL.Vec(http_header), - }), - ], - [http_response], + bitcoin_get_current_fee_percentiles: IDL.Func( + [bitcoin_get_current_fee_percentiles_args], + [bitcoin_get_current_fee_percentiles_result], [], ), - install_chunked_code: IDL.Func( - [ - IDL.Record({ - arg: IDL.Vec(IDL.Nat8), - wasm_module_hash: IDL.Vec(IDL.Nat8), - mode: IDL.Variant({ - reinstall: IDL.Null, - upgrade: IDL.Opt(IDL.Record({ skip_pre_upgrade: IDL.Opt(IDL.Bool) })), - install: IDL.Null, - }), - chunk_hashes_list: IDL.Vec(chunk_hash), - target_canister: canister_id, - sender_canister_version: IDL.Opt(IDL.Nat64), - storage_canister: IDL.Opt(canister_id), - }), - ], - [], - [], + bitcoin_get_utxos: IDL.Func([bitcoin_get_utxos_args], [bitcoin_get_utxos_result], []), + bitcoin_get_utxos_query: IDL.Func( + [bitcoin_get_utxos_query_args], + [bitcoin_get_utxos_query_result], + ['query'], ), - install_code: IDL.Func( - [ - IDL.Record({ - arg: IDL.Vec(IDL.Nat8), - wasm_module: wasm_module, - mode: IDL.Variant({ - reinstall: IDL.Null, - upgrade: IDL.Opt(IDL.Record({ skip_pre_upgrade: IDL.Opt(IDL.Bool) })), - install: IDL.Null, - }), - canister_id: canister_id, - sender_canister_version: IDL.Opt(IDL.Nat64), - }), - ], - [], - [], - ), - node_metrics_history: IDL.Func( - [ - IDL.Record({ - start_at_timestamp_nanos: IDL.Nat64, - subnet_id: IDL.Principal, - }), - ], - [ - IDL.Vec( - IDL.Record({ - timestamp_nanos: IDL.Nat64, - node_metrics: IDL.Vec(node_metrics), - }), - ), - ], - [], + bitcoin_send_transaction: IDL.Func([bitcoin_send_transaction_args], [], []), + canister_info: IDL.Func([canister_info_args], [canister_info_result], []), + canister_status: IDL.Func([canister_status_args], [canister_status_result], []), + clear_chunk_store: IDL.Func([clear_chunk_store_args], [], []), + create_canister: IDL.Func([create_canister_args], [create_canister_result], []), + delete_canister: IDL.Func([delete_canister_args], [], []), + deposit_cycles: IDL.Func([deposit_cycles_args], [], []), + ecdsa_public_key: IDL.Func([ecdsa_public_key_args], [ecdsa_public_key_result], []), + fetch_canister_logs: IDL.Func( + [fetch_canister_logs_args], + [fetch_canister_logs_result], + ['query'], ), + http_request: IDL.Func([http_request_args], [http_request_result], []), + install_chunked_code: IDL.Func([install_chunked_code_args], [], []), + install_code: IDL.Func([install_code_args], [], []), + node_metrics_history: IDL.Func([node_metrics_history_args], [node_metrics_history_result], []), provisional_create_canister_with_cycles: IDL.Func( - [ - IDL.Record({ - settings: IDL.Opt(canister_settings), - specified_id: IDL.Opt(canister_id), - amount: IDL.Opt(IDL.Nat), - sender_canister_version: IDL.Opt(IDL.Nat64), - }), - ], - [IDL.Record({ canister_id: canister_id })], - [], - ), - provisional_top_up_canister: IDL.Func( - [IDL.Record({ canister_id: canister_id, amount: IDL.Nat })], - [], - [], - ), - raw_rand: IDL.Func([], [IDL.Vec(IDL.Nat8)], []), - sign_with_ecdsa: IDL.Func( - [ - IDL.Record({ - key_id: IDL.Record({ name: IDL.Text, curve: ecdsa_curve }), - derivation_path: IDL.Vec(IDL.Vec(IDL.Nat8)), - message_hash: IDL.Vec(IDL.Nat8), - }), - ], - [IDL.Record({ signature: IDL.Vec(IDL.Nat8) })], - [], - ), - start_canister: IDL.Func([IDL.Record({ canister_id: canister_id })], [], []), - stop_canister: IDL.Func([IDL.Record({ canister_id: canister_id })], [], []), - stored_chunks: IDL.Func([IDL.Record({ canister_id: canister_id })], [IDL.Vec(chunk_hash)], []), - uninstall_code: IDL.Func( - [ - IDL.Record({ - canister_id: canister_id, - sender_canister_version: IDL.Opt(IDL.Nat64), - }), - ], - [], - [], - ), - update_settings: IDL.Func( - [ - IDL.Record({ - canister_id: IDL.Principal, - settings: canister_settings, - sender_canister_version: IDL.Opt(IDL.Nat64), - }), - ], - [], - [], - ), - upload_chunk: IDL.Func( - [ - IDL.Record({ - chunk: IDL.Vec(IDL.Nat8), - canister_id: IDL.Principal, - }), - ], - [chunk_hash], + [provisional_create_canister_with_cycles_args], + [provisional_create_canister_with_cycles_result], [], ), + provisional_top_up_canister: IDL.Func([provisional_top_up_canister_args], [], []), + raw_rand: IDL.Func([], [raw_rand_result], []), + sign_with_ecdsa: IDL.Func([sign_with_ecdsa_args], [sign_with_ecdsa_result], []), + start_canister: IDL.Func([start_canister_args], [], []), + stop_canister: IDL.Func([stop_canister_args], [], []), + stored_chunks: IDL.Func([stored_chunks_args], [stored_chunks_result], []), + uninstall_code: IDL.Func([uninstall_code_args], [], []), + update_settings: IDL.Func([update_settings_args], [], []), + upload_chunk: IDL.Func([upload_chunk_args], [upload_chunk_result], []), }); }; diff --git a/packages/agent/src/canisters/management_service.ts b/packages/agent/src/canisters/management_service.ts index 8efe3b63e..8cedd28d3 100644 --- a/packages/agent/src/canisters/management_service.ts +++ b/packages/agent/src/canisters/management_service.ts @@ -10,15 +10,86 @@ import type { ActorMethod } from '@dfinity/agent'; import type { IDL } from '@dfinity/candid'; export type bitcoin_address = string; +export interface bitcoin_get_balance_args { + network: bitcoin_network; + address: bitcoin_address; + min_confirmations: [] | [number]; +} +export interface bitcoin_get_balance_query_args { + network: bitcoin_network; + address: bitcoin_address; + min_confirmations: [] | [number]; +} +export type bitcoin_get_balance_query_result = satoshi; +export type bitcoin_get_balance_result = satoshi; +export interface bitcoin_get_current_fee_percentiles_args { + network: bitcoin_network; +} +export type bitcoin_get_current_fee_percentiles_result = BigUint64Array | bigint[]; +export interface bitcoin_get_utxos_args { + network: bitcoin_network; + filter: [] | [{ page: Uint8Array | number[] } | { min_confirmations: number }]; + address: bitcoin_address; +} +export interface bitcoin_get_utxos_query_args { + network: bitcoin_network; + filter: [] | [{ page: Uint8Array | number[] } | { min_confirmations: number }]; + address: bitcoin_address; +} +export interface bitcoin_get_utxos_query_result { + next_page: [] | [Uint8Array | number[]]; + tip_height: number; + tip_block_hash: block_hash; + utxos: Array; +} +export interface bitcoin_get_utxos_result { + next_page: [] | [Uint8Array | number[]]; + tip_height: number; + tip_block_hash: block_hash; + utxos: Array; +} export type bitcoin_network = { mainnet: null } | { testnet: null }; +export interface bitcoin_send_transaction_args { + transaction: Uint8Array | number[]; + network: bitcoin_network; +} export type block_hash = Uint8Array | number[]; export type canister_id = Principal; +export interface canister_info_args { + canister_id: canister_id; + num_requested_changes: [] | [bigint]; +} +export interface canister_info_result { + controllers: Array; + module_hash: [] | [Uint8Array | number[]]; + recent_changes: Array; + total_num_changes: bigint; +} +export interface canister_log_record { + idx: bigint; + timestamp_nanos: bigint; + content: Uint8Array | number[]; +} export interface canister_settings { freezing_threshold: [] | [bigint]; controllers: [] | [Array]; + reserved_cycles_limit: [] | [bigint]; + log_visibility: [] | [log_visibility]; memory_allocation: [] | [bigint]; compute_allocation: [] | [bigint]; } +export interface canister_status_args { + canister_id: canister_id; +} +export interface canister_status_result { + status: { stopped: null } | { stopping: null } | { running: null }; + memory_size: bigint; + cycles: bigint; + settings: definite_canister_settings; + idle_cycles_burned_per_day: bigint; + module_hash: [] | [Uint8Array | number[]]; + reserved_cycles: bigint; +} export interface change { timestamp_nanos: bigint; canister_version: bigint; @@ -46,56 +117,151 @@ export type change_origin = }; }; export type chunk_hash = Uint8Array | number[]; +export interface clear_chunk_store_args { + canister_id: canister_id; +} +export interface create_canister_args { + settings: [] | [canister_settings]; + sender_canister_version: [] | [bigint]; +} +export interface create_canister_result { + canister_id: canister_id; +} export interface definite_canister_settings { freezing_threshold: bigint; controllers: Array; + reserved_cycles_limit: bigint; + log_visibility: log_visibility; memory_allocation: bigint; compute_allocation: bigint; } +export interface delete_canister_args { + canister_id: canister_id; +} +export interface deposit_cycles_args { + canister_id: canister_id; +} export type ecdsa_curve = { secp256k1: null }; -export interface get_balance_request { - network: bitcoin_network; - address: bitcoin_address; - min_confirmations: [] | [number]; +export interface ecdsa_public_key_args { + key_id: { name: string; curve: ecdsa_curve }; + canister_id: [] | [canister_id]; + derivation_path: Array; } -export interface get_current_fee_percentiles_request { - network: bitcoin_network; +export interface ecdsa_public_key_result { + public_key: Uint8Array | number[]; + chain_code: Uint8Array | number[]; } -export interface get_utxos_request { - network: bitcoin_network; - filter: [] | [{ page: Uint8Array | number[] } | { min_confirmations: number }]; - address: bitcoin_address; +export interface fetch_canister_logs_args { + canister_id: canister_id; } -export interface get_utxos_response { - next_page: [] | [Uint8Array | number[]]; - tip_height: number; - tip_block_hash: block_hash; - utxos: Array; +export interface fetch_canister_logs_result { + canister_log_records: Array; } export interface http_header { value: string; name: string; } -export interface http_response { +export interface http_request_args { + url: string; + method: { get: null } | { head: null } | { post: null }; + max_response_bytes: [] | [bigint]; + body: [] | [Uint8Array | number[]]; + transform: [] | [{ function: [Principal, string]; context: Uint8Array | number[] }]; + headers: Array; +} +export interface http_request_result { status: bigint; body: Uint8Array | number[]; headers: Array; } +export interface install_chunked_code_args { + arg: Uint8Array | number[]; + wasm_module_hash: Uint8Array | number[]; + mode: + | { reinstall: null } + | { upgrade: [] | [{ skip_pre_upgrade: [] | [boolean] }] } + | { install: null }; + chunk_hashes_list: Array; + target_canister: canister_id; + sender_canister_version: [] | [bigint]; + storage_canister: [] | [canister_id]; +} +export interface install_code_args { + arg: Uint8Array | number[]; + wasm_module: wasm_module; + mode: + | { reinstall: null } + | { upgrade: [] | [{ skip_pre_upgrade: [] | [boolean] }] } + | { install: null }; + canister_id: canister_id; + sender_canister_version: [] | [bigint]; +} +export type log_visibility = { controllers: null } | { public: null }; export type millisatoshi_per_byte = bigint; export interface node_metrics { num_block_failures_total: bigint; node_id: Principal; num_blocks_total: bigint; } +export interface node_metrics_history_args { + start_at_timestamp_nanos: bigint; + subnet_id: Principal; +} +export type node_metrics_history_result = Array<{ + timestamp_nanos: bigint; + node_metrics: Array; +}>; export interface outpoint { txid: Uint8Array | number[]; vout: number; } +export interface provisional_create_canister_with_cycles_args { + settings: [] | [canister_settings]; + specified_id: [] | [canister_id]; + amount: [] | [bigint]; + sender_canister_version: [] | [bigint]; +} +export interface provisional_create_canister_with_cycles_result { + canister_id: canister_id; +} +export interface provisional_top_up_canister_args { + canister_id: canister_id; + amount: bigint; +} +export type raw_rand_result = Uint8Array | number[]; export type satoshi = bigint; -export interface send_transaction_request { - transaction: Uint8Array | number[]; - network: bitcoin_network; +export interface sign_with_ecdsa_args { + key_id: { name: string; curve: ecdsa_curve }; + derivation_path: Array; + message_hash: Uint8Array | number[]; +} +export interface sign_with_ecdsa_result { + signature: Uint8Array | number[]; } +export interface start_canister_args { + canister_id: canister_id; +} +export interface stop_canister_args { + canister_id: canister_id; +} +export interface stored_chunks_args { + canister_id: canister_id; +} +export type stored_chunks_result = Array; +export interface uninstall_code_args { + canister_id: canister_id; + sender_canister_version: [] | [bigint]; +} +export interface update_settings_args { + canister_id: Principal; + settings: canister_settings; + sender_canister_version: [] | [bigint]; +} +export interface upload_chunk_args { + chunk: Uint8Array | number[]; + canister_id: Principal; +} +export type upload_chunk_result = chunk_hash; export interface utxo { height: number; value: satoshi; @@ -103,164 +269,46 @@ export interface utxo { } export type wasm_module = Uint8Array | number[]; export default interface _SERVICE { - bitcoin_get_balance: ActorMethod<[get_balance_request], satoshi>; - bitcoin_get_balance_query: ActorMethod<[get_balance_request], satoshi>; - bitcoin_get_current_fee_percentiles: ActorMethod< - [get_current_fee_percentiles_request], - BigUint64Array | bigint[] - >; - bitcoin_get_utxos: ActorMethod<[get_utxos_request], get_utxos_response>; - bitcoin_get_utxos_query: ActorMethod<[get_utxos_request], get_utxos_response>; - bitcoin_send_transaction: ActorMethod<[send_transaction_request], undefined>; - canister_info: ActorMethod< - [{ canister_id: canister_id; num_requested_changes: [] | [bigint] }], - { - controllers: Array; - module_hash: [] | [Uint8Array | number[]]; - recent_changes: Array; - total_num_changes: bigint; - } - >; - canister_status: ActorMethod< - [{ canister_id: canister_id }], - { - status: { stopped: null } | { stopping: null } | { running: null }; - memory_size: bigint; - cycles: bigint; - settings: definite_canister_settings; - idle_cycles_burned_per_day: bigint; - module_hash: [] | [Uint8Array | number[]]; - } + bitcoin_get_balance: ActorMethod<[bitcoin_get_balance_args], bitcoin_get_balance_result>; + bitcoin_get_balance_query: ActorMethod< + [bitcoin_get_balance_query_args], + bitcoin_get_balance_query_result >; - clear_chunk_store: ActorMethod<[{ canister_id: canister_id }], undefined>; - create_canister: ActorMethod< - [ - { - settings: [] | [canister_settings]; - sender_canister_version: [] | [bigint]; - }, - ], - { canister_id: canister_id } - >; - delete_canister: ActorMethod<[{ canister_id: canister_id }], undefined>; - deposit_cycles: ActorMethod<[{ canister_id: canister_id }], undefined>; - ecdsa_public_key: ActorMethod< - [ - { - key_id: { name: string; curve: ecdsa_curve }; - canister_id: [] | [canister_id]; - derivation_path: Array; - }, - ], - { - public_key: Uint8Array | number[]; - chain_code: Uint8Array | number[]; - } - >; - http_request: ActorMethod< - [ - { - url: string; - method: { get: null } | { head: null } | { post: null }; - max_response_bytes: [] | [bigint]; - body: [] | [Uint8Array | number[]]; - transform: - | [] - | [ - { - function: [Principal, string]; - context: Uint8Array | number[]; - }, - ]; - headers: Array; - }, - ], - http_response - >; - install_chunked_code: ActorMethod< - [ - { - arg: Uint8Array | number[]; - wasm_module_hash: Uint8Array | number[]; - mode: - | { reinstall: null } - | { upgrade: [] | [{ skip_pre_upgrade: [] | [boolean] }] } - | { install: null }; - chunk_hashes_list: Array; - target_canister: canister_id; - sender_canister_version: [] | [bigint]; - storage_canister: [] | [canister_id]; - }, - ], - undefined - >; - install_code: ActorMethod< - [ - { - arg: Uint8Array | number[]; - wasm_module: wasm_module; - mode: - | { reinstall: null } - | { upgrade: [] | [{ skip_pre_upgrade: [] | [boolean] }] } - | { install: null }; - canister_id: canister_id; - sender_canister_version: [] | [bigint]; - }, - ], - undefined + bitcoin_get_current_fee_percentiles: ActorMethod< + [bitcoin_get_current_fee_percentiles_args], + bitcoin_get_current_fee_percentiles_result >; - node_metrics_history: ActorMethod< - [{ start_at_timestamp_nanos: bigint; subnet_id: Principal }], - Array<{ timestamp_nanos: bigint; node_metrics: Array }> + bitcoin_get_utxos: ActorMethod<[bitcoin_get_utxos_args], bitcoin_get_utxos_result>; + bitcoin_get_utxos_query: ActorMethod< + [bitcoin_get_utxos_query_args], + bitcoin_get_utxos_query_result >; + bitcoin_send_transaction: ActorMethod<[bitcoin_send_transaction_args], undefined>; + canister_info: ActorMethod<[canister_info_args], canister_info_result>; + canister_status: ActorMethod<[canister_status_args], canister_status_result>; + clear_chunk_store: ActorMethod<[clear_chunk_store_args], undefined>; + create_canister: ActorMethod<[create_canister_args], create_canister_result>; + delete_canister: ActorMethod<[delete_canister_args], undefined>; + deposit_cycles: ActorMethod<[deposit_cycles_args], undefined>; + ecdsa_public_key: ActorMethod<[ecdsa_public_key_args], ecdsa_public_key_result>; + fetch_canister_logs: ActorMethod<[fetch_canister_logs_args], fetch_canister_logs_result>; + http_request: ActorMethod<[http_request_args], http_request_result>; + install_chunked_code: ActorMethod<[install_chunked_code_args], undefined>; + install_code: ActorMethod<[install_code_args], undefined>; + node_metrics_history: ActorMethod<[node_metrics_history_args], node_metrics_history_result>; provisional_create_canister_with_cycles: ActorMethod< - [ - { - settings: [] | [canister_settings]; - specified_id: [] | [canister_id]; - amount: [] | [bigint]; - sender_canister_version: [] | [bigint]; - }, - ], - { canister_id: canister_id } - >; - provisional_top_up_canister: ActorMethod< - [{ canister_id: canister_id; amount: bigint }], - undefined - >; - raw_rand: ActorMethod<[], Uint8Array | number[]>; - sign_with_ecdsa: ActorMethod< - [ - { - key_id: { name: string; curve: ecdsa_curve }; - derivation_path: Array; - message_hash: Uint8Array | number[]; - }, - ], - { signature: Uint8Array | number[] } - >; - start_canister: ActorMethod<[{ canister_id: canister_id }], undefined>; - stop_canister: ActorMethod<[{ canister_id: canister_id }], undefined>; - stored_chunks: ActorMethod<[{ canister_id: canister_id }], Array>; - uninstall_code: ActorMethod< - [ - { - canister_id: canister_id; - sender_canister_version: [] | [bigint]; - }, - ], - undefined - >; - update_settings: ActorMethod< - [ - { - canister_id: Principal; - settings: canister_settings; - sender_canister_version: [] | [bigint]; - }, - ], - undefined + [provisional_create_canister_with_cycles_args], + provisional_create_canister_with_cycles_result >; - upload_chunk: ActorMethod<[{ chunk: Uint8Array | number[]; canister_id: Principal }], chunk_hash>; + provisional_top_up_canister: ActorMethod<[provisional_top_up_canister_args], undefined>; + raw_rand: ActorMethod<[], raw_rand_result>; + sign_with_ecdsa: ActorMethod<[sign_with_ecdsa_args], sign_with_ecdsa_result>; + start_canister: ActorMethod<[start_canister_args], undefined>; + stop_canister: ActorMethod<[stop_canister_args], undefined>; + stored_chunks: ActorMethod<[stored_chunks_args], stored_chunks_result>; + uninstall_code: ActorMethod<[uninstall_code_args], undefined>; + update_settings: ActorMethod<[update_settings_args], undefined>; + upload_chunk: ActorMethod<[upload_chunk_args], upload_chunk_result>; } export declare const idlFactory: IDL.InterfaceFactory; +export declare const init: (args: { IDL: typeof IDL }) => IDL.Type[]; diff --git a/packages/agent/src/utils/buffer.ts b/packages/agent/src/utils/buffer.ts index e858b1c31..7dc08bdf6 100644 --- a/packages/agent/src/utils/buffer.ts +++ b/packages/agent/src/utils/buffer.ts @@ -93,6 +93,7 @@ export function bufFromBufLike( | ArrayBufferView | ArrayBufferLike | [number] + | number[] | { buffer: ArrayBuffer }, ): ArrayBuffer { if (bufLike instanceof Uint8Array) { diff --git a/packages/candid/src/utils/buffer.ts b/packages/candid/src/utils/buffer.ts index 5335ea947..34688b1f3 100644 --- a/packages/candid/src/utils/buffer.ts +++ b/packages/candid/src/utils/buffer.ts @@ -137,7 +137,15 @@ export function uint8ToBuf(arr: Uint8Array): ArrayBuffer { * @returns ArrayBuffer */ export function bufFromBufLike( - bufLike: ArrayBuffer | Uint8Array | DataView | ArrayBufferView | ArrayBufferLike, + bufLike: + | ArrayBuffer + | Uint8Array + | DataView + | ArrayBufferView + | ArrayBufferLike + | [number] + | number[] + | { buffer: ArrayBuffer }, ): ArrayBuffer { if (bufLike instanceof Uint8Array) { return uint8ToBuf(bufLike); @@ -145,8 +153,11 @@ export function bufFromBufLike( if (bufLike instanceof ArrayBuffer) { return bufLike; } + if (Array.isArray(bufLike)) { + return uint8ToBuf(new Uint8Array(bufLike)); + } if ('buffer' in bufLike) { - return bufLike.buffer; + return bufFromBufLike(bufLike.buffer); } - return new Uint8Array(bufLike); + return uint8ToBuf(new Uint8Array(bufLike)); }