diff --git a/CHANGELOG.md b/CHANGELOG.md index 6507800dc..89f78b86d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,11 @@ ## Features - Add support for `get_default_subnets` to `@dfinity/cmc`. +- Add class `AgentManager` in `@dfinity/utils` which caches `HttpAgent` instances for different identities. + +## Docs + +- Rename DFINITY LLC to DFINITY Stiftung in licences. # 2024.10.09-1140Z diff --git a/LICENSE b/LICENSE index 4874b73b8..7b214fe22 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2021 DFINITY LLC. + Copyright 2021 DFINITY Stiftung. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packages/ckbtc/LICENSE b/packages/ckbtc/LICENSE index 4874b73b8..7b214fe22 100644 --- a/packages/ckbtc/LICENSE +++ b/packages/ckbtc/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2021 DFINITY LLC. + Copyright 2021 DFINITY Stiftung. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packages/ckbtc/candid/minter.did b/packages/ckbtc/candid/minter.did index 0726a6266..72d1832a3 100644 --- a/packages/ckbtc/candid/minter.did +++ b/packages/ckbtc/candid/minter.did @@ -1,4 +1,4 @@ -// Generated from IC repo commit 3c76b91 (2024-10-17 tags: release-2024-10-17_03-07-scheduler-changes-guestos-revert) 'rs/bitcoin/ckbtc/minter/ckbtc_minter.did' by import-candid +// Generated from IC repo commit a6ef593 (2024-10-24 tags: release-2024-10-23_03-07-ubuntu20.04) 'rs/bitcoin/ckbtc/minter/ckbtc_minter.did' by import-candid // Represents an account on the ckBTC ledger. type Account = record { owner : principal; subaccount : opt blob }; diff --git a/packages/cketh/LICENSE b/packages/cketh/LICENSE index 4874b73b8..7b214fe22 100644 --- a/packages/cketh/LICENSE +++ b/packages/cketh/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2021 DFINITY LLC. + Copyright 2021 DFINITY Stiftung. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packages/cketh/candid/minter.certified.idl.js b/packages/cketh/candid/minter.certified.idl.js index 15134ac25..d97e92224 100644 --- a/packages/cketh/candid/minter.certified.idl.js +++ b/packages/cketh/candid/minter.certified.idl.js @@ -241,6 +241,7 @@ export const idlFactory = ({ IDL }) => { 'eth_balance' : IDL.Opt(IDL.Nat), 'eth_helper_contract_address' : IDL.Opt(IDL.Text), 'last_observed_block_number' : IDL.Opt(IDL.Nat), + 'evm_rpc_id' : IDL.Opt(IDL.Principal), 'erc20_helper_contract_address' : IDL.Opt(IDL.Text), 'last_erc20_scraped_block_number' : IDL.Opt(IDL.Nat), 'supported_ckerc20_tokens' : IDL.Opt(IDL.Vec(CkErc20Token)), diff --git a/packages/cketh/candid/minter.d.ts b/packages/cketh/candid/minter.d.ts index d22602570..8b3093a34 100644 --- a/packages/cketh/candid/minter.d.ts +++ b/packages/cketh/candid/minter.d.ts @@ -240,6 +240,7 @@ export interface MinterInfo { eth_balance: [] | [bigint]; eth_helper_contract_address: [] | [string]; last_observed_block_number: [] | [bigint]; + evm_rpc_id: [] | [Principal]; erc20_helper_contract_address: [] | [string]; last_erc20_scraped_block_number: [] | [bigint]; supported_ckerc20_tokens: [] | [Array]; diff --git a/packages/cketh/candid/minter.did b/packages/cketh/candid/minter.did index 20083f57a..d44588a13 100644 --- a/packages/cketh/candid/minter.did +++ b/packages/cketh/candid/minter.did @@ -1,4 +1,4 @@ -// Generated from IC repo commit 3c76b91 (2024-10-17 tags: release-2024-10-17_03-07-scheduler-changes-guestos-revert) 'rs/ethereum/cketh/minter/cketh_minter.did' by import-candid +// Generated from IC repo commit a6ef593 (2024-10-24 tags: release-2024-10-23_03-07-ubuntu20.04) 'rs/ethereum/cketh/minter/cketh_minter.did' by import-candid type EthereumNetwork = variant { // The public Ethereum mainnet. Mainnet; @@ -196,6 +196,10 @@ type MinterInfo = record { // Canister ID of the ckETH ledger. cketh_ledger_id: opt principal; + + // Canister ID of the EVM RPC canister that handles the communication + // with the Ethereum blockchain. + evm_rpc_id : opt principal; }; diff --git a/packages/cketh/candid/minter.idl.js b/packages/cketh/candid/minter.idl.js index 0922b0759..26f6c1f11 100644 --- a/packages/cketh/candid/minter.idl.js +++ b/packages/cketh/candid/minter.idl.js @@ -241,6 +241,7 @@ export const idlFactory = ({ IDL }) => { 'eth_balance' : IDL.Opt(IDL.Nat), 'eth_helper_contract_address' : IDL.Opt(IDL.Text), 'last_observed_block_number' : IDL.Opt(IDL.Nat), + 'evm_rpc_id' : IDL.Opt(IDL.Principal), 'erc20_helper_contract_address' : IDL.Opt(IDL.Text), 'last_erc20_scraped_block_number' : IDL.Opt(IDL.Nat), 'supported_ckerc20_tokens' : IDL.Opt(IDL.Vec(CkErc20Token)), diff --git a/packages/cketh/candid/orchestrator.did b/packages/cketh/candid/orchestrator.did index 90fe9a2c9..0676916ec 100644 --- a/packages/cketh/candid/orchestrator.did +++ b/packages/cketh/candid/orchestrator.did @@ -1,4 +1,4 @@ -// Generated from IC repo commit 3c76b91 (2024-10-17 tags: release-2024-10-17_03-07-scheduler-changes-guestos-revert) 'rs/ethereum/ledger-suite-orchestrator/ledger_suite_orchestrator.did' by import-candid +// Generated from IC repo commit a6ef593 (2024-10-24 tags: release-2024-10-23_03-07-ubuntu20.04) 'rs/ethereum/ledger-suite-orchestrator/ledger_suite_orchestrator.did' by import-candid type OrchestratorArg = variant { UpgradeArg : UpgradeArg; InitArg : InitArg; diff --git a/packages/cketh/src/minter.canister.spec.ts b/packages/cketh/src/minter.canister.spec.ts index 81df52676..b82ea6627 100644 --- a/packages/cketh/src/minter.canister.spec.ts +++ b/packages/cketh/src/minter.canister.spec.ts @@ -741,6 +741,9 @@ describe("ckETH minter canister", () => { supported_ckerc20_tokens: [], last_erc20_scraped_block_number: [5892643n], last_eth_scraped_block_number: [5892601n], + evm_rpc_id: toNullable( + Principal.fromText("7hfb6-caaaa-aaaar-qadga-cai"), + ), }; const service = mock>(); diff --git a/packages/cmc/LICENSE b/packages/cmc/LICENSE index 4874b73b8..7b214fe22 100644 --- a/packages/cmc/LICENSE +++ b/packages/cmc/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2021 DFINITY LLC. + Copyright 2021 DFINITY Stiftung. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packages/cmc/candid/cmc.did b/packages/cmc/candid/cmc.did index 9269d7b3f..f832eea74 100644 --- a/packages/cmc/candid/cmc.did +++ b/packages/cmc/candid/cmc.did @@ -1,4 +1,4 @@ -// Generated from IC repo commit 3c76b91 (2024-10-17 tags: release-2024-10-17_03-07-scheduler-changes-guestos-revert) 'rs/nns/cmc/cmc.did' by import-candid +// Generated from IC repo commit a6ef593 (2024-10-24 tags: release-2024-10-23_03-07-ubuntu20.04) 'rs/nns/cmc/cmc.did' by import-candid type Cycles = nat; type BlockIndex = nat64; type log_visibility = variant { diff --git a/packages/ic-management/LICENSE b/packages/ic-management/LICENSE index 4874b73b8..7b214fe22 100644 --- a/packages/ic-management/LICENSE +++ b/packages/ic-management/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2021 DFINITY LLC. + Copyright 2021 DFINITY Stiftung. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packages/ledger-icp/LICENSE b/packages/ledger-icp/LICENSE index 4874b73b8..7b214fe22 100644 --- a/packages/ledger-icp/LICENSE +++ b/packages/ledger-icp/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2021 DFINITY LLC. + Copyright 2021 DFINITY Stiftung. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packages/ledger-icp/candid/index.did b/packages/ledger-icp/candid/index.did index a32d73e49..f1c8b7018 100644 --- a/packages/ledger-icp/candid/index.did +++ b/packages/ledger-icp/candid/index.did @@ -1,4 +1,4 @@ -// Generated from IC repo commit 3c76b91 (2024-10-17 tags: release-2024-10-17_03-07-scheduler-changes-guestos-revert) 'rs/ledger_suite/icp/index/index.did' by import-candid +// Generated from IC repo commit a6ef593 (2024-10-24 tags: release-2024-10-23_03-07-ubuntu20.04) 'rs/ledger_suite/icp/index/index.did' by import-candid type Account = record { owner : principal; subaccount : opt vec nat8 }; type GetAccountIdentifierTransactionsArgs = record { max_results : nat64; diff --git a/packages/ledger-icp/candid/ledger.did b/packages/ledger-icp/candid/ledger.did index 1c0f095db..68426db63 100644 --- a/packages/ledger-icp/candid/ledger.did +++ b/packages/ledger-icp/candid/ledger.did @@ -1,4 +1,4 @@ -// Generated from IC repo commit 3c76b91 (2024-10-17 tags: release-2024-10-17_03-07-scheduler-changes-guestos-revert) 'rs/ledger_suite/icp/ledger.did' by import-candid +// Generated from IC repo commit a6ef593 (2024-10-24 tags: release-2024-10-23_03-07-ubuntu20.04) 'rs/ledger_suite/icp/ledger.did' by import-candid // This is the official Ledger interface that is guaranteed to be backward compatible. // Amount of tokens, measured in 10^-8 of a token. diff --git a/packages/ledger-icrc/LICENSE b/packages/ledger-icrc/LICENSE index 4874b73b8..7b214fe22 100644 --- a/packages/ledger-icrc/LICENSE +++ b/packages/ledger-icrc/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2021 DFINITY LLC. + Copyright 2021 DFINITY Stiftung. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packages/ledger-icrc/candid/icrc_index-ng.did b/packages/ledger-icrc/candid/icrc_index-ng.did index dbf29f928..a027b9041 100644 --- a/packages/ledger-icrc/candid/icrc_index-ng.did +++ b/packages/ledger-icrc/candid/icrc_index-ng.did @@ -1,4 +1,4 @@ -// Generated from IC repo commit 3c76b91 (2024-10-17 tags: release-2024-10-17_03-07-scheduler-changes-guestos-revert) 'rs/ledger_suite/icrc1/index-ng/index-ng.did' by import-candid +// Generated from IC repo commit a6ef593 (2024-10-24 tags: release-2024-10-23_03-07-ubuntu20.04) 'rs/ledger_suite/icrc1/index-ng/index-ng.did' by import-candid type Tokens = nat; type InitArg = record { diff --git a/packages/ledger-icrc/candid/icrc_index.did b/packages/ledger-icrc/candid/icrc_index.did index ffd5ee45a..e0b4feefc 100644 --- a/packages/ledger-icrc/candid/icrc_index.did +++ b/packages/ledger-icrc/candid/icrc_index.did @@ -1,4 +1,4 @@ -// Generated from IC repo commit 3c76b91 (2024-10-17 tags: release-2024-10-17_03-07-scheduler-changes-guestos-revert) 'rs/ledger_suite/icrc1/index/index.did' by import-candid +// Generated from IC repo commit a6ef593 (2024-10-24 tags: release-2024-10-23_03-07-ubuntu20.04) 'rs/ledger_suite/icrc1/index/index.did' by import-candid type TxId = nat; type Account = record { owner : principal; subaccount : opt blob }; diff --git a/packages/ledger-icrc/candid/icrc_ledger.did b/packages/ledger-icrc/candid/icrc_ledger.did index ddd596fc6..fe906a636 100644 --- a/packages/ledger-icrc/candid/icrc_ledger.did +++ b/packages/ledger-icrc/candid/icrc_ledger.did @@ -1,4 +1,4 @@ -// Generated from IC repo commit 3c76b91 (2024-10-17 tags: release-2024-10-17_03-07-scheduler-changes-guestos-revert) 'rs/ledger_suite/icrc1/ledger/ledger.did' by import-candid +// Generated from IC repo commit a6ef593 (2024-10-24 tags: release-2024-10-23_03-07-ubuntu20.04) 'rs/ledger_suite/icrc1/ledger/ledger.did' by import-candid type BlockIndex = nat; type Subaccount = blob; // Number of nanoseconds since the UNIX epoch in UTC timezone. diff --git a/packages/nns-proto/LICENSE b/packages/nns-proto/LICENSE index 4874b73b8..7b214fe22 100644 --- a/packages/nns-proto/LICENSE +++ b/packages/nns-proto/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2021 DFINITY LLC. + Copyright 2021 DFINITY Stiftung. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packages/nns/LICENSE b/packages/nns/LICENSE index 4874b73b8..7b214fe22 100644 --- a/packages/nns/LICENSE +++ b/packages/nns/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2021 DFINITY LLC. + Copyright 2021 DFINITY Stiftung. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packages/nns/candid/genesis_token.did b/packages/nns/candid/genesis_token.did index 2e9cf85cb..88ef73cbe 100644 --- a/packages/nns/candid/genesis_token.did +++ b/packages/nns/candid/genesis_token.did @@ -1,4 +1,4 @@ -// Generated from IC repo commit 3c76b91 (2024-10-17 tags: release-2024-10-17_03-07-scheduler-changes-guestos-revert) 'rs/nns/gtc/canister/gtc.did' by import-candid +// Generated from IC repo commit a6ef593 (2024-10-24 tags: release-2024-10-23_03-07-ubuntu20.04) 'rs/nns/gtc/canister/gtc.did' by import-candid type AccountState = record { authenticated_principal_id : opt principal; successfully_transferred_neurons : vec TransferredNeuron; diff --git a/packages/nns/candid/governance.did b/packages/nns/candid/governance.did index 73bcf257e..d5fff586a 100644 --- a/packages/nns/candid/governance.did +++ b/packages/nns/candid/governance.did @@ -1,4 +1,4 @@ -// Generated from IC repo commit 3c76b91 (2024-10-17 tags: release-2024-10-17_03-07-scheduler-changes-guestos-revert) 'rs/nns/governance/canister/governance.did' by import-candid +// Generated from IC repo commit a6ef593 (2024-10-24 tags: release-2024-10-23_03-07-ubuntu20.04) 'rs/nns/governance/canister/governance.did' by import-candid type AccountIdentifier = record { hash : blob; }; diff --git a/packages/nns/candid/governance_test.did b/packages/nns/candid/governance_test.did index 2b696b4a9..440b4b2d0 100644 --- a/packages/nns/candid/governance_test.did +++ b/packages/nns/candid/governance_test.did @@ -1,4 +1,4 @@ -// Generated from IC repo commit 3c76b91 (2024-10-17 tags: release-2024-10-17_03-07-scheduler-changes-guestos-revert) 'rs/nns/governance/canister/governance_test.did' by import-candid +// Generated from IC repo commit a6ef593 (2024-10-24 tags: release-2024-10-23_03-07-ubuntu20.04) 'rs/nns/governance/canister/governance_test.did' by import-candid type AccountIdentifier = record { hash : blob; }; diff --git a/packages/nns/candid/sns_wasm.did b/packages/nns/candid/sns_wasm.did index 6d5c5639c..c61a18863 100644 --- a/packages/nns/candid/sns_wasm.did +++ b/packages/nns/candid/sns_wasm.did @@ -1,4 +1,4 @@ -// Generated from IC repo commit 3c76b91 (2024-10-17 tags: release-2024-10-17_03-07-scheduler-changes-guestos-revert) 'rs/nns/sns-wasm/canister/sns-wasm.did' by import-candid +// Generated from IC repo commit a6ef593 (2024-10-24 tags: release-2024-10-23_03-07-ubuntu20.04) 'rs/nns/sns-wasm/canister/sns-wasm.did' by import-candid type AddWasmRequest = record { hash : blob; wasm : opt SnsWasm; diff --git a/packages/sns/LICENSE b/packages/sns/LICENSE index 4874b73b8..7b214fe22 100644 --- a/packages/sns/LICENSE +++ b/packages/sns/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2021 DFINITY LLC. + Copyright 2021 DFINITY Stiftung. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packages/sns/candid/sns_governance.certified.idl.js b/packages/sns/candid/sns_governance.certified.idl.js index cab6d0531..9428ddcac 100644 --- a/packages/sns/candid/sns_governance.certified.idl.js +++ b/packages/sns/candid/sns_governance.certified.idl.js @@ -1,5 +1,9 @@ /* Do not edit. Compiled with ./scripts/compile-idl-js from packages/sns/candid/sns_governance.did */ export const idlFactory = ({ IDL }) => { + const Timers = IDL.Record({ + 'last_spawned_timestamp_seconds' : IDL.Opt(IDL.Nat64), + 'last_reset_timestamp_seconds' : IDL.Opt(IDL.Nat64), + }); const Version = IDL.Record({ 'archive_wasm_hash' : IDL.Vec(IDL.Nat8), 'root_wasm_hash' : IDL.Vec(IDL.Nat8), @@ -363,6 +367,7 @@ export const idlFactory = ({ IDL }) => { }); const Governance = IDL.Record({ 'root_canister_id' : IDL.Opt(IDL.Principal), + 'timers' : IDL.Opt(Timers), 'cached_upgrade_steps' : IDL.Opt(CachedUpgradeSteps), 'id_to_nervous_system_functions' : IDL.Vec( IDL.Tuple(IDL.Nat64, NervousSystemFunction) @@ -470,6 +475,7 @@ export const idlFactory = ({ IDL }) => { const GetSnsInitializationParametersResponse = IDL.Record({ 'sns_initialization_parameters' : IDL.Text, }); + const GetTimersResponse = IDL.Record({ 'timers' : IDL.Opt(Timers) }); const GetUpgradeJournalRequest = IDL.Record({}); const GetUpgradeJournalResponse = IDL.Record({ 'upgrade_steps' : IDL.Opt(Versions), @@ -594,6 +600,7 @@ export const idlFactory = ({ IDL }) => { [GetSnsInitializationParametersResponse], [], ), + 'get_timers' : IDL.Func([IDL.Record({})], [GetTimersResponse], []), 'get_upgrade_journal' : IDL.Func( [GetUpgradeJournalRequest], [GetUpgradeJournalResponse], @@ -607,10 +614,15 @@ export const idlFactory = ({ IDL }) => { 'list_neurons' : IDL.Func([ListNeurons], [ListNeuronsResponse], []), 'list_proposals' : IDL.Func([ListProposals], [ListProposalsResponse], []), 'manage_neuron' : IDL.Func([ManageNeuron], [ManageNeuronResponse], []), + 'reset_timers' : IDL.Func([IDL.Record({})], [IDL.Record({})], []), 'set_mode' : IDL.Func([SetMode], [IDL.Record({})], []), }); }; export const init = ({ IDL }) => { + const Timers = IDL.Record({ + 'last_spawned_timestamp_seconds' : IDL.Opt(IDL.Nat64), + 'last_reset_timestamp_seconds' : IDL.Opt(IDL.Nat64), + }); const Version = IDL.Record({ 'archive_wasm_hash' : IDL.Vec(IDL.Nat8), 'root_wasm_hash' : IDL.Vec(IDL.Nat8), @@ -974,6 +986,7 @@ export const init = ({ IDL }) => { }); const Governance = IDL.Record({ 'root_canister_id' : IDL.Opt(IDL.Principal), + 'timers' : IDL.Opt(Timers), 'cached_upgrade_steps' : IDL.Opt(CachedUpgradeSteps), 'id_to_nervous_system_functions' : IDL.Vec( IDL.Tuple(IDL.Nat64, NervousSystemFunction) diff --git a/packages/sns/candid/sns_governance.d.ts b/packages/sns/candid/sns_governance.d.ts index 146a5f918..502e5eb3f 100644 --- a/packages/sns/candid/sns_governance.d.ts +++ b/packages/sns/candid/sns_governance.d.ts @@ -222,6 +222,9 @@ export interface GetRunningSnsVersionResponse { export interface GetSnsInitializationParametersResponse { sns_initialization_parameters: string; } +export interface GetTimersResponse { + timers: [] | [Timers]; +} export type GetUpgradeJournalRequest = {}; export interface GetUpgradeJournalResponse { upgrade_steps: [] | [Versions]; @@ -230,6 +233,7 @@ export interface GetUpgradeJournalResponse { } export interface Governance { root_canister_id: [] | [Principal]; + timers: [] | [Timers]; cached_upgrade_steps: [] | [CachedUpgradeSteps]; id_to_nervous_system_functions: Array<[bigint, NervousSystemFunction]>; metrics: [] | [GovernanceCachedMetrics]; @@ -542,6 +546,10 @@ export interface Tally { total: bigint; timestamp_seconds: bigint; } +export interface Timers { + last_spawned_timestamp_seconds: [] | [bigint]; + last_reset_timestamp_seconds: [] | [bigint]; +} export interface Tokens { e8s: [] | [bigint]; } @@ -615,6 +623,7 @@ export interface _SERVICE { [{}], GetSnsInitializationParametersResponse >; + get_timers: ActorMethod<[{}], GetTimersResponse>; get_upgrade_journal: ActorMethod< [GetUpgradeJournalRequest], GetUpgradeJournalResponse @@ -626,6 +635,7 @@ export interface _SERVICE { list_neurons: ActorMethod<[ListNeurons], ListNeuronsResponse>; list_proposals: ActorMethod<[ListProposals], ListProposalsResponse>; manage_neuron: ActorMethod<[ManageNeuron], ManageNeuronResponse>; + reset_timers: ActorMethod<[{}], {}>; set_mode: ActorMethod<[SetMode], {}>; } export declare const idlFactory: IDL.InterfaceFactory; diff --git a/packages/sns/candid/sns_governance.did b/packages/sns/candid/sns_governance.did index 072f7f83c..b4368899c 100644 --- a/packages/sns/candid/sns_governance.did +++ b/packages/sns/candid/sns_governance.did @@ -1,4 +1,4 @@ -// Generated from IC repo commit 3c76b91 (2024-10-17 tags: release-2024-10-17_03-07-scheduler-changes-guestos-revert) 'rs/sns/governance/canister/governance.did' by import-candid +// Generated from IC repo commit a6ef593 (2024-10-24 tags: release-2024-10-23_03-07-ubuntu20.04) 'rs/sns/governance/canister/governance.did' by import-candid type Account = record { owner : opt principal; subaccount : opt Subaccount; @@ -292,6 +292,16 @@ type Governance = record { neurons : vec record { text; Neuron }; genesis_timestamp_seconds : nat64; target_version: opt Version; + timers : opt Timers; +}; + +type Timers = record { + last_reset_timestamp_seconds : opt nat64; + last_spawned_timestamp_seconds : opt nat64; +}; + +type GetTimersResponse = record { + timers : opt Timers; }; type GovernanceCachedMetrics = record { @@ -741,4 +751,6 @@ service : (Governance) -> { list_proposals : (ListProposals) -> (ListProposalsResponse) query; manage_neuron : (ManageNeuron) -> (ManageNeuronResponse); set_mode : (SetMode) -> (record {}); + reset_timers : (record {}) -> (record {}); + get_timers : (record {}) -> (GetTimersResponse) query; } diff --git a/packages/sns/candid/sns_governance.idl.js b/packages/sns/candid/sns_governance.idl.js index 8d19e7275..796ee636f 100644 --- a/packages/sns/candid/sns_governance.idl.js +++ b/packages/sns/candid/sns_governance.idl.js @@ -1,5 +1,9 @@ /* Do not edit. Compiled with ./scripts/compile-idl-js from packages/sns/candid/sns_governance.did */ export const idlFactory = ({ IDL }) => { + const Timers = IDL.Record({ + 'last_spawned_timestamp_seconds' : IDL.Opt(IDL.Nat64), + 'last_reset_timestamp_seconds' : IDL.Opt(IDL.Nat64), + }); const Version = IDL.Record({ 'archive_wasm_hash' : IDL.Vec(IDL.Nat8), 'root_wasm_hash' : IDL.Vec(IDL.Nat8), @@ -363,6 +367,7 @@ export const idlFactory = ({ IDL }) => { }); const Governance = IDL.Record({ 'root_canister_id' : IDL.Opt(IDL.Principal), + 'timers' : IDL.Opt(Timers), 'cached_upgrade_steps' : IDL.Opt(CachedUpgradeSteps), 'id_to_nervous_system_functions' : IDL.Vec( IDL.Tuple(IDL.Nat64, NervousSystemFunction) @@ -470,6 +475,7 @@ export const idlFactory = ({ IDL }) => { const GetSnsInitializationParametersResponse = IDL.Record({ 'sns_initialization_parameters' : IDL.Text, }); + const GetTimersResponse = IDL.Record({ 'timers' : IDL.Opt(Timers) }); const GetUpgradeJournalRequest = IDL.Record({}); const GetUpgradeJournalResponse = IDL.Record({ 'upgrade_steps' : IDL.Opt(Versions), @@ -598,6 +604,7 @@ export const idlFactory = ({ IDL }) => { [GetSnsInitializationParametersResponse], ['query'], ), + 'get_timers' : IDL.Func([IDL.Record({})], [GetTimersResponse], ['query']), 'get_upgrade_journal' : IDL.Func( [GetUpgradeJournalRequest], [GetUpgradeJournalResponse], @@ -615,10 +622,15 @@ export const idlFactory = ({ IDL }) => { ['query'], ), 'manage_neuron' : IDL.Func([ManageNeuron], [ManageNeuronResponse], []), + 'reset_timers' : IDL.Func([IDL.Record({})], [IDL.Record({})], []), 'set_mode' : IDL.Func([SetMode], [IDL.Record({})], []), }); }; export const init = ({ IDL }) => { + const Timers = IDL.Record({ + 'last_spawned_timestamp_seconds' : IDL.Opt(IDL.Nat64), + 'last_reset_timestamp_seconds' : IDL.Opt(IDL.Nat64), + }); const Version = IDL.Record({ 'archive_wasm_hash' : IDL.Vec(IDL.Nat8), 'root_wasm_hash' : IDL.Vec(IDL.Nat8), @@ -982,6 +994,7 @@ export const init = ({ IDL }) => { }); const Governance = IDL.Record({ 'root_canister_id' : IDL.Opt(IDL.Principal), + 'timers' : IDL.Opt(Timers), 'cached_upgrade_steps' : IDL.Opt(CachedUpgradeSteps), 'id_to_nervous_system_functions' : IDL.Vec( IDL.Tuple(IDL.Nat64, NervousSystemFunction) diff --git a/packages/sns/candid/sns_governance_test.certified.idl.js b/packages/sns/candid/sns_governance_test.certified.idl.js index 5d2e21dab..a639a6ccf 100644 --- a/packages/sns/candid/sns_governance_test.certified.idl.js +++ b/packages/sns/candid/sns_governance_test.certified.idl.js @@ -1,5 +1,9 @@ /* Do not edit. Compiled with ./scripts/compile-idl-js from packages/sns/candid/sns_governance_test.did */ export const idlFactory = ({ IDL }) => { + const Timers = IDL.Record({ + 'last_spawned_timestamp_seconds' : IDL.Opt(IDL.Nat64), + 'last_reset_timestamp_seconds' : IDL.Opt(IDL.Nat64), + }); const Version = IDL.Record({ 'archive_wasm_hash' : IDL.Vec(IDL.Nat8), 'root_wasm_hash' : IDL.Vec(IDL.Nat8), @@ -363,6 +367,7 @@ export const idlFactory = ({ IDL }) => { }); const Governance = IDL.Record({ 'root_canister_id' : IDL.Opt(IDL.Principal), + 'timers' : IDL.Opt(Timers), 'cached_upgrade_steps' : IDL.Opt(CachedUpgradeSteps), 'id_to_nervous_system_functions' : IDL.Vec( IDL.Tuple(IDL.Nat64, NervousSystemFunction) @@ -481,6 +486,7 @@ export const idlFactory = ({ IDL }) => { const GetSnsInitializationParametersResponse = IDL.Record({ 'sns_initialization_parameters' : IDL.Text, }); + const GetTimersResponse = IDL.Record({ 'timers' : IDL.Opt(Timers) }); const GetUpgradeJournalRequest = IDL.Record({}); const GetUpgradeJournalResponse = IDL.Record({ 'upgrade_steps' : IDL.Opt(Versions), @@ -615,6 +621,7 @@ export const idlFactory = ({ IDL }) => { [GetSnsInitializationParametersResponse], [], ), + 'get_timers' : IDL.Func([IDL.Record({})], [GetTimersResponse], []), 'get_upgrade_journal' : IDL.Func( [GetUpgradeJournalRequest], [GetUpgradeJournalResponse], @@ -629,11 +636,16 @@ export const idlFactory = ({ IDL }) => { 'list_proposals' : IDL.Func([ListProposals], [ListProposalsResponse], []), 'manage_neuron' : IDL.Func([ManageNeuron], [ManageNeuronResponse], []), 'mint_tokens' : IDL.Func([MintTokensRequest], [IDL.Record({})], []), + 'reset_timers' : IDL.Func([IDL.Record({})], [IDL.Record({})], []), 'set_mode' : IDL.Func([SetMode], [IDL.Record({})], []), 'update_neuron' : IDL.Func([Neuron], [IDL.Opt(GovernanceError)], []), }); }; export const init = ({ IDL }) => { + const Timers = IDL.Record({ + 'last_spawned_timestamp_seconds' : IDL.Opt(IDL.Nat64), + 'last_reset_timestamp_seconds' : IDL.Opt(IDL.Nat64), + }); const Version = IDL.Record({ 'archive_wasm_hash' : IDL.Vec(IDL.Nat8), 'root_wasm_hash' : IDL.Vec(IDL.Nat8), @@ -997,6 +1009,7 @@ export const init = ({ IDL }) => { }); const Governance = IDL.Record({ 'root_canister_id' : IDL.Opt(IDL.Principal), + 'timers' : IDL.Opt(Timers), 'cached_upgrade_steps' : IDL.Opt(CachedUpgradeSteps), 'id_to_nervous_system_functions' : IDL.Vec( IDL.Tuple(IDL.Nat64, NervousSystemFunction) diff --git a/packages/sns/candid/sns_governance_test.d.ts b/packages/sns/candid/sns_governance_test.d.ts index 47e847b4d..f9373ecf6 100644 --- a/packages/sns/candid/sns_governance_test.d.ts +++ b/packages/sns/candid/sns_governance_test.d.ts @@ -233,6 +233,9 @@ export interface GetRunningSnsVersionResponse { export interface GetSnsInitializationParametersResponse { sns_initialization_parameters: string; } +export interface GetTimersResponse { + timers: [] | [Timers]; +} export type GetUpgradeJournalRequest = {}; export interface GetUpgradeJournalResponse { upgrade_steps: [] | [Versions]; @@ -241,6 +244,7 @@ export interface GetUpgradeJournalResponse { } export interface Governance { root_canister_id: [] | [Principal]; + timers: [] | [Timers]; cached_upgrade_steps: [] | [CachedUpgradeSteps]; id_to_nervous_system_functions: Array<[bigint, NervousSystemFunction]>; metrics: [] | [GovernanceCachedMetrics]; @@ -557,6 +561,10 @@ export interface Tally { total: bigint; timestamp_seconds: bigint; } +export interface Timers { + last_spawned_timestamp_seconds: [] | [bigint]; + last_reset_timestamp_seconds: [] | [bigint]; +} export interface Tokens { e8s: [] | [bigint]; } @@ -635,6 +643,7 @@ export interface _SERVICE { [{}], GetSnsInitializationParametersResponse >; + get_timers: ActorMethod<[{}], GetTimersResponse>; get_upgrade_journal: ActorMethod< [GetUpgradeJournalRequest], GetUpgradeJournalResponse @@ -647,6 +656,7 @@ export interface _SERVICE { list_proposals: ActorMethod<[ListProposals], ListProposalsResponse>; manage_neuron: ActorMethod<[ManageNeuron], ManageNeuronResponse>; mint_tokens: ActorMethod<[MintTokensRequest], {}>; + reset_timers: ActorMethod<[{}], {}>; set_mode: ActorMethod<[SetMode], {}>; update_neuron: ActorMethod<[Neuron], [] | [GovernanceError]>; } diff --git a/packages/sns/candid/sns_governance_test.did b/packages/sns/candid/sns_governance_test.did index 092437a4f..002528645 100644 --- a/packages/sns/candid/sns_governance_test.did +++ b/packages/sns/candid/sns_governance_test.did @@ -1,4 +1,4 @@ -// Generated from IC repo commit 3c76b91 (2024-10-17 tags: release-2024-10-17_03-07-scheduler-changes-guestos-revert) 'rs/sns/governance/canister/governance_test.did' by import-candid +// Generated from IC repo commit a6ef593 (2024-10-24 tags: release-2024-10-23_03-07-ubuntu20.04) 'rs/sns/governance/canister/governance_test.did' by import-candid type Account = record { owner : opt principal; subaccount : opt Subaccount; @@ -301,6 +301,16 @@ type Governance = record { neurons : vec record { text; Neuron }; genesis_timestamp_seconds : nat64; target_version: opt Version; + timers : opt Timers; +}; + +type Timers = record { + last_reset_timestamp_seconds : opt nat64; + last_spawned_timestamp_seconds : opt nat64; +}; + +type GetTimersResponse = record { + timers : opt Timers; }; type GovernanceCachedMetrics = record { @@ -762,4 +772,6 @@ service : (Governance) -> { set_mode : (SetMode) -> (record {}); update_neuron : (Neuron) -> (opt GovernanceError); advance_target_version : (AdvanceTargetVersionRequest) -> (AdvanceTargetVersionResponse); + reset_timers : (record {}) -> (record {}); + get_timers : (record {}) -> (GetTimersResponse) query; } diff --git a/packages/sns/candid/sns_governance_test.idl.js b/packages/sns/candid/sns_governance_test.idl.js index 70e98d54d..815bce1ad 100644 --- a/packages/sns/candid/sns_governance_test.idl.js +++ b/packages/sns/candid/sns_governance_test.idl.js @@ -1,5 +1,9 @@ /* Do not edit. Compiled with ./scripts/compile-idl-js from packages/sns/candid/sns_governance_test.did */ export const idlFactory = ({ IDL }) => { + const Timers = IDL.Record({ + 'last_spawned_timestamp_seconds' : IDL.Opt(IDL.Nat64), + 'last_reset_timestamp_seconds' : IDL.Opt(IDL.Nat64), + }); const Version = IDL.Record({ 'archive_wasm_hash' : IDL.Vec(IDL.Nat8), 'root_wasm_hash' : IDL.Vec(IDL.Nat8), @@ -363,6 +367,7 @@ export const idlFactory = ({ IDL }) => { }); const Governance = IDL.Record({ 'root_canister_id' : IDL.Opt(IDL.Principal), + 'timers' : IDL.Opt(Timers), 'cached_upgrade_steps' : IDL.Opt(CachedUpgradeSteps), 'id_to_nervous_system_functions' : IDL.Vec( IDL.Tuple(IDL.Nat64, NervousSystemFunction) @@ -481,6 +486,7 @@ export const idlFactory = ({ IDL }) => { const GetSnsInitializationParametersResponse = IDL.Record({ 'sns_initialization_parameters' : IDL.Text, }); + const GetTimersResponse = IDL.Record({ 'timers' : IDL.Opt(Timers) }); const GetUpgradeJournalRequest = IDL.Record({}); const GetUpgradeJournalResponse = IDL.Record({ 'upgrade_steps' : IDL.Opt(Versions), @@ -619,6 +625,7 @@ export const idlFactory = ({ IDL }) => { [GetSnsInitializationParametersResponse], ['query'], ), + 'get_timers' : IDL.Func([IDL.Record({})], [GetTimersResponse], ['query']), 'get_upgrade_journal' : IDL.Func( [GetUpgradeJournalRequest], [GetUpgradeJournalResponse], @@ -637,11 +644,16 @@ export const idlFactory = ({ IDL }) => { ), 'manage_neuron' : IDL.Func([ManageNeuron], [ManageNeuronResponse], []), 'mint_tokens' : IDL.Func([MintTokensRequest], [IDL.Record({})], []), + 'reset_timers' : IDL.Func([IDL.Record({})], [IDL.Record({})], []), 'set_mode' : IDL.Func([SetMode], [IDL.Record({})], []), 'update_neuron' : IDL.Func([Neuron], [IDL.Opt(GovernanceError)], []), }); }; export const init = ({ IDL }) => { + const Timers = IDL.Record({ + 'last_spawned_timestamp_seconds' : IDL.Opt(IDL.Nat64), + 'last_reset_timestamp_seconds' : IDL.Opt(IDL.Nat64), + }); const Version = IDL.Record({ 'archive_wasm_hash' : IDL.Vec(IDL.Nat8), 'root_wasm_hash' : IDL.Vec(IDL.Nat8), @@ -1005,6 +1017,7 @@ export const init = ({ IDL }) => { }); const Governance = IDL.Record({ 'root_canister_id' : IDL.Opt(IDL.Principal), + 'timers' : IDL.Opt(Timers), 'cached_upgrade_steps' : IDL.Opt(CachedUpgradeSteps), 'id_to_nervous_system_functions' : IDL.Vec( IDL.Tuple(IDL.Nat64, NervousSystemFunction) diff --git a/packages/sns/candid/sns_root.did b/packages/sns/candid/sns_root.did index 4f1c12ec3..8d1f49f2f 100644 --- a/packages/sns/candid/sns_root.did +++ b/packages/sns/candid/sns_root.did @@ -1,4 +1,4 @@ -// Generated from IC repo commit 3c76b91 (2024-10-17 tags: release-2024-10-17_03-07-scheduler-changes-guestos-revert) 'rs/sns/root/canister/root.did' by import-candid +// Generated from IC repo commit a6ef593 (2024-10-24 tags: release-2024-10-23_03-07-ubuntu20.04) 'rs/sns/root/canister/root.did' by import-candid type CanisterCallError = record { code : opt int32; description : text; diff --git a/packages/sns/candid/sns_swap.did b/packages/sns/candid/sns_swap.did index 89fd17196..b65e9d3b3 100644 --- a/packages/sns/candid/sns_swap.did +++ b/packages/sns/candid/sns_swap.did @@ -1,4 +1,4 @@ -// Generated from IC repo commit 3c76b91 (2024-10-17 tags: release-2024-10-17_03-07-scheduler-changes-guestos-revert) 'rs/sns/swap/canister/swap.did' by import-candid +// Generated from IC repo commit a6ef593 (2024-10-24 tags: release-2024-10-23_03-07-ubuntu20.04) 'rs/sns/swap/canister/swap.did' by import-candid type BuyerState = record { icp : opt TransferableAmount; has_created_neuron_recipes : opt bool; diff --git a/packages/utils/LICENSE b/packages/utils/LICENSE index 4874b73b8..7b214fe22 100644 --- a/packages/utils/LICENSE +++ b/packages/utils/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2021 DFINITY LLC. + Copyright 2021 DFINITY Stiftung. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packages/utils/README.md b/packages/utils/README.md index d37a48623..eaff4fae9 100644 --- a/packages/utils/README.md +++ b/packages/utils/README.md @@ -565,6 +565,70 @@ Parameters: [:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/utils/src/services/canister.ts#L4) +### :factory: AgentManager + +AgentManager class manages HttpAgent instances for different identities. + +It caches agents by identity to optimise resource usage and avoid unnecessary agent creation. +Provides functionality to create new agents, retrieve cached agents, and clear the cache when needed. + +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/utils/src/utils/agent.utils.ts#L53) + +#### Methods + +- [create](#gear-create) +- [getAgent](#gear-getagent) +- [clearAgents](#gear-clearagents) + +##### :gear: create + +Static factory method to create a new AgentManager instance. + +This method serves as an alternative to directly using the private constructor, +making it more convenient to create instances of `AgentManager` using a simple and clear method. + +| Method | Type | +| -------- | ---------------------------------------------- | +| `create` | `(config: AgentManagerConfig) => AgentManager` | + +Parameters: + +- `config`: - Configuration options for the AgentManager instance. +- `config.fetchRootKey`: - Whether to fetch the root key for certificate validation. +- `config.host`: - The host to connect to. + +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/utils/src/utils/agent.utils.ts#L69) + +##### :gear: getAgent + +Get or create an HTTP agent for a given identity. + +If the agent for the specified identity has been created and cached, it is retrieved from the cache. +If no agent exists for the identity, a new one is created, cached, and then returned. + +| Method | Type | +| ---------- | ---------------------------------------------------------------- | +| `getAgent` | `({ identity, }: { identity: Identity; }) => Promise` | + +Parameters: + +- `identity`: - The identity to be used to create the agent. + +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/utils/src/utils/agent.utils.ts#L82) + +##### :gear: clearAgents + +Clear the cache of HTTP agents. + +This method removes all cached agents, forcing new agent creation on the next request for any identity. +Useful when identities have changed or if you want to reset all active connections. + +| Method | Type | +| ------------- | ------------ | +| `clearAgents` | `() => void` | + +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/utils/src/utils/agent.utils.ts#L114) + ### :factory: InvalidPercentageError [:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/utils/src/utils/asserts.utils.ts#L1) diff --git a/packages/utils/src/mocks/agent.mock.ts b/packages/utils/src/mocks/agent.mock.ts new file mode 100644 index 000000000..34e2e4f25 --- /dev/null +++ b/packages/utils/src/mocks/agent.mock.ts @@ -0,0 +1,39 @@ +import type { HttpAgent } from "@dfinity/agent"; +import { AgentManagerConfig } from "../utils/agent.utils"; + +export const mockHttpAgent = { + call: jest.fn().mockResolvedValue({ + ok: true, + status: 200, + statusText: "OK", + json: async () => ({ data: "mocked call result" }), + }), + query: jest.fn().mockResolvedValue({ + ok: true, + status: 200, + statusText: "OK", + json: async () => ({ data: "mocked query result" }), + }), + fetchRootKey: jest.fn().mockResolvedValue(undefined), +} as unknown as HttpAgent; + +export const mockHttpAgent2 = { + call: jest.fn().mockResolvedValue({ + ok: true, + status: 200, + statusText: "OK", + json: async () => ({ data: "mocked call result" }), + }), + query: jest.fn().mockResolvedValue({ + ok: true, + status: 200, + statusText: "OK", + json: async () => ({ data: "mocked query result" }), + }), + fetchRootKey: jest.fn().mockResolvedValue(undefined), +} as unknown as HttpAgent; + +export const mockAgentManagerConfig: AgentManagerConfig = { + fetchRootKey: false, + host: "https://icp-api.io", +}; diff --git a/packages/utils/src/mocks/identity.mock.ts b/packages/utils/src/mocks/identity.mock.ts new file mode 100644 index 000000000..3a0a4a4e1 --- /dev/null +++ b/packages/utils/src/mocks/identity.mock.ts @@ -0,0 +1,20 @@ +import type { Identity } from "@dfinity/agent"; +import { Principal } from "@dfinity/principal"; + +export const mockPrincipalText = + "xlmdg-vkosz-ceopx-7wtgu-g3xmd-koiyc-awqaq-7modz-zf6r6-364rh-oqe"; + +export const mockPrincipal = Principal.fromText(mockPrincipalText); + +export const mockIdentity = { + getPrincipal: () => mockPrincipal, +} as unknown as Identity; + +export const mockPrincipalText2 = + "5uuwe-ggtgm-fonrs-rblmx-cfc23-pb3dg-iyfk2-dle5w-j5uev-ggmep-6ae"; + +export const mockPrincipal2 = Principal.fromText(mockPrincipalText2); + +export const mockIdentity2 = { + getPrincipal: () => mockPrincipal2, +} as unknown as Identity; diff --git a/packages/utils/src/utils/agent.utils.spec.ts b/packages/utils/src/utils/agent.utils.spec.ts new file mode 100644 index 000000000..88ad79e25 --- /dev/null +++ b/packages/utils/src/utils/agent.utils.spec.ts @@ -0,0 +1,86 @@ +import { HttpAgent } from "@dfinity/agent"; +import { describe, expect } from "@jest/globals"; +import { + mockAgentManagerConfig, + mockHttpAgent, + mockHttpAgent2, +} from "../mocks/agent.mock"; +import { mockIdentity, mockIdentity2 } from "../mocks/identity.mock"; +import { AgentManager } from "./agent.utils"; + +jest.mock("@dfinity/agent", () => ({ + HttpAgent: { + create: jest.fn(), + }, +})); + +describe("AgentManager", () => { + let agentManager: AgentManager; + const mockHttpAgentCreate = HttpAgent.create as jest.Mock; + + beforeEach(() => { + agentManager = AgentManager.create(mockAgentManagerConfig); + jest.clearAllMocks(); + + mockHttpAgentCreate.mockResolvedValueOnce(mockHttpAgent); + }); + + describe("getAgent", () => { + it("should create a new agent when there is none", async () => { + const agent = await agentManager.getAgent({ identity: mockIdentity }); + + expect(mockHttpAgentCreate).toHaveBeenCalledWith( + expect.objectContaining({ identity: mockIdentity }), + ); + expect(agent).toBe(mockHttpAgent); + }); + + it("should return cached agent if already created", async () => { + await agentManager.getAgent({ identity: mockIdentity }); + + const agent = await agentManager.getAgent({ identity: mockIdentity }); + + expect(mockHttpAgentCreate).toHaveBeenCalledTimes(1); + expect(agent).toBe(mockHttpAgent); + }); + + it("should handle multiple agents for multiple identities", async () => { + await agentManager.getAgent({ identity: mockIdentity }); + + mockHttpAgentCreate.mockResolvedValueOnce(mockHttpAgent2); + + const agent2 = await agentManager.getAgent({ identity: mockIdentity2 }); + const agent1 = await agentManager.getAgent({ identity: mockIdentity }); + + expect(mockHttpAgentCreate).toHaveBeenCalledTimes(2); + + expect(agent1).toBe(mockHttpAgent); + expect(agent1).not.toBe(mockHttpAgent2); + + expect(agent2).toBe(mockHttpAgent2); + expect(agent2).not.toBe(mockHttpAgent); + }); + }); + + describe("clearAgents", () => { + it("should clear cached agents", async () => { + await agentManager.getAgent({ identity: mockIdentity }); + + const agentBefore = await agentManager.getAgent({ + identity: mockIdentity, + }); + + expect(agentBefore).toBe(mockHttpAgent); + + agentManager.clearAgents(); + + const agentAfter = await agentManager.getAgent({ + identity: mockIdentity, + }); + + expect(mockHttpAgentCreate).toHaveBeenCalledTimes(2); + expect(agentAfter).not.toBe(mockHttpAgent); + expect(agentAfter).toBeUndefined(); + }); + }); +}); diff --git a/packages/utils/src/utils/agent.utils.ts b/packages/utils/src/utils/agent.utils.ts index bfe572fd3..0c4cd76f2 100644 --- a/packages/utils/src/utils/agent.utils.ts +++ b/packages/utils/src/utils/agent.utils.ts @@ -1,7 +1,7 @@ -import type { Agent } from "@dfinity/agent"; +import type { Agent, Identity } from "@dfinity/agent"; import { AnonymousIdentity, HttpAgent } from "@dfinity/agent"; import type { CreateAgentParams } from "../types/agent.utils"; -import { nonNullish } from "./nullish.utils"; +import { isNullish, nonNullish } from "./nullish.utils"; /** * Get a default agent that connects to mainnet with the anonymous identity. @@ -38,3 +38,80 @@ export const createAgent = async ({ shouldFetchRootKey: fetchRootKey, }); }; + +export type AgentManagerConfig = Pick< + CreateAgentParams, + "fetchRootKey" | "host" +>; + +/** + * AgentManager class manages HttpAgent instances for different identities. + * + * It caches agents by identity to optimise resource usage and avoid unnecessary agent creation. + * Provides functionality to create new agents, retrieve cached agents, and clear the cache when needed. + */ +export class AgentManager { + private agents: Record | undefined | null = undefined; + + private constructor(private readonly config: AgentManagerConfig) {} + + /** + * Static factory method to create a new AgentManager instance. + * + * This method serves as an alternative to directly using the private constructor, + * making it more convenient to create instances of `AgentManager` using a simple and clear method. + * + * @param {AgentManagerConfig} config - Configuration options for the AgentManager instance. + * @param {boolean} config.fetchRootKey - Whether to fetch the root key for certificate validation. + * @param {string} config.host - The host to connect to. + * @returns {AgentManager} A new instance of `AgentManager`. + */ + public static create(config: AgentManagerConfig): AgentManager { + return new AgentManager(config); + } + + /** + * Get or create an HTTP agent for a given identity. + * + * If the agent for the specified identity has been created and cached, it is retrieved from the cache. + * If no agent exists for the identity, a new one is created, cached, and then returned. + * + * @param {Identity} identity - The identity to be used to create the agent. + * @returns {Promise} The HttpAgent associated with the given identity. + */ + public async getAgent({ + identity, + }: { + identity: Identity; + }): Promise { + const key = identity.getPrincipal().toText(); + + if (isNullish(this.agents) || isNullish(this.agents[key])) { + const agent = await createAgent({ + identity, + fetchRootKey: this.config.fetchRootKey, + host: this.config.host, + verifyQuerySignatures: true, + }); + + this.agents = { + ...(this.agents ?? {}), + [key]: agent, + }; + + return agent; + } + + return this.agents[key]; + } + + /** + * Clear the cache of HTTP agents. + * + * This method removes all cached agents, forcing new agent creation on the next request for any identity. + * Useful when identities have changed or if you want to reset all active connections. + */ + public clearAgents(): void { + this.agents = null; + } +}