Skip to content

Commit bd01f93

Browse files
Merge pull request #7596 from BitGo/WP-6461-ada-address-verification
feat: address verification for ada
2 parents c1a0309 + 208318c commit bd01f93

File tree

2 files changed

+217
-4
lines changed

2 files changed

+217
-4
lines changed

modules/sdk-coin-ada/src/ada.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
SignedTransaction,
1313
SignTransactionOptions as BaseSignTransactionOptions,
1414
TransactionExplanation,
15-
VerifyAddressOptions,
1615
VerifyTransactionOptions,
1716
EDDSAMethods,
1817
EDDSAMethodTypes,
@@ -32,6 +31,8 @@ import {
3231
MultisigType,
3332
multisigTypes,
3433
AuditDecryptedKeyParams,
34+
extractCommonKeychain,
35+
TssVerifyAddressOptions,
3536
} from '@bitgo/sdk-core';
3637
import { KeyPair as AdaKeyPair, Transaction, TransactionBuilderFactory, Utils } from './lib';
3738
import { BaseCoin as StaticsBaseCoin, CoinFamily, coins } from '@bitgo/statics';
@@ -161,12 +162,24 @@ export class Ada extends BaseCoin {
161162
return true;
162163
}
163164

164-
async isWalletAddress(params: VerifyAddressOptions): Promise<boolean> {
165-
const { address } = params;
165+
async isWalletAddress(params: TssVerifyAddressOptions): Promise<boolean> {
166+
const { address, keychains, index } = params;
166167
if (!this.isValidAddress(address)) {
167168
throw new InvalidAddressError(`Invalid Cardano Address: ${address}`);
168169
}
169-
return true;
170+
171+
const indexNumber = Number(index);
172+
if (isNaN(indexNumber)) {
173+
throw new Error('Invalid index. index must be a number.');
174+
}
175+
176+
const commonKeychain = extractCommonKeychain(keychains);
177+
const { address: derivedAddress } = await this.getAdaAddressAndAccountId({
178+
bitgoKey: commonKeychain,
179+
index: indexNumber,
180+
});
181+
182+
return address === derivedAddress;
170183
}
171184

172185
/** @inheritDoc */

modules/sdk-coin-ada/test/unit/ada.ts

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,206 @@ describe('ADA', function () {
812812
});
813813
});
814814

815+
describe('Verify wallet address (isWalletAddress):', () => {
816+
const commonKeychain =
817+
'ed312d0db4615688219c43231eb4b98d5883c0b44bcfef1956290555995ad68ef7c22917b4a8b69183864b83cc7028655cd7a70ef76d6948d809a15050054840';
818+
819+
it('should verify a valid wallet address at index 0', async function () {
820+
const keychains = [
821+
{
822+
id: '1',
823+
commonKeychain: commonKeychain,
824+
type: 'tss',
825+
source: 'user',
826+
},
827+
{
828+
id: '2',
829+
commonKeychain: commonKeychain,
830+
type: 'tss',
831+
source: 'backup',
832+
},
833+
{
834+
id: '3',
835+
commonKeychain: commonKeychain,
836+
type: 'tss',
837+
source: 'bitgo',
838+
},
839+
];
840+
841+
const address =
842+
'addr_test1qzvmazmpgfhjyppwlsw29zjjwazcsfk62z9zv5vsv24p0wyeh69kzsn0ygzzalqu5299ya693qnd55y2yegeqc42z7uq0ge2pq';
843+
const isValid = await basecoin.isWalletAddress({
844+
address,
845+
keychains,
846+
index: 0,
847+
});
848+
849+
isValid.should.equal(true);
850+
});
851+
852+
it('should fail to verify an address with wrong index', async function () {
853+
const keychains = [
854+
{
855+
id: '1',
856+
commonKeychain: commonKeychain,
857+
type: 'tss' as const,
858+
source: 'user' as const,
859+
},
860+
{
861+
id: '2',
862+
commonKeychain: commonKeychain,
863+
type: 'tss' as const,
864+
source: 'backup' as const,
865+
},
866+
{
867+
id: '3',
868+
commonKeychain: commonKeychain,
869+
type: 'tss' as const,
870+
source: 'bitgo' as const,
871+
},
872+
];
873+
874+
const isValid = await basecoin.isWalletAddress({
875+
address:
876+
'addr_test1qzvmazmpgfhjyppwlsw29zjjwazcsfk62z9zv5vsv24p0wyeh69kzsn0ygzzalqu5299ya693qnd55y2yegeqc42z7uq0ge2pq',
877+
keychains,
878+
index: 2,
879+
});
880+
881+
isValid.should.equal(false);
882+
});
883+
884+
it('should fail to verify a random address not from wallet', async function () {
885+
const keychains = [
886+
{
887+
id: '1',
888+
commonKeychain: commonKeychain,
889+
type: 'tss' as const,
890+
source: 'user' as const,
891+
},
892+
{
893+
id: '2',
894+
commonKeychain: commonKeychain,
895+
type: 'tss' as const,
896+
source: 'backup' as const,
897+
},
898+
{
899+
id: '3',
900+
commonKeychain: commonKeychain,
901+
type: 'tss' as const,
902+
source: 'bitgo' as const,
903+
},
904+
];
905+
906+
// Use a random valid ADA address not from this wallet
907+
const randomAddress = 'addr_test1vr8rakm66rcfv4fcxqykg5lf0yv7lsyk9mvapx369jpvtcgfcuk7f';
908+
909+
const isValid = await basecoin.isWalletAddress({
910+
address: randomAddress,
911+
keychains,
912+
index: 0,
913+
});
914+
915+
isValid.should.equal(false);
916+
});
917+
918+
it('should throw error for invalid address format', async function () {
919+
const keychains = [
920+
{
921+
id: '1',
922+
commonKeychain: commonKeychain,
923+
type: 'tss' as const,
924+
source: 'user' as const,
925+
},
926+
{
927+
id: '2',
928+
commonKeychain: commonKeychain,
929+
type: 'tss' as const,
930+
source: 'backup' as const,
931+
},
932+
{
933+
id: '3',
934+
commonKeychain: commonKeychain,
935+
type: 'tss' as const,
936+
source: 'bitgo' as const,
937+
},
938+
];
939+
940+
const invalidAddress = 'not_a_valid_address';
941+
942+
await basecoin
943+
.isWalletAddress({
944+
address: invalidAddress,
945+
keychains,
946+
index: 0,
947+
})
948+
.should.be.rejectedWith('Invalid Cardano Address: not_a_valid_address');
949+
});
950+
951+
it('should throw error when keychains are missing', async function () {
952+
const address =
953+
'addr_test1qzvmazmpgfhjyppwlsw29zjjwazcsfk62z9zv5vsv24p0wyeh69kzsn0ygzzalqu5299ya693qnd55y2yegeqc42z7uq0ge2pq';
954+
955+
await basecoin
956+
.isWalletAddress({
957+
address,
958+
keychains: [],
959+
index: 0,
960+
})
961+
.should.be.rejectedWith('missing required param keychains');
962+
});
963+
964+
it('should throw error when commonKeychain is missing', async function () {
965+
const keychains = [
966+
{
967+
id: '1',
968+
type: 'tss' as const,
969+
source: 'user' as const,
970+
// commonKeychain is missing
971+
},
972+
];
973+
974+
const address =
975+
'addr_test1qzvmazmpgfhjyppwlsw29zjjwazcsfk62z9zv5vsv24p0wyeh69kzsn0ygzzalqu5299ya693qnd55y2yegeqc42z7uq0ge2pq';
976+
977+
await basecoin
978+
.isWalletAddress({
979+
address,
980+
keychains,
981+
index: 0,
982+
})
983+
.should.be.rejectedWith('missing required param commonKeychain');
984+
});
985+
986+
it('should throw error when keychains have mismatched commonKeychains', async function () {
987+
const keychains = [
988+
{
989+
id: '1',
990+
commonKeychain: commonKeychain,
991+
type: 'tss' as const,
992+
source: 'user' as const,
993+
},
994+
{
995+
id: '2',
996+
commonKeychain: 'differentKeychain1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
997+
type: 'tss' as const,
998+
source: 'backup' as const,
999+
},
1000+
];
1001+
1002+
const address =
1003+
'addr_test1qzvmazmpgfhjyppwlsw29zjjwazcsfk62z9zv5vsv24p0wyeh69kzsn0ygzzalqu5299ya693qnd55y2yegeqc42z7uq0ge2pq';
1004+
1005+
await basecoin
1006+
.isWalletAddress({
1007+
address,
1008+
keychains,
1009+
index: 0,
1010+
})
1011+
.should.be.rejectedWith('all keychains must have the same commonKeychain for MPC coins');
1012+
});
1013+
});
1014+
8151015
describe('Verify token consolidation transaction:', () => {
8161016
it('should fail to verify a spoofed token consolidation transaction with incorrect address', async () => {
8171017
const consolidationTx = {

0 commit comments

Comments
 (0)