diff --git a/modules/sdk-coin-apt/src/apt.ts b/modules/sdk-coin-apt/src/apt.ts index 6091583b85..d18694a596 100644 --- a/modules/sdk-coin-apt/src/apt.ts +++ b/modules/sdk-coin-apt/src/apt.ts @@ -3,7 +3,6 @@ import { BaseCoin, BaseTransaction, BitGoBase, - InvalidAddressError, KeyPair, MPCAlgorithm, MultisigType, @@ -14,7 +13,9 @@ import { PrebuildTransactionWithIntentOptions, SignedTransaction, SignTransactionOptions, - VerifyAddressOptions, + TssVerifyAddressOptions, + UnexpectedAddressError, + verifyEddsaTssWalletAddress, VerifyTransactionOptions, } from '@bitgo/sdk-core'; import { BaseCoin as StaticsBaseCoin, coins } from '@bitgo/statics'; @@ -120,12 +121,22 @@ export class Apt extends BaseCoin { return true; } - async isWalletAddress(params: VerifyAddressOptions): Promise { - const { address: newAddress } = params; + /** + * Verify that an address belongs to this wallet. + * + * @param params - Verification parameters including address, keychains, and index + * @returns True if address belongs to wallet + * @throws UnexpectedAddressError if address doesn't match derived address + */ + async isWalletAddress(params: TssVerifyAddressOptions): Promise { + const isValid = await verifyEddsaTssWalletAddress(params, this.isValidAddress.bind(this), (pubKey) => + utils.getAddressFromPublicKey(pubKey) + ); - if (!this.isValidAddress(newAddress)) { - throw new InvalidAddressError(`invalid address: ${newAddress}`); + if (!isValid) { + throw new UnexpectedAddressError(); } + return true; } diff --git a/modules/sdk-coin-apt/test/unit/apt.ts b/modules/sdk-coin-apt/test/unit/apt.ts index f7d8d03ff6..03f07a96dd 100644 --- a/modules/sdk-coin-apt/test/unit/apt.ts +++ b/modules/sdk-coin-apt/test/unit/apt.ts @@ -280,42 +280,19 @@ describe('APT:', function () { }); describe('Address Validation', () => { - let keychains; - let commonKeychain; - - before(function () { - commonKeychain = - '19bdfe2a4b498a05511381235a8892d54267807c4a3f654e310b938b8b424ff4adedbe92f4c146de641c67508a961324c8504cdf8e0c0acbb68d6104ccccd781'; - keychains = [ - { - id: '6424c353eaf78d000766e95949868468', - source: 'user', - type: 'tss', - commonKeychain: - '19bdfe2a4b498a05511381235a8892d54267807c4a3f654e310b938b8b424ff4adedbe92f4c146de641c67508a961324c8504cdf8e0c0acbb68d6104ccccd781', - encryptedPrv: - '{"iv":"cZd5i7L4RxtwrALW2rK7UA==","v":1,"iter":10000,"ks":256,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"5zgoH1Bd3Fw=","ct":"9vVlnXFRtrM9FVEo+d2chbGHlM9lFZemueBuAs3BIkPo33Fo7jzwwNK/kIWkEyg+NmEBd5IaqAS157nvvvwzzsmMWlQdUz9qbmXNv3pg987cXFR08exS+4uhwP1YNOjJTRvRNcO9ZqHb46d4fmyJ/yC9/susCge7r/EsbaN5C3afv1dzybuq912FwaQElZLYYp5BICudFOMZ9k0UDMfKM/PMDkH7WexoGHr9GKq/bgCH2B39TZZyHKU6Uy47lXep2s6h0DrMwHOrnmiL3DZjOj88Ynvphlzxuo4eOlD2UHia2+nvIaISYs29Pr0DAvREutchvcBpExj1kWWPv7hQYrv8F0NAdatsbWl3w+xKyfiMKo1USlrwyJviypGtQtXOJyw0XPN0rv2+L5lW8BbjpzHfYYN13fJTedlGTFhhkzVtbbPAKE02kx7zCJcjYaiexdSTsrDLScYNT9/Jhdt27KpsooehwVohLfSKz4vbFfRu2MPZw3/+c/hfiJNgtz6esWbnxGrcE8U2IwPYCaK+Ghk4DcqWNIni59RI5B5kAsQOToII40qPN510uTgxBSPO7q7MHgkxdd4CqBq+ojr9j0P7oao8E5Y+CBDJrojDoCh1oCCDW9vo2dXlVcD8SIbw7U/9AfvEbA4xyE/5md1M7CIwLnWs2Ynv0YtaKoqhdS9x6FmHlMDhN/DKHinrwmowtrTT82fOkpO5g9saSmgU7Qy3gLt8t+VwdEyeFeQUKRSyci8qgqXQaZIg4+aXgaSOnlCFMtmB8ekYxEhTY5uzRfrNgS4s1QeqFBpNtUF+Ydi297pbVXnJoXAN+SVWd80GCx+yI2dpVC89k3rOWK9WeyqlnzuLJWp2RIOB9cdW8GFv/fN+QAJpYeVxOE4+nZDsKnsj8nKcg9t4Dlx1G6gLM1/Vq9YxNLbuzuRC0asUYvdMnoMvszmpm++TxndYisgNYscpZSoz7wvcazJNEPfhPVjEkd6tUUuN4GM35H0DmKCUQNT+a6B6hmHlTZvjxiyGAg5bY59hdjvJ+22QduazlEEC6LI3HrA7uK0TpplWzS1tCIFvTMUhj65DEZmNJ2+ZY9bQ4vsMf+DRR3OOG4t+DMlNfjOd3zNv3QoY95BjfWpryFwPzDq7bCP67JDsoj7j2TY5FRSrRkD77H0Ewlux2cWfjRTwcMHcdQxxuV0OP0aNjGDjybFN"}', - }, - { - id: '6424c353eaf78d000766e96137d4404b', - source: 'backup', - type: 'tss', - commonKeychain: - '19bdfe2a4b498a05511381235a8892d54267807c4a3f654e310b938b8b424ff4adedbe92f4c146de641c67508a961324c8504cdf8e0c0acbb68d6104ccccd781', - encryptedPrv: - '{"iv":"vi0dPef/Rx7kG/pRySQi6Q==","v":1,"iter":10000,"ks":256,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"9efhQsiEvVs=","ct":"Gw6atvf6gxKzsjtl3xseipO3rAxp1mAz7Yu1ihFsi5/lf2vMZegApgZx+pyILFS9KKLHbNF3U6WgSYdrr2t4vzdLsXkH1WIxfHS+cd2C5N59yADZDnPJBT6pv/IRvaYelP0Ck3nIYQ2hSMm8op+VOWC/SzHeh7slYDqwEHTGan0Wigfvk1yRd7CCJTaEAomnc/4eFi2NY3X3gt/3opy9IAgknnwUFohn96EWpEQ0F6pbzH/Z8VF6gF+DUcrrByAxExUPnHQZiFk3YHU/vVV4FxBU/mVAE8xBsBn5ul5e5SUMPfc7TBuJWv4BByTNg9xDShF/91Yx2nbfUm5d9QmM8lpKgzzQvcK8POAPk87gRCuKnsGh5vNS0UppkHc+ocfzRQlGA6jze7QyyQO0rMj5Ly8kWjwk2vISvKYHYS1NR7VU549UIXo7NXjatunKSc3+IreoRUHIshiaLg6hl+pxCCuc0qQ43V0mdIfCjTN8gkGWLNk8R7tAGPz9jyapQPcPEGHgEz0ATIi6yMNWCsibS2eLiE1uVEJONoM4lk6FPl3Q2CHbW2MeEbqjY8hbaw18mNb2xSBH/Fwpiial+Tvi2imqgnCO4ZpO9bllKftZPcQy0stN+eGBlb5ufyflKkDSiChHYroGjEpmiFicdde48cJszF52uKNnf1q67fA9/S2FAHQab3EXojxH2Gbk+kkV2h/TYKFFZSWC3vi4e8mO+vjMUcR0AdsgPFyEIz0SCGuba3CnTLNdEuZwsauAeHkx2vUTnRgJPVgNeeuXmsVG76Sy2ggJHuals0Hj8U2Xda0qO1RuFfoCWfss9wn6HGRwPPkhSB/8oNguAqmRVGKkd8Zwt3IvrTd9fk0/rFFDJKGz7WyNHkYgUmNiGcItD12v0jx7FZ52EJzl3Av1RyJUQK18+8EYPh3SGiU9dt7VX0aF0uo6JouKhOeldUvMP+AugQz8fUclwTQsbboVg27Yxo0DyATVwThW5a56R6Qf5ZiQJluFuzs5y98rq0S5q046lE6o3vVmJpEdwjeSCJoET5CL4nTgkXyWvhm4eB8u/e66l3o0qbaSx8q9YYmT9EpRcl5TP4ThLBKETYdzVvg4exjQfektMatk5EyUpEIhZPXh5vXpJZesdfO9LJ8zTaHBsBjDPU7cdNgQMbebpataRi8A0el2/IJXl+E+olgAz5zC4i2O1Q=="}', - }, - { - id: '6424c353eaf78d000766e9510b125fba', - source: 'bitgo', - type: 'tss', - commonKeychain: - '19bdfe2a4b498a05511381235a8892d54267807c4a3f654e310b938b8b424ff4adedbe92f4c146de641c67508a961324c8504cdf8e0c0acbb68d6104ccccd781', - verifiedVssProof: true, - isBitGo: true, - }, - ]; - }); + const testData = { + commonKeychain: + '6a724c11eafea4209704c35e6ee3e1fba80d2a40860d873bbe5981de636c9cf6ade77e6fdd4388889ee93d7eaa737ab584edb57cc0cc15b2899380348d6e482c', + rootAddress: '0x0598b31aa77176dbaba25306404aa8131218068df58bf0b7eec13f57053fd5a7', + receiveAddress: '0xdc169725dd6d9a07ee255b17087b4079e8a80850c895c65b62c0ef6de740d37a', + receiveAddressIndex: 1, + }; + + const keychains = [ + { commonKeychain: testData.commonKeychain }, + { commonKeychain: testData.commonKeychain }, + { commonKeychain: testData.commonKeychain }, + ]; it('should return true when validating a well formatted address prefixed with 0x', async function () { const address = '0xf941ae3cbe5645dccc15da8346b533f7f91f202089a5521653c062b2ff10b304'; @@ -332,19 +309,23 @@ describe('APT:', function () { basecoin.isValidAddress(address).should.equal(false); }); - it('should return true for isWalletAddress with valid address for index 4', async function () { - const newAddress = '0x8b3c7807730d75792dd6c49732cf9f014d6984a9c77d386bdb1072a9e537d8d8'; - const index = 4; + it('should verify a valid receive address', async function () { + const params = { + address: testData.receiveAddress, + rootAddress: testData.rootAddress, + keychains, + index: testData.receiveAddressIndex, + }; - const params = { commonKeychain, address: newAddress, index, keychains }; - (await basecoin.isWalletAddress(params)).should.equal(true); + const result = await basecoin.isWalletAddress(params); + result.should.equal(true); }); it('should throw error for isWalletAddress when keychains is missing', async function () { const address = '0x2959bfc3fdb7dc23fed8deba2fafb70f3e606a59'; const index = 0; - const params = { commonKeychain, address, index }; + const params = { commonKeychain: testData.commonKeychain, address, index }; await assert.rejects(async () => basecoin.isWalletAddress(params)); }); @@ -352,7 +333,7 @@ describe('APT:', function () { const wrongAddress = 'badAddress'; const index = 0; - const params = { commonKeychain, address: wrongAddress, index }; + const params = { commonKeychain: testData.commonKeychain, address: wrongAddress, index }; await assert.rejects(async () => basecoin.isWalletAddress(params), { message: `invalid address: ${wrongAddress}`, });