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
21 changes: 17 additions & 4 deletions modules/sdk-coin-ada/src/ada.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
SignedTransaction,
SignTransactionOptions as BaseSignTransactionOptions,
TransactionExplanation,
VerifyAddressOptions,
VerifyTransactionOptions,
EDDSAMethods,
EDDSAMethodTypes,
Expand All @@ -32,6 +31,8 @@ import {
MultisigType,
multisigTypes,
AuditDecryptedKeyParams,
extractCommonKeychain,
TssVerifyAddressOptions,
} from '@bitgo/sdk-core';
import { KeyPair as AdaKeyPair, Transaction, TransactionBuilderFactory, Utils } from './lib';
import { BaseCoin as StaticsBaseCoin, CoinFamily, coins } from '@bitgo/statics';
Expand Down Expand Up @@ -161,12 +162,24 @@ export class Ada extends BaseCoin {
return true;
}

async isWalletAddress(params: VerifyAddressOptions): Promise<boolean> {
const { address } = params;
async isWalletAddress(params: TssVerifyAddressOptions): Promise<boolean> {
const { address, keychains, index } = params;
if (!this.isValidAddress(address)) {
throw new InvalidAddressError(`Invalid Cardano Address: ${address}`);
}
return true;

const indexNumber = Number(index);
if (isNaN(indexNumber)) {
throw new Error('Invalid index. index must be a number.');
}

const commonKeychain = extractCommonKeychain(keychains);
const { address: derivedAddress } = await this.getAdaAddressAndAccountId({
bitgoKey: commonKeychain,
index: indexNumber,
});

return address === derivedAddress;
}

/** @inheritDoc */
Expand Down
200 changes: 200 additions & 0 deletions modules/sdk-coin-ada/test/unit/ada.ts
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,206 @@ describe('ADA', function () {
});
});

describe('Verify wallet address (isWalletAddress):', () => {
const commonKeychain =
'ed312d0db4615688219c43231eb4b98d5883c0b44bcfef1956290555995ad68ef7c22917b4a8b69183864b83cc7028655cd7a70ef76d6948d809a15050054840';

it('should verify a valid wallet address at index 0', async function () {
const keychains = [
{
id: '1',
commonKeychain: commonKeychain,
type: 'tss',
source: 'user',
},
{
id: '2',
commonKeychain: commonKeychain,
type: 'tss',
source: 'backup',
},
{
id: '3',
commonKeychain: commonKeychain,
type: 'tss',
source: 'bitgo',
},
];

const address =
'addr_test1qzvmazmpgfhjyppwlsw29zjjwazcsfk62z9zv5vsv24p0wyeh69kzsn0ygzzalqu5299ya693qnd55y2yegeqc42z7uq0ge2pq';
const isValid = await basecoin.isWalletAddress({
address,
keychains,
index: 0,
});

isValid.should.equal(true);
});

it('should fail to verify an address with wrong index', async function () {
const keychains = [
{
id: '1',
commonKeychain: commonKeychain,
type: 'tss' as const,
source: 'user' as const,
},
{
id: '2',
commonKeychain: commonKeychain,
type: 'tss' as const,
source: 'backup' as const,
},
{
id: '3',
commonKeychain: commonKeychain,
type: 'tss' as const,
source: 'bitgo' as const,
},
];

const isValid = await basecoin.isWalletAddress({
address:
'addr_test1qzvmazmpgfhjyppwlsw29zjjwazcsfk62z9zv5vsv24p0wyeh69kzsn0ygzzalqu5299ya693qnd55y2yegeqc42z7uq0ge2pq',
keychains,
index: 2,
});

isValid.should.equal(false);
});

it('should fail to verify a random address not from wallet', async function () {
const keychains = [
{
id: '1',
commonKeychain: commonKeychain,
type: 'tss' as const,
source: 'user' as const,
},
{
id: '2',
commonKeychain: commonKeychain,
type: 'tss' as const,
source: 'backup' as const,
},
{
id: '3',
commonKeychain: commonKeychain,
type: 'tss' as const,
source: 'bitgo' as const,
},
];

// Use a random valid ADA address not from this wallet
const randomAddress = 'addr_test1vr8rakm66rcfv4fcxqykg5lf0yv7lsyk9mvapx369jpvtcgfcuk7f';

const isValid = await basecoin.isWalletAddress({
address: randomAddress,
keychains,
index: 0,
});

isValid.should.equal(false);
});

it('should throw error for invalid address format', async function () {
const keychains = [
{
id: '1',
commonKeychain: commonKeychain,
type: 'tss' as const,
source: 'user' as const,
},
{
id: '2',
commonKeychain: commonKeychain,
type: 'tss' as const,
source: 'backup' as const,
},
{
id: '3',
commonKeychain: commonKeychain,
type: 'tss' as const,
source: 'bitgo' as const,
},
];

const invalidAddress = 'not_a_valid_address';

await basecoin
.isWalletAddress({
address: invalidAddress,
keychains,
index: 0,
})
.should.be.rejectedWith('Invalid Cardano Address: not_a_valid_address');
});

it('should throw error when keychains are missing', async function () {
const address =
'addr_test1qzvmazmpgfhjyppwlsw29zjjwazcsfk62z9zv5vsv24p0wyeh69kzsn0ygzzalqu5299ya693qnd55y2yegeqc42z7uq0ge2pq';

await basecoin
.isWalletAddress({
address,
keychains: [],
index: 0,
})
.should.be.rejectedWith('missing required param keychains');
});

it('should throw error when commonKeychain is missing', async function () {
const keychains = [
{
id: '1',
type: 'tss' as const,
source: 'user' as const,
// commonKeychain is missing
},
];

const address =
'addr_test1qzvmazmpgfhjyppwlsw29zjjwazcsfk62z9zv5vsv24p0wyeh69kzsn0ygzzalqu5299ya693qnd55y2yegeqc42z7uq0ge2pq';

await basecoin
.isWalletAddress({
address,
keychains,
index: 0,
})
.should.be.rejectedWith('missing required param commonKeychain');
});

it('should throw error when keychains have mismatched commonKeychains', async function () {
const keychains = [
{
id: '1',
commonKeychain: commonKeychain,
type: 'tss' as const,
source: 'user' as const,
},
{
id: '2',
commonKeychain: 'differentKeychain1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
type: 'tss' as const,
source: 'backup' as const,
},
];

const address =
'addr_test1qzvmazmpgfhjyppwlsw29zjjwazcsfk62z9zv5vsv24p0wyeh69kzsn0ygzzalqu5299ya693qnd55y2yegeqc42z7uq0ge2pq';

await basecoin
.isWalletAddress({
address,
keychains,
index: 0,
})
.should.be.rejectedWith('all keychains must have the same commonKeychain for MPC coins');
});
});

describe('Verify token consolidation transaction:', () => {
it('should fail to verify a spoofed token consolidation transaction with incorrect address', async () => {
const consolidationTx = {
Expand Down