diff --git a/modules/sdk-coin-zketh/package.json b/modules/sdk-coin-zketh/package.json index cabe983e9e..f43281cbca 100644 --- a/modules/sdk-coin-zketh/package.json +++ b/modules/sdk-coin-zketh/package.json @@ -43,10 +43,14 @@ "@bitgo/abstract-eth": "^11.0.0", "@bitgo/sdk-core": "^18.0.0", "@bitgo/statics": "^39.0.0", - "@ethereumjs/common": "^2.6.5" + "@ethereumjs/common": "^2.6.5", + "superagent": "^3.8.3", + "@bitgo/sjcl": "^1.0.1", + "@bitgo/utxo-lib": "^9.16.0" }, "devDependencies": { "@bitgo/sdk-api": "^1.34.0", - "@bitgo/sdk-test": "^1.2.53" + "@bitgo/sdk-test": "^1.2.53", + "secp256k1": "5.0.0" } } diff --git a/modules/sdk-coin-zketh/src/lib/resources.ts b/modules/sdk-coin-zketh/src/lib/resources.ts index f290b0f3c6..baf2cb6a8c 100644 --- a/modules/sdk-coin-zketh/src/lib/resources.ts +++ b/modules/sdk-coin-zketh/src/lib/resources.ts @@ -9,6 +9,7 @@ export const testnetCommon = EthereumCommon.custom( }, { baseChain: 'sepolia', + hardfork: 'london', } ); @@ -20,5 +21,6 @@ export const mainnetCommon = EthereumCommon.custom( }, { baseChain: 'mainnet', + hardfork: 'london', } ); diff --git a/modules/sdk-coin-zketh/src/register.ts b/modules/sdk-coin-zketh/src/register.ts index 0abc34d986..9466a8ba1b 100644 --- a/modules/sdk-coin-zketh/src/register.ts +++ b/modules/sdk-coin-zketh/src/register.ts @@ -1,8 +1,12 @@ import { BitGoBase } from '@bitgo/sdk-core'; import { Zketh } from './zketh'; import { Tzketh } from './tzketh'; +import { ZkethToken } from './zkethToken'; export const register = (sdk: BitGoBase): void => { sdk.register('zketh', Zketh.createInstance); sdk.register('tzketh', Tzketh.createInstance); + ZkethToken.createTokenConstructors().forEach(({ name, coinConstructor }) => { + sdk.register(name, coinConstructor); + }); }; diff --git a/modules/sdk-coin-zketh/src/zketh.ts b/modules/sdk-coin-zketh/src/zketh.ts index f7a4c66e82..0db92e70d7 100644 --- a/modules/sdk-coin-zketh/src/zketh.ts +++ b/modules/sdk-coin-zketh/src/zketh.ts @@ -1,7 +1,8 @@ /** * @prettier */ -import { BaseCoin, BitGoBase } from '@bitgo/sdk-core'; +import request from 'superagent'; +import { BaseCoin, BitGoBase, common } from '@bitgo/sdk-core'; import { BaseCoin as StaticsBaseCoin, coins } from '@bitgo/statics'; import { AbstractEthLikeNewCoins, TransactionBuilder as EthLikeTransactionBuilder } from '@bitgo/abstract-eth'; import { TransactionBuilder } from './lib'; @@ -18,4 +19,28 @@ export class Zketh extends AbstractEthLikeNewCoins { protected getTransactionBuilder(): EthLikeTransactionBuilder { return new TransactionBuilder(coins.get(this.getBaseChain())); } + + /** + * Make a query to zkSync explorer for information such as balance, token balance, solidity calls + * @param {Object} query key-value pairs of parameters to append after /api + * @returns {Promise} response from zkSync explorer + */ + async recoveryBlockchainExplorerQuery(query: Record): Promise> { + const token = common.Environments[this.bitgo.getEnv()].arbiscanApiToken; + if (token) { + query.apikey = token; + } + const response = await request + .get(common.Environments[this.bitgo.getEnv()].zksyncExplorerBaseUrl + '/api') + .query(query); + + if (!response.ok) { + throw new Error('could not reach zkSync explorer'); + } + + if (response.body.status === '0' && response.body.message === 'NOTOK') { + throw new Error('zkSync explorer rate limit reached'); + } + return response.body; + } } diff --git a/modules/sdk-coin-zketh/test/fixtures/zketh.ts b/modules/sdk-coin-zketh/test/fixtures/zketh.ts new file mode 100644 index 0000000000..47fd0f29f1 --- /dev/null +++ b/modules/sdk-coin-zketh/test/fixtures/zketh.ts @@ -0,0 +1,51 @@ +export function getTxListRequest(address: string) { + return { + module: 'account', + action: 'txlist', + address: address, + }; +} + +export const getTxListResponse = { + status: '0', + message: 'No transactions found', + result: [], +}; + +export function getBalanceRequest(address: string) { + return { + module: 'account', + action: 'balance', + address: address, + }; +} + +export function getTokenBalanceRequest(tokenContractAddress: string, address: string) { + return { + module: 'account', + action: 'tokenbalance', + contractaddress: tokenContractAddress, + address: address, + tag: 'latest', + }; +} + +export const getBalanceResponse = { + status: '1', + message: 'OK', + result: '9999999999999999928', +}; + +export const getContractCallRequest = { + module: 'proxy', + action: 'eth_call', + to: '0xdf07117705a9f8dc4c2a78de66b7f1797dba9d4e', + data: 'a0b7967b', + tag: 'latest', +}; + +export const getContractCallResponse = { + jsonrpc: '2.0', + result: '0x0000000000000000000000000000000000000000000000000000000000002a7f', + id: 1, +}; diff --git a/modules/sdk-coin-zketh/test/getBuilder.ts b/modules/sdk-coin-zketh/test/getBuilder.ts new file mode 100644 index 0000000000..5077f98885 --- /dev/null +++ b/modules/sdk-coin-zketh/test/getBuilder.ts @@ -0,0 +1,7 @@ +import { BaseBuilder } from '@bitgo/sdk-core'; +import { coins } from '@bitgo/statics'; +import { TransactionBuilder } from '../src'; + +export function getBuilder(coinName: string): BaseBuilder { + return new TransactionBuilder(coins.get(coinName)); +} diff --git a/modules/sdk-coin-zketh/test/resources.ts b/modules/sdk-coin-zketh/test/resources.ts new file mode 100644 index 0000000000..f6c0c2314d --- /dev/null +++ b/modules/sdk-coin-zketh/test/resources.ts @@ -0,0 +1,37 @@ +import { ETHTransactionType, KeyPair, LegacyTxData } from '@bitgo/abstract-eth'; + +export const ENCODED_TRANSACTION = + '0xf91661010a822ee09419645032c7f1533395d44a629462e751084d3e4c8204d2b915fb60606040526000600160006101000a81548160ff021916908315150217905550341561002a57600080fd5b60405161155b38038061155b833981016040528080518201919050506003815114151561005657600080fd5b806000908051906020019061006c929190610073565b5050610140565b8280548282559060005260206000209081019282156100ec579160200282015b828111156100eb5782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555091602001919060010190610093565b5b5090506100f991906100fd565b5090565b61013d91905b8082111561013957600081816101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905550600101610103565b5090565b90565b61140c8061014f6000396000f300606060405260043610610099576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630dcd7a6c146101335780632079fb9a146101e95780632da034091461024c57806339125215146102a45780637df73e271461037e578063a0b7967b146103cf578063a68a76cc146103f8578063abe3219c1461044d578063fc0f392d1461047a575b6000341115610131577f6e89d517057028190560dd200cf6bf792842861353d1173761dfa362e1c133f03334600036604051808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200184815260200180602001828103825284848281815260200192508082843782019150509550505050505060405180910390a15b005b341561013e57600080fd5b6101e7600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190803590602001909190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509190505061048f565b005b34156101f457600080fd5b61020a6004808035906020019091905050610668565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561025757600080fd5b6102a2600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506106a7565b005b34156102af57600080fd5b61037c600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509190803590602001909190803590602001909190803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091905050610773565b005b341561038957600080fd5b6103b5600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610a72565b604051808215151515815260200191505060405180910390f35b34156103da57600080fd5b6103e2610b16565b6040518082815260200191505060405180910390f35b341561040357600080fd5b61040b610b70565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561045857600080fd5b610460610b95565b604051808215151515815260200191505060405180910390f35b341561048557600080fd5b61048d610ba8565b005b60008061049b33610a72565b15156104a657600080fd5b878787878760405180807f45524332300000000000000000000000000000000000000000000000000000008152506005018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018581526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140183815260200182815260200195505050505050604051809103902091506105898883858888610c3b565b508590508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb89896000604051602001526040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b151561063857600080fd5b6102c65a03f1151561064957600080fd5b50505060405180519050151561065e57600080fd5b5050505050505050565b60008181548110151561067757fe5b90600052602060002090016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006106b233610a72565b15156106bd57600080fd5b8290508073ffffffffffffffffffffffffffffffffffffffff16633ef13367836040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b151561075a57600080fd5b6102c65a03f1151561076b57600080fd5b505050505050565b60008061077f33610a72565b151561078a57600080fd5b878787878760405180807f45544845520000000000000000000000000000000000000000000000000000008152506005018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140185815260200184805190602001908083835b602083101515610833578051825260208201915060208101905060208303925061080e565b6001836020036101000a038019825116818451168082178552505050505050905001838152602001828152602001955050505050506040518091039020915061087f8883858888610c3b565b90508773ffffffffffffffffffffffffffffffffffffffff16878760405180828051906020019080838360005b838110156108c75780820151818401526020810190506108ac565b50505050905090810190601f1680156108f45780820380516001836020036101000a031916815260200191505b5091505060006040518083038185876187965a03f192505050151561091857600080fd5b7f59bed9ab5d78073465dd642a9e3e76dfdb7d53bcae9d09df7d0b8f5234d5a8063382848b8b8b604051808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200185600019166000191681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610a29578082015181840152602081019050610a0e565b50505050905090810190601f168015610a565780820380516001836020036101000a031916815260200191505b5097505050505050505060405180910390a15050505050505050565b600080600090505b600080549050811015610b0b578273ffffffffffffffffffffffffffffffffffffffff16600082815481101515610aad57fe5b906000526020600020900160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610afe5760019150610b10565b8080600101915050610a7a565b600091505b50919050565b6000806000809150600090505b600a811015610b655781600282600a81101515610b3c57fe5b01541115610b5857600281600a81101515610b5357fe5b015491505b8080600101915050610b23565b600182019250505090565b6000610b7a610e90565b604051809103906000f0801515610b9057600080fd5b905090565b600160009054906101000a900460ff1681565b610bb133610a72565b1515610bbc57600080fd5b60018060006101000a81548160ff0219169083151502179055507f0909e8f76a4fd3e970f2eaef56c0ee6dfaf8b87c5b8d3f56ffce78e825a9115733604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1565b600080610c488686610ce6565b9050600160009054906101000a900460ff168015610c6c5750610c6a87610a72565b155b15610c7657600080fd5b42841015610c8357600080fd5b610c8c83610db9565b610c9581610a72565b1515610ca057600080fd5b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610cd957600080fd5b8091505095945050505050565b60008060008060418551141515610cfc57600080fd5b602085015192506040850151915060ff6041860151169050601b8160ff161015610d2757601b810190505b600186828585604051600081526020016040526000604051602001526040518085600019166000191681526020018460ff1660ff16815260200183600019166000191681526020018260001916600019168152602001945050505050602060405160208103908084039060008661646e5a03f11515610da557600080fd5b505060206040510351935050505092915050565b600080610dc533610a72565b1515610dd057600080fd5b60009150600090505b600a811015610e385782600282600a81101515610df257fe5b01541415610dff57600080fd5b600282600a81101515610e0e57fe5b0154600282600a81101515610e1f57fe5b01541015610e2b578091505b8080600101915050610dd9565b600282600a81101515610e4757fe5b0154831015610e5557600080fd5b612710600283600a81101515610e6757fe5b015401831115610e7657600080fd5b82600283600a81101515610e8657fe5b0181905550505050565b60405161054080610ea18339019056006060604052341561000f57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506104e28061005e6000396000f300606060405260043610610056576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168062821de3146101475780633ef133671461019c5780636b9f96ea146101d5575b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f1935050505015156100b757600080fd5b7f69b31548dea9b3b707b4dff357d326e3e9348b24e7a6080a218a6edeeec48f9b3334600036604051808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200184815260200180602001828103825284848281815260200192508082843782019150509550505050505060405180910390a1005b341561015257600080fd5b61015a6101ea565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101a757600080fd5b6101d3600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061020f565b005b34156101e057600080fd5b6101e861043c565b005b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561026f57600080fd5b8392503091508273ffffffffffffffffffffffffffffffffffffffff166370a08231836000604051602001526040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b151561031857600080fd5b6102c65a03f1151561032957600080fd5b505050604051805190509050600081141561034357610436565b8273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836000604051602001526040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b151561040f57600080fd5b6102c65a03f1151561042057600080fd5b50505060405180519050151561043557600080fd5b5b50505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f1935050505015156104b457600080fd5b5600a165627a7a72305820088cce905e424bfe474510efe41761893e9e34b54b885b8fee546d8be88aee3c0029a165627a7a72305820827adc3ef3a179757bc33003e41070fbbfcdfc5db31275af3cb0395155cd3bbb0029000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000030000000000000000000000008775ed5a9f67f90a017afb46980bfdae423dd41c00000000000000000000000042ff8ce0f79b69993893cef89412a4c48b7d29af0000000000000000000000007ae2ccba98e20daa6f6271cdf97a79c0274856f7830cde00a041fe10c137393d71dbcbca45d53bf2499f5270f1d68f1d2d397a036de878aca5a00a54dd576225125b7a4c3ab2d885d5657b32e73d48ae1679f8255b754b97d575'; + +export const TXDATA: LegacyTxData = { + _type: ETHTransactionType.LEGACY, + nonce: 1, + data: '0x60606040526000600160006101000a81548160ff021916908315150217905550341561002a57600080fd5b60405161155b38038061155b833981016040528080518201919050506003815114151561005657600080fd5b806000908051906020019061006c929190610073565b5050610140565b8280548282559060005260206000209081019282156100ec579160200282015b828111156100eb5782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555091602001919060010190610093565b5b5090506100f991906100fd565b5090565b61013d91905b8082111561013957600081816101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905550600101610103565b5090565b90565b61140c8061014f6000396000f300606060405260043610610099576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630dcd7a6c146101335780632079fb9a146101e95780632da034091461024c57806339125215146102a45780637df73e271461037e578063a0b7967b146103cf578063a68a76cc146103f8578063abe3219c1461044d578063fc0f392d1461047a575b6000341115610131577f6e89d517057028190560dd200cf6bf792842861353d1173761dfa362e1c133f03334600036604051808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200184815260200180602001828103825284848281815260200192508082843782019150509550505050505060405180910390a15b005b341561013e57600080fd5b6101e7600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190803590602001909190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509190505061048f565b005b34156101f457600080fd5b61020a6004808035906020019091905050610668565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561025757600080fd5b6102a2600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506106a7565b005b34156102af57600080fd5b61037c600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509190803590602001909190803590602001909190803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091905050610773565b005b341561038957600080fd5b6103b5600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610a72565b604051808215151515815260200191505060405180910390f35b34156103da57600080fd5b6103e2610b16565b6040518082815260200191505060405180910390f35b341561040357600080fd5b61040b610b70565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561045857600080fd5b610460610b95565b604051808215151515815260200191505060405180910390f35b341561048557600080fd5b61048d610ba8565b005b60008061049b33610a72565b15156104a657600080fd5b878787878760405180807f45524332300000000000000000000000000000000000000000000000000000008152506005018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018581526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140183815260200182815260200195505050505050604051809103902091506105898883858888610c3b565b508590508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb89896000604051602001526040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b151561063857600080fd5b6102c65a03f1151561064957600080fd5b50505060405180519050151561065e57600080fd5b5050505050505050565b60008181548110151561067757fe5b90600052602060002090016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006106b233610a72565b15156106bd57600080fd5b8290508073ffffffffffffffffffffffffffffffffffffffff16633ef13367836040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b151561075a57600080fd5b6102c65a03f1151561076b57600080fd5b505050505050565b60008061077f33610a72565b151561078a57600080fd5b878787878760405180807f45544845520000000000000000000000000000000000000000000000000000008152506005018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140185815260200184805190602001908083835b602083101515610833578051825260208201915060208101905060208303925061080e565b6001836020036101000a038019825116818451168082178552505050505050905001838152602001828152602001955050505050506040518091039020915061087f8883858888610c3b565b90508773ffffffffffffffffffffffffffffffffffffffff16878760405180828051906020019080838360005b838110156108c75780820151818401526020810190506108ac565b50505050905090810190601f1680156108f45780820380516001836020036101000a031916815260200191505b5091505060006040518083038185876187965a03f192505050151561091857600080fd5b7f59bed9ab5d78073465dd642a9e3e76dfdb7d53bcae9d09df7d0b8f5234d5a8063382848b8b8b604051808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200185600019166000191681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610a29578082015181840152602081019050610a0e565b50505050905090810190601f168015610a565780820380516001836020036101000a031916815260200191505b5097505050505050505060405180910390a15050505050505050565b600080600090505b600080549050811015610b0b578273ffffffffffffffffffffffffffffffffffffffff16600082815481101515610aad57fe5b906000526020600020900160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610afe5760019150610b10565b8080600101915050610a7a565b600091505b50919050565b6000806000809150600090505b600a811015610b655781600282600a81101515610b3c57fe5b01541115610b5857600281600a81101515610b5357fe5b015491505b8080600101915050610b23565b600182019250505090565b6000610b7a610e90565b604051809103906000f0801515610b9057600080fd5b905090565b600160009054906101000a900460ff1681565b610bb133610a72565b1515610bbc57600080fd5b60018060006101000a81548160ff0219169083151502179055507f0909e8f76a4fd3e970f2eaef56c0ee6dfaf8b87c5b8d3f56ffce78e825a9115733604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1565b600080610c488686610ce6565b9050600160009054906101000a900460ff168015610c6c5750610c6a87610a72565b155b15610c7657600080fd5b42841015610c8357600080fd5b610c8c83610db9565b610c9581610a72565b1515610ca057600080fd5b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610cd957600080fd5b8091505095945050505050565b60008060008060418551141515610cfc57600080fd5b602085015192506040850151915060ff6041860151169050601b8160ff161015610d2757601b810190505b600186828585604051600081526020016040526000604051602001526040518085600019166000191681526020018460ff1660ff16815260200183600019166000191681526020018260001916600019168152602001945050505050602060405160208103908084039060008661646e5a03f11515610da557600080fd5b505060206040510351935050505092915050565b600080610dc533610a72565b1515610dd057600080fd5b60009150600090505b600a811015610e385782600282600a81101515610df257fe5b01541415610dff57600080fd5b600282600a81101515610e0e57fe5b0154600282600a81101515610e1f57fe5b01541015610e2b578091505b8080600101915050610dd9565b600282600a81101515610e4757fe5b0154831015610e5557600080fd5b612710600283600a81101515610e6757fe5b015401831115610e7657600080fd5b82600283600a81101515610e8657fe5b0181905550505050565b60405161054080610ea18339019056006060604052341561000f57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506104e28061005e6000396000f300606060405260043610610056576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168062821de3146101475780633ef133671461019c5780636b9f96ea146101d5575b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f1935050505015156100b757600080fd5b7f69b31548dea9b3b707b4dff357d326e3e9348b24e7a6080a218a6edeeec48f9b3334600036604051808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200184815260200180602001828103825284848281815260200192508082843782019150509550505050505060405180910390a1005b341561015257600080fd5b61015a6101ea565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101a757600080fd5b6101d3600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061020f565b005b34156101e057600080fd5b6101e861043c565b005b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561026f57600080fd5b8392503091508273ffffffffffffffffffffffffffffffffffffffff166370a08231836000604051602001526040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b151561031857600080fd5b6102c65a03f1151561032957600080fd5b505050604051805190509050600081141561034357610436565b8273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836000604051602001526040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b151561040f57600080fd5b6102c65a03f1151561042057600080fd5b50505060405180519050151561043557600080fd5b5b50505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f1935050505015156104b457600080fd5b5600a165627a7a72305820088cce905e424bfe474510efe41761893e9e34b54b885b8fee546d8be88aee3c0029a165627a7a72305820827adc3ef3a179757bc33003e41070fbbfcdfc5db31275af3cb0395155cd3bbb0029000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000030000000000000000000000008775ed5a9f67f90a017afb46980bfdae423dd41c00000000000000000000000042ff8ce0f79b69993893cef89412a4c48b7d29af0000000000000000000000007ae2ccba98e20daa6f6271cdf97a79c0274856f7', + gasLimit: '12000', + gasPrice: '10', + chainId: '0x66eee', + value: '1234', + to: '0x19645032c7f1533395d44a629462e751084d3e4c', + id: '0x4181c0469703d3d58bae42e50c1c0c063531f2ce6c9109b838ea28e2f7249727', +}; + +export const UNSIGNED_TX = + '0xf9161e010a822ee09419645032c7f1533395d44a629462e751084d3e4c8204d2b915fb60606040526000600160006101000a81548160ff021916908315150217905550341561002a57600080fd5b60405161155b38038061155b833981016040528080518201919050506003815114151561005657600080fd5b806000908051906020019061006c929190610073565b5050610140565b8280548282559060005260206000209081019282156100ec579160200282015b828111156100eb5782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555091602001919060010190610093565b5b5090506100f991906100fd565b5090565b61013d91905b8082111561013957600081816101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905550600101610103565b5090565b90565b61140c8061014f6000396000f300606060405260043610610099576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630dcd7a6c146101335780632079fb9a146101e95780632da034091461024c57806339125215146102a45780637df73e271461037e578063a0b7967b146103cf578063a68a76cc146103f8578063abe3219c1461044d578063fc0f392d1461047a575b6000341115610131577f6e89d517057028190560dd200cf6bf792842861353d1173761dfa362e1c133f03334600036604051808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200184815260200180602001828103825284848281815260200192508082843782019150509550505050505060405180910390a15b005b341561013e57600080fd5b6101e7600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190803590602001909190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509190505061048f565b005b34156101f457600080fd5b61020a6004808035906020019091905050610668565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561025757600080fd5b6102a2600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506106a7565b005b34156102af57600080fd5b61037c600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509190803590602001909190803590602001909190803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091905050610773565b005b341561038957600080fd5b6103b5600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610a72565b604051808215151515815260200191505060405180910390f35b34156103da57600080fd5b6103e2610b16565b6040518082815260200191505060405180910390f35b341561040357600080fd5b61040b610b70565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561045857600080fd5b610460610b95565b604051808215151515815260200191505060405180910390f35b341561048557600080fd5b61048d610ba8565b005b60008061049b33610a72565b15156104a657600080fd5b878787878760405180807f45524332300000000000000000000000000000000000000000000000000000008152506005018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018581526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140183815260200182815260200195505050505050604051809103902091506105898883858888610c3b565b508590508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb89896000604051602001526040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b151561063857600080fd5b6102c65a03f1151561064957600080fd5b50505060405180519050151561065e57600080fd5b5050505050505050565b60008181548110151561067757fe5b90600052602060002090016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006106b233610a72565b15156106bd57600080fd5b8290508073ffffffffffffffffffffffffffffffffffffffff16633ef13367836040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b151561075a57600080fd5b6102c65a03f1151561076b57600080fd5b505050505050565b60008061077f33610a72565b151561078a57600080fd5b878787878760405180807f45544845520000000000000000000000000000000000000000000000000000008152506005018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140185815260200184805190602001908083835b602083101515610833578051825260208201915060208101905060208303925061080e565b6001836020036101000a038019825116818451168082178552505050505050905001838152602001828152602001955050505050506040518091039020915061087f8883858888610c3b565b90508773ffffffffffffffffffffffffffffffffffffffff16878760405180828051906020019080838360005b838110156108c75780820151818401526020810190506108ac565b50505050905090810190601f1680156108f45780820380516001836020036101000a031916815260200191505b5091505060006040518083038185876187965a03f192505050151561091857600080fd5b7f59bed9ab5d78073465dd642a9e3e76dfdb7d53bcae9d09df7d0b8f5234d5a8063382848b8b8b604051808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200185600019166000191681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610a29578082015181840152602081019050610a0e565b50505050905090810190601f168015610a565780820380516001836020036101000a031916815260200191505b5097505050505050505060405180910390a15050505050505050565b600080600090505b600080549050811015610b0b578273ffffffffffffffffffffffffffffffffffffffff16600082815481101515610aad57fe5b906000526020600020900160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610afe5760019150610b10565b8080600101915050610a7a565b600091505b50919050565b6000806000809150600090505b600a811015610b655781600282600a81101515610b3c57fe5b01541115610b5857600281600a81101515610b5357fe5b015491505b8080600101915050610b23565b600182019250505090565b6000610b7a610e90565b604051809103906000f0801515610b9057600080fd5b905090565b600160009054906101000a900460ff1681565b610bb133610a72565b1515610bbc57600080fd5b60018060006101000a81548160ff0219169083151502179055507f0909e8f76a4fd3e970f2eaef56c0ee6dfaf8b87c5b8d3f56ffce78e825a9115733604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1565b600080610c488686610ce6565b9050600160009054906101000a900460ff168015610c6c5750610c6a87610a72565b155b15610c7657600080fd5b42841015610c8357600080fd5b610c8c83610db9565b610c9581610a72565b1515610ca057600080fd5b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610cd957600080fd5b8091505095945050505050565b60008060008060418551141515610cfc57600080fd5b602085015192506040850151915060ff6041860151169050601b8160ff161015610d2757601b810190505b600186828585604051600081526020016040526000604051602001526040518085600019166000191681526020018460ff1660ff16815260200183600019166000191681526020018260001916600019168152602001945050505050602060405160208103908084039060008661646e5a03f11515610da557600080fd5b505060206040510351935050505092915050565b600080610dc533610a72565b1515610dd057600080fd5b60009150600090505b600a811015610e385782600282600a81101515610df257fe5b01541415610dff57600080fd5b600282600a81101515610e0e57fe5b0154600282600a81101515610e1f57fe5b01541015610e2b578091505b8080600101915050610dd9565b600282600a81101515610e4757fe5b0154831015610e5557600080fd5b612710600283600a81101515610e6757fe5b015401831115610e7657600080fd5b82600283600a81101515610e8657fe5b0181905550505050565b60405161054080610ea18339019056006060604052341561000f57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506104e28061005e6000396000f300606060405260043610610056576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168062821de3146101475780633ef133671461019c5780636b9f96ea146101d5575b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f1935050505015156100b757600080fd5b7f69b31548dea9b3b707b4dff357d326e3e9348b24e7a6080a218a6edeeec48f9b3334600036604051808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200184815260200180602001828103825284848281815260200192508082843782019150509550505050505060405180910390a1005b341561015257600080fd5b61015a6101ea565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101a757600080fd5b6101d3600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061020f565b005b34156101e057600080fd5b6101e861043c565b005b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561026f57600080fd5b8392503091508273ffffffffffffffffffffffffffffffffffffffff166370a08231836000604051602001526040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b151561031857600080fd5b6102c65a03f1151561032957600080fd5b505050604051805190509050600081141561034357610436565b8273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836000604051602001526040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b151561040f57600080fd5b6102c65a03f1151561042057600080fd5b50505060405180519050151561043557600080fd5b5b50505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f1935050505015156104b457600080fd5b5600a165627a7a72305820088cce905e424bfe474510efe41761893e9e34b54b885b8fee546d8be88aee3c0029a165627a7a72305820827adc3ef3a179757bc33003e41070fbbfcdfc5db31275af3cb0395155cd3bbb0029000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000030000000000000000000000008775ed5a9f67f90a017afb46980bfdae423dd41c00000000000000000000000042ff8ce0f79b69993893cef89412a4c48b7d29af0000000000000000000000007ae2ccba98e20daa6f6271cdf97a79c0274856f7808080'; + +export const ACCOUNT_1 = '0xe6c43626f11312de29b0011fa9da71ea3bba0e9f'; + +export const PRIVATE_KEY_1 = + 'xprv9s21ZrQH143K3vYxF8BfcG8g82bkkrf962jYfdc2SdsbXzLRcnaWAD3jWMsQaTz9ZoqD7gvYeR3fRPZy3Fr2UFXrome67sTdb66wAFmcz6G'; + +export const PUBLIC_KEY_1 = + 'xpub661MyMwAqRbcGQdRM9ifyQ5Qg4SFAKNzTFf9U21dzyQaQnfaAKtki1NDMeKs5XEH9WfUTCcApRVZdbmD7qwt4iCUYDr6qdnQas3WTx9REN4'; + +export const KEYPAIR_PRV = new KeyPair({ prv: PRIVATE_KEY_1 }); + +export const ACCOUNT_2 = '0x78caeb4527170e52f54d936e4eef6f83250e01bb'; + +export const PRIVATE_KEY_2 = + 'xprv9s21ZrQH143K33n6M4jpMgtiqbR9J5oDr2Hg7hYFTNy9cusMtuzoShP1we7wr2H4aVtHuQyTTGD99KVoQtrnEN6dqEG9VzJR5fL9sqikk1S'; + +export const PUBLIC_KEY_2 = + 'xpub661MyMwAqRbcFXrZT6GpipqTPdFdhYX5DFDGv5ws1iW8ViCWSTK3zVhVntpiKDjPqXrqP1hhQscJZhVpbmZt9qygxgPdmN9RAZVKqovPfLw'; diff --git a/modules/sdk-coin-zketh/test/unit/transaction.ts b/modules/sdk-coin-zketh/test/unit/transaction.ts new file mode 100644 index 0000000000..ce723a0a6a --- /dev/null +++ b/modules/sdk-coin-zketh/test/unit/transaction.ts @@ -0,0 +1,60 @@ +import should from 'should'; +import { coins } from '@bitgo/statics'; +import { Transaction } from '../../src'; +import { getCommon } from '../../src/lib/utils'; +import * as testData from '../resources'; + +describe('Zketh Transaction', () => { + const coinConfig = coins.get('tzketh'); + const common = getCommon(coinConfig.network.type); + + /** + * return a new transaction object + */ + function getTransaction(): Transaction { + return new Transaction(coinConfig, common); + } + + describe('should throw ', () => { + it('an empty transaction', () => { + const tx = getTransaction(); + should.throws(() => { + tx.toJson(); + }); + should.throws(() => { + tx.toBroadcastFormat(); + }); + }); + }); + + describe('should return', () => { + it('a valid transaction', () => { + const tx = getTransaction(); + tx.setTransactionData(testData.TXDATA); + should.deepEqual(tx.toJson(), testData.TXDATA); + should.equal(tx.toBroadcastFormat(), testData.UNSIGNED_TX); + }); + }); + + describe('should sign', () => { + it('invalid', () => { + const tx = getTransaction(); + return tx.sign(testData.KEYPAIR_PRV).should.be.rejected(); + }); + + it('valid', () => { + const tx = getTransaction(); + tx.setTransactionData(testData.TXDATA); + return tx.sign(testData.KEYPAIR_PRV).should.be.fulfilled(); + }); + }); + + describe('should return encoded tx', () => { + it('valid sign', async function () { + const tx = getTransaction(); + tx.setTransactionData(testData.TXDATA); + await tx.sign(testData.KEYPAIR_PRV); + should.equal(tx.toBroadcastFormat(), testData.ENCODED_TRANSACTION); + }); + }); +}); diff --git a/modules/sdk-coin-zketh/test/unit/zketh.ts b/modules/sdk-coin-zketh/test/unit/zketh.ts index 7660a390bd..8d75fbaede 100644 --- a/modules/sdk-coin-zketh/test/unit/zketh.ts +++ b/modules/sdk-coin-zketh/test/unit/zketh.ts @@ -1,19 +1,102 @@ -import 'should'; - +import * as should from 'should'; +import { bip32 } from '@bitgo/utxo-lib'; +import { common, FullySignedTransaction, TransactionType, Wallet } from '@bitgo/sdk-core'; +import * as secp256k1 from 'secp256k1'; +import nock from 'nock'; import { TestBitGo, TestBitGoAPI } from '@bitgo/sdk-test'; import { BitGoAPI } from '@bitgo/sdk-api'; +import { OfflineVaultTxInfo, optionalDeps, SignTransactionOptions } from '@bitgo/abstract-eth'; -import { Zketh, Tzketh } from '../../src/index'; +import { Zketh, Tzketh, TransactionBuilder, TransferBuilder } from '../../src'; +import * as mockData from '../fixtures/zketh'; +import { getBuilder } from '../getBuilder'; -const bitgo: TestBitGoAPI = TestBitGo.decorate(BitGoAPI, { env: 'test' }); +nock.enableNetConnect(); describe('zkSync', function () { + let bitgo: TestBitGoAPI; + let basecoin; + let hopTxBitgoSignature; + + const address1 = '0x174cfd823af8ce27ed0afee3fcf3c3ba259116be'; + const address2 = '0x7e85bdc27c050e3905ebf4b8e634d9ad6edd0de6'; + const hopContractAddress = '0x47ce7cc86efefef19f8fb516b11735d183da8635'; + const hopDestinationAddress = '0x9c7e8ce6825bD48278B3Ab59228EE26f8BE7925b'; + const hopTx = + '0xf86b808504a817c8ff8252ff949c7e8ce6825bd48278b3ab59228ee26f8be7925b87038d7ea4c68000801ca011bc22c664570133dfca4f08a0b8d02339cf467046d6a4152f04f368d0eaf99ea01d6dc5cf0c897c8d4c3e1df53d0d042784c424536a4cc5b802552b7d64fee8b5'; + const hopTxid = '0x4af65143bc77da2b50f35b3d13cacb4db18f026bf84bc0743550bc57b9b53351'; + const userReqSig = + '0x404db307f6147f0d8cd338c34c13906ef46a6faa7e0e119d5194ef05aec16e6f3d710f9b7901460f97e924066b62efd74443bd34402c6d40b49c203a559ff2c8'; + before(function () { + const bitgoKeyXprv = + 'xprv9s21ZrQH143K3tpWBHWe31sLoXNRQ9AvRYJgitkKxQ4ATFQMwvr7hHNqYRUnS7PsjzB7aK1VxqHLuNQjj1sckJ2Jwo2qxmsvejwECSpFMfC'; + const bitgoKey = bip32.fromBase58(bitgoKeyXprv); + if (!bitgoKey.privateKey) { + throw new Error('no privateKey'); + } + const bitgoXpub = bitgoKey.neutered().toBase58(); + hopTxBitgoSignature = + '0xaa' + + Buffer.from(secp256k1.ecdsaSign(Buffer.from(hopTxid.slice(2), 'hex'), bitgoKey.privateKey).signature).toString( + 'hex' + ); + + const env = 'test'; + bitgo = TestBitGo.decorate(BitGoAPI, { env }); + common.Environments[env].hsmXpub = bitgoXpub; + bitgo.safeRegister('zketh', Zketh.createInstance); bitgo.safeRegister('tzketh', Tzketh.createInstance); bitgo.initializeTestVars(); + basecoin = bitgo.coin('tzketh'); + }); + + after(function () { + nock.cleanAll(); }); + /** + * Build an unsigned account-lib multi-signature send transactino + * @param destination The destination address of the transaction + * @param contractAddress The address of the smart contract processing the transaction + * @param contractSequenceId The sequence id of the contract + * @param nonce The nonce of the sending address + * @param expireTime The expire time of the transaction + * @param amount The amount to send to the recipient + * @param gasPrice The gas price of the transaction + * @param gasLimit The gas limit of the transaction + */ + const buildUnsignedTransaction = async function ({ + destination, + contractAddress, + contractSequenceId = 1, + nonce = 0, + expireTime = Math.floor(new Date().getTime() / 1000), + amount = '100000', + gasPrice = '10000', + gasLimit = '20000', + }) { + const txBuilder: TransactionBuilder = getBuilder('tzketh') as TransactionBuilder; + txBuilder.type(TransactionType.Send); + txBuilder.fee({ + fee: gasPrice, + gasLimit: gasLimit, + }); + txBuilder.counter(nonce); + txBuilder.contract(contractAddress); + const transferBuilder = txBuilder.transfer() as TransferBuilder; + + transferBuilder + .coin('tzketh') + .expirationTime(expireTime) + .amount(amount) + .to(destination) + .contractSequenceId(contractSequenceId); + + return await txBuilder.build(); + }; + describe('Basic Coin Info', function () { it('should return the right info for zketh', function () { const zketh = bitgo.coin('zketh'); @@ -21,9 +104,8 @@ describe('zkSync', function () { zketh.should.be.an.instanceof(Zketh); zketh.getChain().should.equal('zketh'); zketh.getFamily().should.equal('zketh'); - zketh.getFullName().should.equal('zkSync Ethereum'); + zketh.getFullName().should.equal('zkSync'); zketh.getBaseFactor().should.equal(1e18); - zketh.supportsTss().should.equal(false); }); it('should return the right info for tzketh', function () { @@ -32,9 +114,572 @@ describe('zkSync', function () { tzketh.should.be.an.instanceof(Tzketh); tzketh.getChain().should.equal('tzketh'); tzketh.getFamily().should.equal('zketh'); - tzketh.getFullName().should.equal('Testnet zkSync Ethereum'); + tzketh.getFullName().should.equal('Testnet zkSync Sepolia'); tzketh.getBaseFactor().should.equal(1e18); - tzketh.supportsTss().should.equal(false); + }); + }); + + describe('Explain transaction:', () => { + it('should fail if the options object is missing parameters', async function () { + const explainParams = { + feeInfo: { fee: 1 }, + txHex: null, + }; + await basecoin.explainTransaction(explainParams).should.be.rejectedWith('missing explain tx parameters'); + }); + + it('explain a transfer transaction', async function () { + const destination = '0xfaa8f14f46a99eb439c50e0c3b835cc21dad51b4'; + const contractAddress = '0x9e2c5712ab4caf402a98c4bf58c79a0dfe718ad1'; + + const unsignedTransaction = await buildUnsignedTransaction({ + destination, + contractAddress, + }); + + const explainParams = { + halfSigned: { + txHex: unsignedTransaction.toBroadcastFormat(), + }, + feeInfo: { fee: 1 }, + }; + const explanation = await basecoin.explainTransaction(explainParams); + should.exist(explanation.id); + }); + }); + + describe('Sign Transaction', () => { + const account_1 = { + address: '0x8Ce59c2d1702844F8EdED451AA103961bC37B4e8', + owner_1: '4ee089aceabf3ddbf748db79b1066c33b7d3ea1ab3eb7e325121bba2bff2f5ca', + owner_2: '5c7e4efff7304d4dfff6d5f1591844ec6f2adfa6a47e9fece6a3c1a4d755f1e3', + owner_3: '4421ab25dd91e1a3180d03d57c323a7886dcc313d3b3a4b4256a5791572bf597', + }; + + const account_2 = { + address: '0xeeaf0F05f37891ab4a21208B105A0687d12c5aF7', + owner_1: '4ee089aceabf3ddbf748db79b1066c33b7d3ea1ab3eb7e325121bba2bff2f5ca', + owner_2: '5ca116d25aec5f765465432cc421ff25ef9ffdc330b10bb3d9ad61e3baad88d7', + owner_3: '1fae946cc84af8bd74d610a88537e24e19c3349d478d86fc5bb59ba4c88fb9cc', + }; + + it('should sign an unsigned test tx', async function () { + const builder = getBuilder('tzketh') as TransactionBuilder; + builder.fee({ + fee: '280000000000', + gasLimit: '7000000', + }); + builder.counter(1); + builder.type(TransactionType.Send); + builder.contract(account_1.address); + builder.transfer().amount('1').to(account_2.address).expirationTime(10000).contractSequenceId(1); + + const unsignedTx = await builder.build(); + const unsignedTxForBroadcasting = unsignedTx.toBroadcastFormat(); + + const halfSignedRawTx = await basecoin.signTransaction({ + txPrebuild: { + txHex: unsignedTxForBroadcasting, + }, + prv: account_1.owner_2, + }); + + builder.transfer().key(account_1.owner_2); + const halfSignedTx = await builder.build(); + const halfSignedTxForBroadcasting = halfSignedTx.toBroadcastFormat(); + + halfSignedRawTx.halfSigned.txHex.should.equals(halfSignedTxForBroadcasting); + halfSignedRawTx.halfSigned.recipients.length.should.equals(1); + halfSignedRawTx.halfSigned.recipients[0].address.toLowerCase().should.equals(account_2.address.toLowerCase()); + halfSignedRawTx.halfSigned.recipients[0].amount.toLowerCase().should.equals('1'); + }); + + it('should sign an unsigned test tx with eip1559', async function () { + const builder = getBuilder('tzketh') as TransactionBuilder; + builder.fee({ + fee: '280000000000', + gasLimit: '7000000', + eip1559: { + maxFeePerGas: '7593123', + maxPriorityFeePerGas: '150', + }, + }); + builder.counter(1); + builder.type(TransactionType.Send); + builder.contract(account_1.address); + builder.transfer().amount('1').to(account_2.address).expirationTime(10000).contractSequenceId(1); + + const unsignedTx = await builder.build(); + const unsignedTxForBroadcasting = unsignedTx.toBroadcastFormat(); + + const halfSignedRawTx = await basecoin.signTransaction({ + txPrebuild: { + txHex: unsignedTxForBroadcasting, + eip1559: { + maxFeePerGas: '7593123', + maxPriorityFeePerGas: '150', + }, + }, + prv: account_1.owner_2, + }); + + builder.transfer().key(account_1.owner_2); + const halfSignedTx = await builder.build(); + const halfSignedTxForBroadcasting = halfSignedTx.toBroadcastFormat(); + + halfSignedRawTx.halfSigned.txHex.should.equals(halfSignedTxForBroadcasting); + halfSignedRawTx.halfSigned.recipients.length.should.equals(1); + halfSignedRawTx.halfSigned.recipients[0].address.toLowerCase().should.equals(account_2.address.toLowerCase()); + halfSignedRawTx.halfSigned.recipients[0].amount.toLowerCase().should.equals('1'); + halfSignedRawTx.halfSigned.eip1559.maxFeePerGas.should.equal('7593123'); + halfSignedRawTx.halfSigned.eip1559.maxPriorityFeePerGas.should.equal('150'); + }); + }); + + describe('Transaction Verification', function () { + it('should verify a normal txPrebuild from the bitgo server that matches the client txParams', async function () { + const wallet = new Wallet(bitgo, basecoin, {}); + + const txParams = { + recipients: [{ amount: '1000000000000', address: address1 }], + wallet: wallet, + walletPassphrase: 'fakeWalletPassphrase', + }; + + const txPrebuild = { + recipients: [{ amount: '1000000000000', address: address1 }], + nextContractSequenceId: 0, + gasPrice: 20000000000, + gasLimit: 500000, + isBatch: false, + coin: 'tzketh', + walletId: 'fakeWalletId', + walletContractAddress: 'fakeWalletContractAddress', + }; + + const verification = {}; + + const isTransactionVerified = await basecoin.verifyTransaction({ txParams, txPrebuild, wallet, verification }); + isTransactionVerified.should.equal(true); + }); + + it('should verify a hop txPrebuild from the bitgo server that matches the client txParams', async function () { + const wallet = new Wallet(bitgo, basecoin, {}); + + const txParams = { + recipients: [{ amount: 1000000000000000, address: hopDestinationAddress }], + wallet: wallet, + walletPassphrase: 'fakeWalletPassphrase', + hop: true, + }; + + const txPrebuild = { + recipients: [{ amount: '5000000000000000', address: hopContractAddress }], + nextContractSequenceId: 0, + gasPrice: 20000000000, + gasLimit: 500000, + isBatch: false, + coin: 'tzketh', + walletId: 'fakeWalletId', + walletContractAddress: 'fakeWalletContractAddress', + hopTransaction: { + tx: hopTx, + id: hopTxid, + signature: hopTxBitgoSignature, + paymentId: '2773928196', + gasPrice: 20000000000, + gasLimit: 500000, + amount: '1000000000000000', + recipient: hopDestinationAddress, + nonce: 0, + userReqSig: userReqSig, + gasPriceMax: 500000000000, + }, + }; + + const verification = {}; + + const isTransactionVerified = await basecoin.verifyTransaction({ txParams, txPrebuild, wallet, verification }); + isTransactionVerified.should.equal(true); + }); + + it('should reject when client txParams are missing', async function () { + const wallet = new Wallet(bitgo, basecoin, {}); + + const txParams = null; + + const txPrebuild = { + recipients: [{ amount: '1000000000000', address: address1 }], + nextContractSequenceId: 0, + gasPrice: 20000000000, + gasLimit: 500000, + isBatch: false, + coin: 'tzketh', + walletId: 'fakeWalletId', + walletContractAddress: 'fakeWalletContractAddress', + }; + + const verification = {}; + + await basecoin + .verifyTransaction({ txParams, txPrebuild, wallet, verification }) + .should.be.rejectedWith('missing params'); + }); + + it('should reject txPrebuild that is both batch and hop', async function () { + const wallet = new Wallet(bitgo, basecoin, {}); + + const txParams = { + recipients: [ + { amount: '1000000000000', address: address1 }, + { amount: '2500000000000', address: address2 }, + ], + wallet: wallet, + walletPassphrase: 'fakeWalletPassphrase', + hop: true, + }; + + const txPrebuild = { + recipients: [{ amount: '3500000000000', address: address1 }], + nextContractSequenceId: 0, + gasPrice: 20000000000, + gasLimit: 500000, + isBatch: true, + coin: 'tzketh', + walletId: 'fakeWalletId', + walletContractAddress: 'fakeWalletContractAddress', + hopTransaction: { + tx: hopTx, + id: hopTxid, + signature: hopTxBitgoSignature, + paymentId: '2773928196', + gasPrice: 20000000000, + gasLimit: 500000, + amount: '1000000000000000', + recipient: hopDestinationAddress, + nonce: 0, + userReqSig: userReqSig, + gasPriceMax: 500000000000, + }, + }; + + const verification = {}; + + await basecoin + .verifyTransaction({ txParams, txPrebuild, wallet, verification }) + .should.be.rejectedWith('tx cannot be both a batch and hop transaction'); + }); + + it('should reject a txPrebuild with more than one recipient', async function () { + const wallet = new Wallet(bitgo, basecoin, {}); + + const txParams = { + recipients: [ + { amount: '1000000000000', address: address1 }, + { amount: '2500000000000', address: address2 }, + ], + wallet: wallet, + walletPassphrase: 'fakeWalletPassphrase', + }; + + const txPrebuild = { + recipients: [ + { amount: '1000000000000', address: address1 }, + { amount: '2500000000000', address: address2 }, + ], + nextContractSequenceId: 0, + gasPrice: 20000000000, + gasLimit: 500000, + isBatch: true, + coin: 'tzketh', + walletId: 'fakeWalletId', + walletContractAddress: 'fakeWalletContractAddress', + }; + + const verification = {}; + + await basecoin + .verifyTransaction({ txParams, txPrebuild, wallet, verification }) + .should.be.rejectedWith('txPrebuild should only have 1 recipient but 2 found'); + }); + + it('should reject a hop txPrebuild that does not send to its hop address', async function () { + const wallet = new Wallet(bitgo, basecoin, {}); + + const txParams = { + recipients: [{ amount: '1000000000000000', address: hopDestinationAddress }], + wallet: wallet, + walletPassphrase: 'fakeWalletPassphrase', + hop: true, + }; + + const txPrebuild = { + recipients: [{ amount: '5000000000000000', address: address1 }], + nextContractSequenceId: 0, + gasPrice: 20000000000, + gasLimit: 500000, + isBatch: false, + coin: 'tzketh', + walletId: 'fakeWalletId', + walletContractAddress: 'fakeWalletContractAddress', + hopTransaction: { + tx: hopTx, + id: hopTxid, + signature: hopTxBitgoSignature, + paymentId: '0', + gasPrice: 20000000000, + gasLimit: 500000, + amount: '1000000000000000', + recipient: hopDestinationAddress, + nonce: 0, + userReqSig: userReqSig, + gasPriceMax: 500000000000, + }, + }; + + const verification = {}; + + await basecoin + .verifyTransaction({ txParams, txPrebuild, wallet, verification }) + .should.be.rejectedWith('recipient address of txPrebuild does not match hop address'); + }); + + it('should reject a normal txPrebuild from the bitgo server with the wrong amount', async function () { + const wallet = new Wallet(bitgo, basecoin, {}); + + const txParams = { + recipients: [{ amount: '1000000000000', address: address1 }], + wallet: wallet, + walletPassphrase: 'fakeWalletPassphrase', + }; + + const txPrebuild = { + recipients: [{ amount: '2000000000000', address: address1 }], + nextContractSequenceId: 0, + gasPrice: 20000000000, + gasLimit: 500000, + isBatch: false, + coin: 'tzketh', + walletId: 'fakeWalletId', + walletContractAddress: 'fakeWalletContractAddress', + }; + + const verification = {}; + + await basecoin + .verifyTransaction({ txParams, txPrebuild, wallet, verification }) + .should.be.rejectedWith( + 'normal transaction amount in txPrebuild received from BitGo servers does not match txParams supplied by client' + ); + }); + + it('should reject a normal txPrebuild from the bitgo server with the wrong recipient', async function () { + const wallet = new Wallet(bitgo, basecoin, {}); + + const txParams = { + recipients: [{ amount: '1000000000000', address: address1 }], + wallet: wallet, + walletPassphrase: 'fakeWalletPassphrase', + }; + + const txPrebuild = { + recipients: [{ amount: '1000000000000', address: address2 }], + nextContractSequenceId: 0, + gasPrice: 20000000000, + gasLimit: 500000, + isBatch: false, + coin: 'tzketh', + walletId: 'fakeWalletId', + walletContractAddress: 'fakeWalletContractAddress', + }; + + const verification = {}; + + await basecoin + .verifyTransaction({ txParams, txPrebuild, wallet, verification }) + .should.be.rejectedWith( + 'destination address in normal txPrebuild does not match that in txParams supplied by client' + ); + }); + + it('should reject a txPrebuild from the bitgo server with the wrong coin', async function () { + const wallet = new Wallet(bitgo, basecoin, {}); + + const txParams = { + recipients: [{ amount: '1000000000000', address: address1 }], + wallet: wallet, + walletPassphrase: 'fakeWalletPassphrase', + }; + + const txPrebuild = { + recipients: [{ amount: '1000000000000', address: address1 }], + nextContractSequenceId: 0, + gasPrice: 20000000000, + gasLimit: 500000, + isBatch: false, + coin: 'btc', + walletId: 'fakeWalletId', + walletContractAddress: 'fakeWalletContractAddress', + }; + + const verification = {}; + + await basecoin + .verifyTransaction({ txParams, txPrebuild, wallet, verification }) + .should.be.rejectedWith('coin in txPrebuild did not match that in txParams supplied by client'); + }); + }); + + describe('Recover transaction:', function () { + const baseUrl = 'https://api-sepolia.arbiscan.io'; + const userXpub = + 'xpub661MyMwAqRbcEeTc8789MK5PUGEYiPG4F4V17n2Rd2LoTATA1XoCnJT5FAYAShQxSxtFjpo5NHmcWwTp2LiWGBMwpUcAA3HywhxivgYfq7q'; + const userXprv = + 'xprv9s21ZrQH143K2AP925b8zB8evEQ4JvYCsqZQKPcp4gopaN81TzUxEW8bPtVyDgjmddGhRRETn8xi1cVAB9bf1Bx9kGRRFgTZXxJayZLnag1'; + const backupXpub = + 'xpub661MyMwAqRbcFZX15xpZf4ERCGHiVSJm8r5C4yh1yXV2GrdZCUPYo4WQr6tN9oUywKXsgSHo7Risf9r22GH5joVD2hEEEhqnSCvK8qy11wW'; + const backupXprv = + 'xprv9s21ZrQH143K35SXywHZHvHgeETE5yaumd9bGbHQRBx3Q4JQew5JFGBvzqiZjCUkBdBUZnfuMDTGURRayN1hFSWxEJQsCEAMm1D3pk1h7Jj'; + + it('should generate an unsigned sweep', async function () { + const walletContractAddress = TestBitGo.V2.TEST_ETH_WALLET_FIRST_ADDRESS as string; + const backupKeyAddress = '0x4f2c4830cc37f2785c646f89ded8a919219fa0e9'; + nock(baseUrl) + .get('/api') + .twice() + .query(mockData.getTxListRequest(backupKeyAddress)) + .reply(200, mockData.getTxListResponse); + nock(baseUrl) + .get('/api') + .query(mockData.getBalanceRequest(walletContractAddress)) + .reply(200, mockData.getBalanceResponse); + nock(baseUrl) + .get('/api') + .query(mockData.getBalanceRequest(backupKeyAddress)) + .reply(200, mockData.getBalanceResponse); + nock(baseUrl).get('/api').query(mockData.getContractCallRequest).reply(200, mockData.getContractCallResponse); + const basecoin = bitgo.coin('tzketh') as Zketh; + const transaction = (await basecoin.recover({ + userKey: userXpub, + backupKey: backupXpub, + walletContractAddress: walletContractAddress, + recoveryDestination: TestBitGo.V2.TEST_ERC20_TOKEN_RECIPIENT as string, + eip1559: { maxFeePerGas: 20000000000, maxPriorityFeePerGas: 10000000000 }, + gasLimit: 500000, + })) as OfflineVaultTxInfo; + should.exist(transaction); + transaction.should.have.property('txHex'); + transaction.should.have.property('contractSequenceId'); + transaction.should.have.property('expireTime'); + transaction.should.have.property('gasLimit'); + transaction.gasLimit.should.equal('500000'); + transaction.should.have.property('walletContractAddress'); + transaction.walletContractAddress.should.equal(TestBitGo.V2.TEST_ETH_WALLET_FIRST_ADDRESS); + transaction.should.have.property('recipients'); + const recipient = transaction.recipients[0]; + recipient.should.have.property('address'); + recipient.address.should.equal(TestBitGo.V2.TEST_ERC20_TOKEN_RECIPIENT); + recipient.should.have.property('amount'); + recipient.amount.should.equal('9999999999999999928'); + }); + + it('should construct a recovery transaction without BitGo', async function () { + const backupKeyAddress = '0x6d22efdd634996248170c948e5726007fc251bb3'; + const walletContractAddress = TestBitGo.V2.TEST_ETH_WALLET_FIRST_ADDRESS as string; + nock(baseUrl) + .get('/api') + .query(mockData.getTxListRequest(backupKeyAddress)) + .reply(200, mockData.getTxListResponse); + nock(baseUrl) + .get('/api') + .query(mockData.getBalanceRequest(walletContractAddress)) + .reply(200, mockData.getBalanceResponse); + nock(baseUrl) + .get('/api') + .query(mockData.getBalanceRequest(backupKeyAddress)) + .reply(200, mockData.getBalanceResponse); + nock(baseUrl).get('/api').query(mockData.getContractCallRequest).reply(200, mockData.getContractCallResponse); + const basecoin = bitgo.coin('tzketh') as Zketh; + const transaction = (await basecoin.recover({ + userKey: + '{"iv":"VFZ3jvXhxo1Z+Yaf2MtZnA==","v":1,"iter":10000,"ks":256,"ts":64,"mode"\n' + + ':"ccm","adata":"","cipher":"aes","salt":"p+fkHuLa/8k=","ct":"hYG7pvljLIgCjZ\n' + + '53PBlCde5KZRmlUKKHLtDMk+HJfuU46hW+x+C9WsIAO4gFPnTCvFVmQ8x7czCtcNFub5AO2otOG\n' + + 'OsX4GE2gXOEmCl1TpWwwNhm7yMUjGJUpgW6ZZgXSXdDitSKi4V/hk78SGSzjFOBSPYRa6I="}\n', + backupKey: + '{"iv":"AbsCtv1qwPIhOgyrCpNagA==","v":1,"iter":10000,"ks":256,"ts":64,"mode"\n' + + ':"ccm","adata":"","cipher":"aes","salt":"5vpUDBUlzm8=","ct":"PapYYCjBXRLUKA\n' + + 'JbOsB/EJ9B8fUmVQTxMPjUnQyAky12me9K66GiMEAxTD7kd6bYAQJuuTkATXKU7Bnf7vK9JxNOw\n' + + 'oji7HF9eFH0aD4/hX5SWFfHF2Qfi+TnXv6hVsMAoisDZs3/F67/ZUaDYR0ZsdrQ4Q/cLD0="}\n', + + walletContractAddress: walletContractAddress, + walletPassphrase: TestBitGo.V2.TEST_RECOVERY_PASSCODE, + recoveryDestination: TestBitGo.V2.TEST_ERC20_TOKEN_RECIPIENT as string, + gasLimit: 500000, + })) as OfflineVaultTxInfo; + should.exist(transaction); + transaction.should.have.property('tx'); + transaction.should.have.property('id'); + const decodedTx = optionalDeps.EthTx.Transaction.fromSerializedTx(optionalDeps.ethUtil.toBuffer(transaction.tx)); + decodedTx.should.have.property('gasPrice'); + decodedTx.should.have.property('nonce'); + decodedTx.should.have.property('to'); + }); + + it('should be able to second sign', async function () { + const walletContractAddress = TestBitGo.V2.TEST_ETH_WALLET_FIRST_ADDRESS as string; + const backupKeyAddress = '0x4f2c4830cc37f2785c646f89ded8a919219fa0e9'; + nock(baseUrl) + .get('/api') + .twice() + .query(mockData.getTxListRequest(backupKeyAddress)) + .reply(200, mockData.getTxListResponse); + nock(baseUrl) + .get('/api') + .query(mockData.getBalanceRequest(walletContractAddress)) + .reply(200, mockData.getBalanceResponse); + nock(baseUrl) + .get('/api') + .query(mockData.getBalanceRequest(backupKeyAddress)) + .reply(200, mockData.getBalanceResponse); + nock(baseUrl).get('/api').query(mockData.getContractCallRequest).reply(200, mockData.getContractCallResponse); + const basecoin = bitgo.coin('tzketh') as Zketh; + const transaction = (await basecoin.recover({ + userKey: userXpub, + backupKey: backupXpub, + walletContractAddress: walletContractAddress, + recoveryDestination: TestBitGo.V2.TEST_ERC20_TOKEN_RECIPIENT as string, + eip1559: { maxFeePerGas: 20000000000, maxPriorityFeePerGas: 10000000000 }, + replayProtectionOptions: { chain: 80001, hardfork: 'london' }, + gasLimit: 500000, + })) as OfflineVaultTxInfo; + + const txPrebuild = { + txHex: transaction.txHex, + }; + + const params = { + txPrebuild, + prv: userXprv, + }; + // sign transaction once + const halfSigned = await basecoin.signTransaction(params as SignTransactionOptions); + const halfSignedParams = { + txPrebuild: halfSigned, + isLastSignature: true, + walletContractAddress: walletContractAddress, + prv: backupXprv, + }; + + const finalSigned = (await basecoin.signTransaction( + halfSignedParams as SignTransactionOptions + )) as FullySignedTransaction; + finalSigned.should.have.property('txHex'); + const txBuilder = getBuilder('tzketh') as TransactionBuilder; + txBuilder.from(finalSigned.txHex); + const rebuiltTx = await txBuilder.build(); + rebuiltTx.signature.length.should.equal(2); + rebuiltTx.outputs.length.should.equal(1); }); }); }); diff --git a/modules/sdk-coin-zketh/test/unit/zkethToken.ts b/modules/sdk-coin-zketh/test/unit/zkethToken.ts index 31d5d490b7..70ec661075 100644 --- a/modules/sdk-coin-zketh/test/unit/zkethToken.ts +++ b/modules/sdk-coin-zketh/test/unit/zkethToken.ts @@ -29,4 +29,9 @@ describe('Zketh Token:', function () { zkethTokenCoin.network.should.equal('Testnet'); zkethTokenCoin.decimalPlaces.should.equal(18); }); + + it('should return same token by contract address', function () { + const tokencoinBycontractAddress = bitgo.coin(zkethTokenCoin.tokenContractAddress); + zkethTokenCoin.should.deepEqual(tokencoinBycontractAddress); + }); });