Skip to content

Commit f9207ad

Browse files
fix(sdk-coin-sol): verify ata address on consolidation
TICKET: WP-3968
1 parent 0ae8dd0 commit f9207ad

File tree

2 files changed

+207
-1
lines changed

2 files changed

+207
-1
lines changed

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

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,8 +322,30 @@ export class Sol extends BaseCoin {
322322
//verify funds are sent to walletRootAddress for a consolidation
323323
const filteredOutputs = explainedTx.outputs.map((output) => _.pick(output, ['address', 'amount', 'tokenName']));
324324

325+
// Cache to store already derived ATA addresses
326+
const ataAddressCache: Record<string, string> = {};
327+
325328
for (const output of filteredOutputs) {
326-
if (output.address !== walletRootAddress) {
329+
if (output.tokenName) {
330+
// Check cache first before deriving ATA address
331+
if (!ataAddressCache[output.tokenName]) {
332+
const tokenMintAddress = getSolTokenFromTokenName(output.tokenName);
333+
if (tokenMintAddress?.tokenAddress && tokenMintAddress?.programId) {
334+
ataAddressCache[output.tokenName] = await getAssociatedTokenAccountAddress(
335+
tokenMintAddress.tokenAddress,
336+
walletRootAddress as string,
337+
true,
338+
tokenMintAddress.programId
339+
);
340+
} else {
341+
throw new Error(`Unable to get token information for ${output.tokenName}`);
342+
}
343+
}
344+
345+
if (ataAddressCache[output.tokenName] !== output.address) {
346+
throw new Error('tx outputs does not match with expected address');
347+
}
348+
} else if (output.address !== walletRootAddress) {
327349
throw new Error('tx outputs does not match with expected address');
328350
}
329351
}

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

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3020,5 +3020,189 @@ describe('SOL:', function () {
30203020
assert.fail('Transaction should pass verification');
30213021
}
30223022
});
3023+
3024+
it('should verify a token consolidation transaction', async () => {
3025+
const consolidationTx = {
3026+
txRequestId: '4fdd0cae-2563-43b1-b5cf-94865158ca10',
3027+
walletId: '63068ed4efa63a000877f02fd4b0fa6d',
3028+
txHex:
3029+
'02b7c2c7829eded4e8f947c90ed3b9afce71f616eb47dfcfbf4b765778149060013acb33b9f67fdd9c2512f48fac4e4c049eab93829b69404f3bd166fe3242c90700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020104096da690bd558fd8634ac14f1645d8095afd0caea5953578c596e3c0dea38305ee7298bfac55101f177735659d42ed6be890ef3a1d204d9e33f32e24c5635327ca66d1fe00826e5a4f759f87b279c1aee19cce5301af4ed66ae17db48b201ed6c2a0e8a28bf565627f1ab8a34b1a95ee1b0a2a39084f1f0e2acb1c394b20185d8e0b22657c8d9c4ce5f6495efb6410c199011530f90e3ab9d8d1e4206f9ae0ffeb0000000000000000000000000000000000000000000000000000000000000000c5f9fb32f49111ab20c33f2598fc836c113e291881ac21ee29169394011244e406a7d517192c568ee08a845f73d29788cf035c3145b21ab344d8062ea940000006ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9de13c74d2b4d948e1608ea6eebdafe75bc2f995aad11b21d1e2c94f2a2d12f6802050303070004040000000804020604010a0ce0076bb20400000006',
3030+
feeInfo: {
3031+
fee: 10000,
3032+
feeString: '10000',
3033+
},
3034+
txInfo: {
3035+
inputs: [
3036+
{
3037+
address: '8iLa26KSbdpBUzNK7uYq8FvyuyA5h4k4erDHsDcPbHus',
3038+
value: 2.0173228e10,
3039+
valueString: '20173228000',
3040+
},
3041+
{
3042+
address: '8P2kX7Tyh9eS3RKdaBhqbEtQGAX58DXzL7mhDQABGX2d',
3043+
value: 10000,
3044+
valueString: '10000',
3045+
},
3046+
],
3047+
minerFee: '10000',
3048+
outputs: [
3049+
{
3050+
address: 'HBxZShcE86UMmF93KUM8eWJKqeEXi5cqWCLYLMMhqMYm',
3051+
coinName: 'sol:wif',
3052+
enterprise: {
3053+
$oid: '5553ba8ae7a5c77006719661',
3054+
},
3055+
enterprises: [
3056+
{
3057+
$oid: '5553ba8ae7a5c77006719661',
3058+
},
3059+
],
3060+
value: 2.0173228e10,
3061+
valueString: '20173228000',
3062+
wallet: {
3063+
$oid: '62f4c3720d92c50008257eb5',
3064+
},
3065+
walletType: 'hot',
3066+
wallets: [
3067+
{
3068+
$oid: '62f4c3720d92c50008257eb5',
3069+
},
3070+
],
3071+
},
3072+
],
3073+
payGoFee: '0',
3074+
spendAmount: '20173228000',
3075+
spendAmounts: [
3076+
{
3077+
amountString: '20173228000',
3078+
coinName: 'sol:wif',
3079+
},
3080+
],
3081+
type: 'Send',
3082+
},
3083+
consolidateId: '6712d7fda6de4906d658c04aebbf8f9b',
3084+
coin: 'tsol',
3085+
};
3086+
3087+
const mockedWallet: Partial<IWallet> = {
3088+
coinSpecific: () => {
3089+
const cs = {
3090+
rootAddress: 'HBxZShcE86UMmF93KUM8eWJKqeEXi5cqWCLYLMMhqMYm',
3091+
} as WalletCoinSpecific;
3092+
return cs;
3093+
},
3094+
};
3095+
3096+
try {
3097+
if (
3098+
!(await basecoin.verifyTransaction({
3099+
blockhash: '',
3100+
feePayer: '',
3101+
txParams: {},
3102+
txPrebuild: consolidationTx as unknown as TransactionPrebuild,
3103+
walletType: 'tss',
3104+
wallet: mockedWallet as IWallet,
3105+
verification: {
3106+
consolidationToBaseAddress: true,
3107+
},
3108+
}))
3109+
) {
3110+
assert.fail('Transaction should pass verification');
3111+
}
3112+
} catch (e) {
3113+
assert.fail('Transaction should pass verification');
3114+
}
3115+
});
3116+
3117+
it('should verify a spoofed token consolidation transaction', async () => {
3118+
const consolidationTx = {
3119+
txRequestId: '4fdd0cae-2563-43b1-b5cf-94865158ca10',
3120+
walletId: '63068ed4efa63a000877f02fd4b0fa6d',
3121+
txHex:
3122+
'02b7c2c7829eded4e8f947c90ed3b9afce71f616eb47dfcfbf4b765778149060013acb33b9f67fdd9c2512f48fac4e4c049eab93829b69404f3bd166fe3242c90700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020104096da690bd558fd8634ac14f1645d8095afd0caea5953578c596e3c0dea38305ee7298bfac55101f177735659d42ed6be890ef3a1d204d9e33f32e24c5635327ca66d1fe00826e5a4f759f87b279c1aee19cce5301af4ed66ae17db48b201ed6c2a0e8a28bf565627f1ab8a34b1a95ee1b0a2a39084f1f0e2acb1c394b20185d8e0b22657c8d9c4ce5f6495efb6410c199011530f90e3ab9d8d1e4206f9ae0ffeb0000000000000000000000000000000000000000000000000000000000000000c5f9fb32f49111ab20c33f2598fc836c113e291881ac21ee29169394011244e406a7d517192c568ee08a845f73d29788cf035c3145b21ab344d8062ea940000006ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9de13c74d2b4d948e1608ea6eebdafe75bc2f995aad11b21d1e2c94f2a2d12f6802050303070004040000000804020604010a0ce0076bb20400000006',
3123+
feeInfo: {
3124+
fee: 10000,
3125+
feeString: '10000',
3126+
},
3127+
txInfo: {
3128+
inputs: [
3129+
{
3130+
address: '8iLa26KSbdpBUzNK7uYq8FvyuyA5h4k4erDHsDcPbHus',
3131+
value: 2.0173228e10,
3132+
valueString: '20173228000',
3133+
},
3134+
{
3135+
address: '8P2kX7Tyh9eS3RKdaBhqbEtQGAX58DXzL7mhDQABGX2d',
3136+
value: 10000,
3137+
valueString: '10000',
3138+
},
3139+
],
3140+
minerFee: '10000',
3141+
outputs: [
3142+
{
3143+
address: 'HBxZShcE86UMmF93KUM8eWJKqeEXi5cqWCLYLMMhqMYm',
3144+
coinName: 'sol:wif',
3145+
enterprise: {
3146+
$oid: '5553ba8ae7a5c77006719661',
3147+
},
3148+
enterprises: [
3149+
{
3150+
$oid: '5553ba8ae7a5c77006719661',
3151+
},
3152+
],
3153+
value: 2.0173228e10,
3154+
valueString: '20173228000',
3155+
wallet: {
3156+
$oid: '62f4c3720d92c50008257eb5',
3157+
},
3158+
walletType: 'hot',
3159+
wallets: [
3160+
{
3161+
$oid: '62f4c3720d92c50008257eb5',
3162+
},
3163+
],
3164+
},
3165+
],
3166+
payGoFee: '0',
3167+
spendAmount: '20173228000',
3168+
spendAmounts: [
3169+
{
3170+
amountString: '20173228000',
3171+
coinName: 'sol:wif',
3172+
},
3173+
],
3174+
type: 'Send',
3175+
},
3176+
consolidateId: '6712d7fda6de4906d658c04aebbf8f9b',
3177+
coin: 'tsol',
3178+
};
3179+
3180+
const mockedWallet: Partial<IWallet> = {
3181+
coinSpecific: () => {
3182+
const cs = {
3183+
rootAddress: '8rQXeVEMrKvtWCEJirEM6cKYnbZuTqVTbqRPiMMAJ8R4',
3184+
} as WalletCoinSpecific;
3185+
return cs;
3186+
},
3187+
};
3188+
3189+
await assert.rejects(
3190+
async () =>
3191+
basecoin.verifyTransaction({
3192+
blockhash: '',
3193+
feePayer: '',
3194+
txParams: {},
3195+
txPrebuild: consolidationTx as unknown as TransactionPrebuild,
3196+
walletType: 'tss',
3197+
wallet: mockedWallet as IWallet,
3198+
verification: {
3199+
consolidationToBaseAddress: true,
3200+
},
3201+
}),
3202+
{
3203+
message: 'tx outputs does not match with expected address',
3204+
}
3205+
);
3206+
});
30233207
});
30243208
});

0 commit comments

Comments
 (0)