Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions modules/sdk-coin-icp/src/icp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
TssVerifyAddressOptions,
VerifyTransactionOptions,
} from '@bitgo/sdk-core';
import { coins, BaseCoin as StaticsBaseCoin } from '@bitgo/statics';
import { coins, NetworkType, BaseCoin as StaticsBaseCoin } from '@bitgo/statics';
import { Principal } from '@dfinity/principal';
import axios from 'axios';
import BigNumber from 'bignumber.js';
Expand All @@ -30,6 +30,7 @@ import * as mpc from '@bitgo/sdk-lib-mpc';
import {
CurveType,
LEDGER_CANISTER_ID,
TESTNET_LEDGER_CANISTER_ID,
PayloadsData,
PUBLIC_NODE_REQUEST_ENDPOINT,
PublicNodeSubmitResponse,
Expand Down Expand Up @@ -249,7 +250,9 @@ export class Icp extends BaseCoin {

private getPublicNodeBroadcastEndpoint(): string {
const nodeUrl = this.getPublicNodeUrl();
const principal = Principal.fromUint8Array(LEDGER_CANISTER_ID);
const ledgerCanisterId =
this._staticsCoin.network.type === NetworkType.TESTNET ? TESTNET_LEDGER_CANISTER_ID : LEDGER_CANISTER_ID;
const principal = Principal.fromUint8Array(ledgerCanisterId);
const canisterIdHex = principal.toText();
const endpoint = `${nodeUrl}${PUBLIC_NODE_REQUEST_ENDPOINT}${canisterIdHex}/call`;
return endpoint;
Expand All @@ -263,7 +266,7 @@ export class Icp extends BaseCoin {
*/
protected async getAccountBalance(publicKeyHex: string): Promise<BigNumber> {
const principalId = utils.getPrincipalIdFromPublicKey(publicKeyHex).toText();
const agent = new IcpAgent(this.getPublicNodeUrl());
const agent = new IcpAgent(this.getPublicNodeUrl(), this._staticsCoin);
return agent.getBalance(principalId);
}

Expand All @@ -277,7 +280,7 @@ export class Icp extends BaseCoin {
* @throws Will propagate any errors encountered while communicating with the ICP node.
*/
protected async getFeeData(): Promise<BigNumber> {
const agent = new IcpAgent(this.getPublicNodeUrl());
const agent = new IcpAgent(this.getPublicNodeUrl(), this._staticsCoin);
return await agent.getFee();
}

Expand Down
18 changes: 15 additions & 3 deletions modules/sdk-coin-icp/src/lib/icpAgent.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
import { Principal } from '@dfinity/principal';
import { HttpAgent, replica, AgentCanister } from 'ic0';
import utils from './utils';
import { ACCOUNT_BALANCE_CALL, LEDGER_CANISTER_ID, ICRC1_FEE_KEY, METADATA_CALL, DEFAULT_SUBACCOUNT } from './iface';
import {
ACCOUNT_BALANCE_CALL,
LEDGER_CANISTER_ID,
TESTNET_LEDGER_CANISTER_ID,
ICRC1_FEE_KEY,
METADATA_CALL,
DEFAULT_SUBACCOUNT,
} from './iface';
import BigNumber from 'bignumber.js';
import { NetworkType, BaseCoin as StaticsBaseCoin } from '@bitgo/statics';

export class IcpAgent {
private readonly host: string;
private readonly staticsCoin: Readonly<StaticsBaseCoin>;

constructor(host: string) {
constructor(host: string, staticsCoin: Readonly<StaticsBaseCoin>) {
this.host = host;
this.staticsCoin = staticsCoin;
}

/**
Expand All @@ -35,7 +45,9 @@ export class IcpAgent {
private getLedger(): AgentCanister {
const agent = this.createAgent();
const ic = replica(agent, { local: true });
return ic(Principal.fromUint8Array(LEDGER_CANISTER_ID).toText());
const ledgerCanisterId =
this.staticsCoin.network.type === NetworkType.TESTNET ? TESTNET_LEDGER_CANISTER_ID : LEDGER_CANISTER_ID;
return ic(Principal.fromUint8Array(ledgerCanisterId).toText());
}

/**
Expand Down
7 changes: 6 additions & 1 deletion modules/sdk-coin-icp/src/lib/iface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
export const MAX_INGRESS_TTL = 5 * 60 * 1000_000_000; // 5 minutes in nanoseconds
export const PERMITTED_DRIFT = 60 * 1000_000_000; // 60 seconds in nanoseconds
export const LEDGER_CANISTER_ID = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 2, 1, 1]); // Uint8Array value for "00000000000000020101" and the string value is "ryjl3-tyaaa-aaaaa-aaaba-cai"
export const TESTNET_LEDGER_CANISTER_ID = new Uint8Array([0, 0, 0, 0, 1, 0, 130, 251, 1, 1]); // Uint8Array value for "00000000010082fb0101" and the string value is "xafvr-biaaa-aaaai-aql5q-cai"
export const ROOT_PATH = 'm/0';
export const ACCOUNT_BALANCE_CALL = 'icrc1_balance_of';
export const PUBLIC_NODE_REQUEST_ENDPOINT = '/api/v3/canister/';
Expand Down Expand Up @@ -36,7 +37,11 @@ export enum MethodName {
}

export enum Network {
ID = '00000000000000020101', // ICP does not have different network IDs for mainnet and testnet
ID = '00000000000000020101',
}

export enum TestNetwork {
ID = '00000000010082fb0101',
}

export interface IcpTransactionData {
Expand Down
5 changes: 4 additions & 1 deletion modules/sdk-coin-icp/src/lib/transferBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ export class TransferBuilder extends TransactionBuilder {
}
this.validateTransaction(this._transaction);
this.buildIcpTransactionData();
const unsignedTransactionBuilder = new UnsignedTransactionBuilder(this._transaction.icpTransaction);
const unsignedTransactionBuilder = new UnsignedTransactionBuilder(
this._transaction.icpTransaction,
this._coinConfig
);
const payloadsData = await unsignedTransactionBuilder.getUnsignedTransaction();
this._transaction.payloadsData = payloadsData;
return this._transaction;
Expand Down
11 changes: 9 additions & 2 deletions modules/sdk-coin-icp/src/lib/unsignedTransactionBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,18 @@ import {
MAX_INGRESS_TTL,
PERMITTED_DRIFT,
LEDGER_CANISTER_ID,
TESTNET_LEDGER_CANISTER_ID,
} from './iface';
import utils from './utils';
import { NetworkType, BaseCoin as StaticsBaseCoin } from '@bitgo/statics';

export class UnsignedTransactionBuilder {
private _icpTransactionPayload: IcpTransaction;
constructor(icpTransactionPayload: IcpTransaction) {
private readonly _staticsCoin: Readonly<StaticsBaseCoin>;

constructor(icpTransactionPayload: IcpTransaction, staticsCoin: Readonly<StaticsBaseCoin>) {
this._icpTransactionPayload = icpTransactionPayload;
this._staticsCoin = staticsCoin;
}

async getUnsignedTransaction(): Promise<PayloadsData> {
Expand Down Expand Up @@ -104,7 +109,9 @@ export class UnsignedTransactionBuilder {
async getUpdate(sendArgs: SendArgs, publicKeyHex: string): Promise<HttpCanisterUpdate> {
const principalId = utils.getPrincipalIdFromPublicKey(publicKeyHex).toUint8Array();
const senderBlob = Buffer.from(principalId);
const canisterIdBuffer = Buffer.from(LEDGER_CANISTER_ID);
const ledgerCanisterId =
this._staticsCoin.network.type === NetworkType.TESTNET ? TESTNET_LEDGER_CANISTER_ID : LEDGER_CANISTER_ID;
const canisterIdBuffer = Buffer.from(ledgerCanisterId);
const args = await utils.toArg(sendArgs);
const update: HttpCanisterUpdate = {
canister_id: canisterIdBuffer,
Expand Down
20 changes: 10 additions & 10 deletions modules/sdk-coin-icp/test/resources/icp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,35 +192,35 @@ export const PayloadsData = {
payloads: [
{
account_identifier: { address: '0af815da8259ba8bb3d34fbfb2ac730f07a1adc81438d40d667d91b408b25f2f' },
hex_bytes: '0a69632d72657175657374523de3c7c5b4613155b74ede2e54493f6acbe8bf6d910154fbbb3a98ba3e0098',
hex_bytes: '0a69632d726571756573745f47cbcfe8333d5bf3806a121a6d17b0a71f895f311664cb476a18b166a0e867',
signature_type: 'ecdsa',
},
],
unsigned_transaction:
'b90002677570646174657381826b5452414e53414354494f4eb900056b63616e69737465725f69644a000000000000000201016b6d6574686f645f6e616d656773656e645f70626361726758400a0308d20912040a02080a1a0308904e2a220a20c3d30f404955975adaba89f2e1ebc75c1f44a6a204578afce8f3780d64fe252e3a0a0880a48596eb92b599186673656e646572581dd5fc1dc4d74d4aa35d81cf345533d20548113412d32fffdcece2f68a026e696e67726573735f6578706972791b000000000000000070696e67726573735f6578706972696573811b1832d4ce93deb200',
'b90002677570646174657381826b5452414e53414354494f4eb900056b63616e69737465725f69644a00000000010082fb01016b6d6574686f645f6e616d656773656e645f70626361726758400a0308d20912040a02080a1a0308904e2a220a20c3d30f404955975adaba89f2e1ebc75c1f44a6a204578afce8f3780d64fe252e3a0a0880a48596eb92b599186673656e646572581dd5fc1dc4d74d4aa35d81cf345533d20548113412d32fffdcece2f68a026e696e67726573735f6578706972791b000000000000000070696e67726573735f6578706972696573811b1832d4ce93deb200',
};

export const OnChainTransactionHash = '87f2e7ca80961bdc3a1fe761553a8a7f8ac5bf28b71f4e1fba807cf352a27f52';

export const PayloadsDataWithDefaultMemo = {
payloads: [
{
hex_bytes: '0a69632d726571756573747c1aff6d0edea47545315bb0be0230b5908e94aa5fcb8040e0680f30da5d4359',
hex_bytes: '0a69632d726571756573746a1eaf27e1b00fafe135ba095d0a1f9cdbd91d36babb7d3e5884a773e516843d',
account_identifier: {
address: '0af815da8259ba8bb3d34fbfb2ac730f07a1adc81438d40d667d91b408b25f2f',
},
signature_type: 'ecdsa',
},
],
unsigned_transaction:
'b90002677570646174657381826b5452414e53414354494f4eb900056b63616e69737465725f69644a000000000000000201016b6d6574686f645f6e616d656773656e645f706263617267583f0a02080012040a02080a1a0308904e2a220a20c3d30f404955975adaba89f2e1ebc75c1f44a6a204578afce8f3780d64fe252e3a0a0880a48596eb92b599186673656e646572581dd5fc1dc4d74d4aa35d81cf345533d20548113412d32fffdcece2f68a026e696e67726573735f6578706972791b000000000000000070696e67726573735f6578706972696573811b1832d4ce93deb200',
'b90002677570646174657381826b5452414e53414354494f4eb900056b63616e69737465725f69644a00000000010082fb01016b6d6574686f645f6e616d656773656e645f706263617267583f0a02080012040a02080a1a0308904e2a220a20c3d30f404955975adaba89f2e1ebc75c1f44a6a204578afce8f3780d64fe252e3a0a0880a48596eb92b599186673656e646572581dd5fc1dc4d74d4aa35d81cf345533d20548113412d32fffdcece2f68a026e696e67726573735f6578706972791b000000000000000070696e67726573735f6578706972696573811b1832d4ce93deb200',
};

export const Signatures = [
{
signing_payload: {
account_identifier: { address: '0af815da8259ba8bb3d34fbfb2ac730f07a1adc81438d40d667d91b408b25f2f' },
hex_bytes: '0a69632d72657175657374523de3c7c5b4613155b74ede2e54493f6acbe8bf6d910154fbbb3a98ba3e0098',
hex_bytes: '0a69632d726571756573745f47cbcfe8333d5bf3806a121a6d17b0a71f895f311664cb476a18b166a0e867',
signature_type: 'ecdsa',
},
signature_type: 'ecdsa',
Expand All @@ -230,7 +230,7 @@ export const Signatures = [
curve_type: 'secp256k1',
},
hex_bytes:
'dee0c728fc06d2140ad84e2be5f983626114d49f51216d4070bfccbfba79041d77648bad917428a8adb9908828458488562f0d159571382b1ac50fb81d5165c9',
'f2b4cd71e3399e3859fd89f675a0cb6a6a4227fb5cf089e88b627c1168f8ef430d9bb49deed0c30f36b3032d917912d5fcbbb67b05b9a4af743c83b151b15a3b',
},
];

Expand All @@ -240,7 +240,7 @@ export const SignaturesWithDefaultMemo = [
account_identifier: {
address: '0af815da8259ba8bb3d34fbfb2ac730f07a1adc81438d40d667d91b408b25f2f',
},
hex_bytes: '0a69632d726571756573747c1aff6d0edea47545315bb0be0230b5908e94aa5fcb8040e0680f30da5d4359',
hex_bytes: '0a69632d726571756573746a1eaf27e1b00fafe135ba095d0a1f9cdbd91d36babb7d3e5884a773e516843d',
signature_type: 'ecdsa',
},
signature_type: 'ecdsa',
Expand All @@ -250,15 +250,15 @@ export const SignaturesWithDefaultMemo = [
curve_type: 'secp256k1',
},
hex_bytes:
'32f3f90cbf76f81a4ffcba7819dad2b483afe1515d87711475d4af2e993a444b7f22ef303273d40fc18c7b4ffa3295c5cb58886a9e8cf252cedd1cdb8be5a399',
'fb5346def1d12b2cc246ff807447b95b4202af7f430f24d9de14ad7035b92c1621bef73f82221e00df12552958f27736e73f550e6aa5768dfac931945ff2d41a',
},
];

export const SignedTransaction =
'b9000367636f6e74656e74b900066c726571756573745f747970656463616c6c6b63616e69737465725f69644a000000000000000201016b6d6574686f645f6e616d656773656e645f70626361726758400a0308d20912040a02080a1a0308904e2a220a20c3d30f404955975adaba89f2e1ebc75c1f44a6a204578afce8f3780d64fe252e3a0a0880a48596eb92b599186673656e646572581dd5fc1dc4d74d4aa35d81cf345533d20548113412d32fffdcece2f68a026e696e67726573735f6578706972791b1832d4ce93deb2006d73656e6465725f7075626b6579d84058583056301006072a8648ce3d020106052b8104000a034200042ab77b959e28c4fa47fa8fb9e57cec3d66df5684d076ac2e4c5f28fd69a23dd31a59f908c8add51eab3530b4ac5d015166eaf2198c52fa9a8df7cfaeb8fdb7d46a73656e6465725f7369675840dee0c728fc06d2140ad84e2be5f983626114d49f51216d4070bfccbfba79041d77648bad917428a8adb9908828458488562f0d159571382b1ac50fb81d5165c9';
'b9000367636f6e74656e74b900066c726571756573745f747970656463616c6c6b63616e69737465725f69644a00000000010082fb01016b6d6574686f645f6e616d656773656e645f70626361726758400a0308d20912040a02080a1a0308904e2a220a20c3d30f404955975adaba89f2e1ebc75c1f44a6a204578afce8f3780d64fe252e3a0a0880a48596eb92b599186673656e646572581dd5fc1dc4d74d4aa35d81cf345533d20548113412d32fffdcece2f68a026e696e67726573735f6578706972791b1832d4ce93deb2006d73656e6465725f7075626b6579d84058583056301006072a8648ce3d020106052b8104000a034200042ab77b959e28c4fa47fa8fb9e57cec3d66df5684d076ac2e4c5f28fd69a23dd31a59f908c8add51eab3530b4ac5d015166eaf2198c52fa9a8df7cfaeb8fdb7d46a73656e6465725f7369675840f2b4cd71e3399e3859fd89f675a0cb6a6a4227fb5cf089e88b627c1168f8ef430d9bb49deed0c30f36b3032d917912d5fcbbb67b05b9a4af743c83b151b15a3b';

export const SignedTransactionWithDefaultMemo =
'b9000367636f6e74656e74b900066c726571756573745f747970656463616c6c6b63616e69737465725f69644a000000000000000201016b6d6574686f645f6e616d656773656e645f706263617267583f0a02080012040a02080a1a0308904e2a220a20c3d30f404955975adaba89f2e1ebc75c1f44a6a204578afce8f3780d64fe252e3a0a0880a48596eb92b599186673656e646572581dd5fc1dc4d74d4aa35d81cf345533d20548113412d32fffdcece2f68a026e696e67726573735f6578706972791b1832d4ce93deb2006d73656e6465725f7075626b6579d84058583056301006072a8648ce3d020106052b8104000a034200042ab77b959e28c4fa47fa8fb9e57cec3d66df5684d076ac2e4c5f28fd69a23dd31a59f908c8add51eab3530b4ac5d015166eaf2198c52fa9a8df7cfaeb8fdb7d46a73656e6465725f736967584032f3f90cbf76f81a4ffcba7819dad2b483afe1515d87711475d4af2e993a444b7f22ef303273d40fc18c7b4ffa3295c5cb58886a9e8cf252cedd1cdb8be5a399';
'b9000367636f6e74656e74b900066c726571756573745f747970656463616c6c6b63616e69737465725f69644a00000000010082fb01016b6d6574686f645f6e616d656773656e645f706263617267583f0a02080012040a02080a1a0308904e2a220a20c3d30f404955975adaba89f2e1ebc75c1f44a6a204578afce8f3780d64fe252e3a0a0880a48596eb92b599186673656e646572581dd5fc1dc4d74d4aa35d81cf345533d20548113412d32fffdcece2f68a026e696e67726573735f6578706972791b1832d4ce93deb2006d73656e6465725f7075626b6579d84058583056301006072a8648ce3d020106052b8104000a034200042ab77b959e28c4fa47fa8fb9e57cec3d66df5684d076ac2e4c5f28fd69a23dd31a59f908c8add51eab3530b4ac5d015166eaf2198c52fa9a8df7cfaeb8fdb7d46a73656e6465725f7369675840fb5346def1d12b2cc246ff807447b95b4202af7f430f24d9de14ad7035b92c1621bef73f82221e00df12552958f27736e73f550e6aa5768dfac931945ff2d41a';

export const ParsedUnsignedTransaction = {
operations: [
Expand Down
6 changes: 3 additions & 3 deletions modules/sdk-coin-icp/test/unit/icp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@ import should from 'should';
nock.enableNetConnect();

const bitgo: TestBitGoAPI = TestBitGo.decorate(BitGoAPI, { env: 'test' });
bitgo.safeRegister('ticp', Ticp.createInstance);
bitgo.safeRegister('icp', Icp.createInstance);

describe('Internet computer', function () {
let bitgo;
let basecoin;
const factory = getBuilderFactory('ticp');
const factory = getBuilderFactory('icp');
let txBuilder: any;

before(async function () {
bitgo = TestBitGo.decorate(BitGoAPI, { env: 'test' });
bitgo.safeRegister('icp', Icp.createInstance);
bitgo.safeRegister('ticp', Ticp.createInstance);
bitgo.initializeTestVars();
basecoin = bitgo.coin('ticp');
basecoin = bitgo.coin('icp');

txBuilder = factory.getTransferBuilder();
txBuilder.sender(testData.Accounts.account1.address, testData.Accounts.account1.publicKey);
Expand Down
2 changes: 1 addition & 1 deletion modules/sdk-core/src/bitgo/environments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ const testnetBase: EnvironmentTemplate = {
flrExplorerBaseUrl: 'https://coston2-explorer.flare.network',
xdcExplorerBaseUrl: 'https://api.etherscan.io/v2',
sgbExplorerBaseUrl: 'https://coston-explorer.flare.network',
icpNodeUrl: 'https://exchanges.testnet.dfinity.network',
icpNodeUrl: 'https://ic0.app',
monExplorerBaseUrl: 'https://api.etherscan.io/v2',
worldExplorerBaseUrl: 'https://sepolia.worldscan.org/',
somniaExplorerBaseUrl: 'https://shannon-explorer.somnia.network/',
Expand Down