Skip to content

Commit c23aad2

Browse files
Copilot0xrinegade
andcommitted
Implement comprehensive code review improvements: address validation, BigNumber precision, storage abstraction, quote refresh API, and robust error handling
Co-authored-by: 0xrinegade <[email protected]>
1 parent bdd5864 commit c23aad2

File tree

10 files changed

+579
-74
lines changed

10 files changed

+579
-74
lines changed

__tests__/bridge/cross-chain.test.ts

Lines changed: 79 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ describe('Cross-Chain Payment Functionality', () => {
4545
destinationNetwork: SVMNetwork.SOLANA,
4646
recipient: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263',
4747
amount: '100',
48-
token: '0xA0b86a33E6441c4d0C85c81a1a4e18a3f3F3f77f', // USDC on Ethereum
48+
token: '0xa0B86a33E6441c4D0c85C81a1a4E18A3f3f3F77F', // USDC on Ethereum
4949
bridge: 'wormhole',
5050
label: 'Test Payment',
5151
message: 'Cross-chain test',
@@ -56,7 +56,7 @@ describe('Cross-Chain Payment Functionality', () => {
5656
expect(request.sourceNetwork).toBe(EVMNetwork.ETHEREUM);
5757
expect(request.destinationNetwork).toBe(SVMNetwork.SOLANA);
5858
expect(request.amount).toBe('100');
59-
expect(request.token).toBe('0xA0b86a33E6441c4d0C85c81a1a4e18a3f3F3f77f');
59+
expect(request.token).toBe('0xa0B86a33E6441c4D0c85C81a1a4E18A3f3f3F77F');
6060
expect(request.bridge).toBe('wormhole');
6161
});
6262
});
@@ -67,7 +67,7 @@ describe('Cross-Chain Payment Functionality', () => {
6767
const supported = wormholeAdapter.supportsTransfer(
6868
EVMNetwork.ETHEREUM,
6969
SVMNetwork.SOLANA,
70-
'0xA0b86a33E6441c4d0C85c81a1a4e18a3f3F3f77f' // USDC
70+
'0xa0B86a33E6441c4D0c85C81a1a4E18A3f3f3F77F' // USDC
7171
);
7272
expect(supported).toBe(true);
7373
});
@@ -89,7 +89,7 @@ describe('Cross-Chain Payment Functionality', () => {
8989
destinationNetwork: SVMNetwork.SOLANA,
9090
recipient: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263',
9191
amount: '100',
92-
token: '0xA0b86a33E6441c4d0C85c81a1a4e18a3f3F3f77f'
92+
token: '0xa0B86a33E6441c4D0c85C81a1a4E18A3f3f3F77F'
9393
};
9494

9595
const quote = await wormholeAdapter.quote(request);
@@ -107,7 +107,7 @@ describe('Cross-Chain Payment Functionality', () => {
107107
const supported = allbridgeAdapter.supportsTransfer(
108108
EVMNetwork.ETHEREUM,
109109
SVMNetwork.SOLANA,
110-
'0xA0b86a33E6441c4d0C85c81a1a4e18a3f3F3f77f' // USDC
110+
'0xa0B86a33E6441c4D0c85C81a1a4E18A3f3f3F77F' // USDC
111111
);
112112
expect(supported).toBe(true);
113113
});
@@ -120,7 +120,7 @@ describe('Cross-Chain Payment Functionality', () => {
120120
destinationNetwork: SVMNetwork.SOLANA,
121121
recipient: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263',
122122
amount: '100',
123-
token: '0xA0b86a33E6441c4d0C85c81a1a4e18a3f3F3f77f'
123+
token: '0xa0B86a33E6441c4D0c85C81a1a4E18A3f3f3F77F'
124124
};
125125

126126
const [wormholeQuote, allbridgeQuote] = await Promise.all([
@@ -140,7 +140,7 @@ describe('Cross-Chain Payment Functionality', () => {
140140
const compatibleAdapters = BridgeAdapterFactory.findCompatibleAdapters(
141141
EVMNetwork.ETHEREUM,
142142
SVMNetwork.SOLANA,
143-
'0xA0b86a33E6441c4d0C85c81a1a4e18a3f3F3f77f' // USDC
143+
'0xa0B86a33E6441c4D0c85C81a1a4E18A3f3f3F77F' // USDC
144144
);
145145

146146
expect(compatibleAdapters).toHaveLength(2); // Wormhole and Allbridge
@@ -168,7 +168,7 @@ describe('Cross-Chain Payment Functionality', () => {
168168
destinationNetwork: SVMNetwork.SOLANA,
169169
recipient: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263',
170170
amount: '100',
171-
token: '0xA0b86a33E6441c4d0C85c81a1a4e18a3f3F3f77f'
171+
token: '0xa0B86a33E6441c4D0c85C81a1a4E18A3f3f3F77F'
172172
};
173173

174174
expect(() => validateCrossChainRequest(request)).not.toThrow();
@@ -182,7 +182,7 @@ describe('Cross-Chain Payment Functionality', () => {
182182
destinationNetwork: SVMNetwork.SOLANA,
183183
recipient: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263',
184184
amount: '100',
185-
token: '0xA0b86a33E6441c4d0C85c81a1a4e18a3f3F3f77f'
185+
token: '0xa0B86a33E6441c4D0c85C81a1a4E18A3f3f3F77F'
186186
};
187187

188188
expect(() => validateCrossChainRequest(request)).toThrow('Source and destination networks cannot be the same');
@@ -196,7 +196,7 @@ describe('Cross-Chain Payment Functionality', () => {
196196
destinationNetwork: SVMNetwork.SOLANA,
197197
recipient: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263',
198198
amount: '100',
199-
token: '0xA0b86a33E6441c4d0C85c81a1a4e18a3f3F3f77f'
199+
token: '0xa0B86a33E6441c4D0c85C81a1a4E18A3f3f3F77F'
200200
};
201201

202202
const result = await getBestBridgeQuote(request);
@@ -219,7 +219,7 @@ describe('Cross-Chain Payment Functionality', () => {
219219
destinationNetwork: SVMNetwork.SOLANA,
220220
recipient: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263',
221221
amount: '100',
222-
token: '0xA0b86a33E6441c4d0C85c81a1a4e18a3f3F3f77f'
222+
token: '0xa0B86a33E6441c4D0c85C81a1a4E18A3f3f3F77F'
223223
};
224224

225225
const result = await paymentManager.executePayment(request);
@@ -238,7 +238,7 @@ describe('Cross-Chain Payment Functionality', () => {
238238
destinationNetwork: SVMNetwork.SOLANA,
239239
recipient: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263',
240240
amount: '100',
241-
token: '0xA0b86a33E6441c4d0C85c81a1a4e18a3f3F3f77f'
241+
token: '0xa0B86a33E6441c4D0c85C81a1a4E18A3f3f3F77F'
242242
};
243243

244244
const result = await paymentManager.executePayment(request);
@@ -250,4 +250,71 @@ describe('Cross-Chain Payment Functionality', () => {
250250
expect(status?.bridgeUsed).toBe('allbridge');
251251
});
252252
});
253+
254+
describe('Negative Test Cases', () => {
255+
describe('Unsupported Token Quotes', () => {
256+
it('should throw error for unsupported token in Wormhole', async () => {
257+
const request: CrossChainTransferRequest = {
258+
type: RequestType.CROSS_CHAIN_TRANSFER,
259+
network: SVMNetwork.SOLANA,
260+
sourceNetwork: EVMNetwork.ETHEREUM,
261+
destinationNetwork: SVMNetwork.SOLANA,
262+
recipient: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263',
263+
amount: '100',
264+
token: '0x1234567890123456789012345678901234567890' // Unsupported token
265+
};
266+
267+
await expect(wormholeAdapter.quote(request)).rejects.toThrow(
268+
'Wormhole does not support transfer from ethereum to solana for token 0x1234567890123456789012345678901234567890'
269+
);
270+
});
271+
272+
it('should throw error for unsupported token in Allbridge', async () => {
273+
const request: CrossChainTransferRequest = {
274+
type: RequestType.CROSS_CHAIN_TRANSFER,
275+
network: SVMNetwork.SOLANA,
276+
sourceNetwork: EVMNetwork.ETHEREUM,
277+
destinationNetwork: SVMNetwork.SOLANA,
278+
recipient: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263',
279+
amount: '100',
280+
token: '0x9876543210987654321098765432109876543210' // Unsupported token
281+
};
282+
283+
await expect(allbridgeAdapter.quote(request)).rejects.toThrow(
284+
'Allbridge does not support transfer from ethereum to solana for token 0x9876543210987654321098765432109876543210'
285+
);
286+
});
287+
288+
it('should return null from getBestBridgeQuote for unsupported token', async () => {
289+
const request: CrossChainTransferRequest = {
290+
type: RequestType.CROSS_CHAIN_TRANSFER,
291+
network: SVMNetwork.SOLANA,
292+
sourceNetwork: EVMNetwork.ETHEREUM,
293+
destinationNetwork: SVMNetwork.SOLANA,
294+
recipient: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263',
295+
amount: '100',
296+
token: '0x1111111111111111111111111111111111111111' // Unsupported token
297+
};
298+
299+
const result = await getBestBridgeQuote(request);
300+
expect(result).toBeNull();
301+
});
302+
303+
it('should throw error when no compatible bridges found', async () => {
304+
const request: CrossChainTransferRequest = {
305+
type: RequestType.CROSS_CHAIN_TRANSFER,
306+
network: SVMNetwork.SOLANA,
307+
sourceNetwork: EVMNetwork.ETHEREUM,
308+
destinationNetwork: SVMNetwork.SOLANA,
309+
recipient: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263',
310+
amount: '100',
311+
token: '0x2222222222222222222222222222222222222222' // Unsupported token
312+
};
313+
314+
await expect(paymentManager.executePayment(request)).rejects.toThrow(
315+
'No compatible bridges found for this transfer'
316+
);
317+
});
318+
});
319+
});
253320
});

package-lock.json

Lines changed: 118 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,12 @@
5555
"@walletconnect/solana-adapter": "^0.0.7",
5656
"@walletconnect/universal-provider": "^2.19.2",
5757
"axios": "^1.5.1",
58+
"bignumber.js": "^9.3.0",
5859
"bs58": "^6.0.0",
5960
"commander": "^11.0.0",
6061
"crypto": "^1.0.1",
61-
"crypto-js": "^4.2.0"
62+
"crypto-js": "^4.2.0",
63+
"ethers": "^6.15.0"
6264
},
6365
"peerDependencies": {
6466
"@angular/core": "^13.0.0 || ^14.0.0 || ^15.0.0",

src/bridge/adapter.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
SupportedNetwork,
1616
SVMNetwork
1717
} from '../core/types';
18+
import { areTokensEquivalent } from './utils';
1819

1920
/**
2021
* Abstract base class for bridge adapters
@@ -80,13 +81,18 @@ export abstract class BaseBridgeAdapter implements BridgeAdapter {
8081
return false;
8182
}
8283

83-
// Check if token is supported on source network
84+
// Check if token is supported on source network using normalization/aliasing
8485
const sourceTokens = this.info.supportedTokens[sourceNetwork];
85-
if (!sourceTokens || !sourceTokens.includes(token)) {
86+
if (!sourceTokens) {
8687
return false;
8788
}
8889

89-
return true;
90+
// Use token equivalence check instead of strict equality
91+
const isTokenSupported = sourceTokens.some(supportedToken =>
92+
areTokensEquivalent(token, supportedToken, sourceNetwork)
93+
);
94+
95+
return isTokenSupported;
9096
}
9197
}
9298

0 commit comments

Comments
 (0)