Skip to content

Commit 64a9760

Browse files
authored
feat: [WT-1660] Smart Checkout onRamp route calculator implementation (#881)
1 parent f710bce commit 64a9760

File tree

5 files changed

+396
-8
lines changed

5 files changed

+396
-8
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './onRampRoute';
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
import { BigNumber } from 'ethers';
2+
import { Environment } from '@imtbl/config';
3+
import { CheckoutConfiguration } from '../../../config';
4+
import {
5+
ChainId,
6+
FundingRouteType,
7+
ItemType,
8+
OnRampProvider,
9+
} from '../../../types';
10+
import { allowListCheckForOnRamp } from '../../allowList';
11+
import { onRampRoute } from './onRampRoute';
12+
import { BalanceERC20Requirement, BalanceERC721Requirement } from '../../balanceCheck/types';
13+
14+
jest.mock('../../allowList/allowListCheck');
15+
16+
describe('onRampRoute', () => {
17+
const config = new CheckoutConfiguration({
18+
baseConfig: { environment: Environment.SANDBOX },
19+
});
20+
21+
beforeEach(() => {
22+
(allowListCheckForOnRamp as jest.Mock).mockResolvedValue({
23+
[OnRampProvider.TRANSAK]: [
24+
{
25+
address: '0x65AA7a21B0f3ce9B478aAC3408fE75b423939b1F',
26+
name: 'Ethereum',
27+
symbol: 'ETH',
28+
decimals: 18,
29+
},
30+
],
31+
});
32+
});
33+
34+
it('should return the onRamp route if the ERC20 balance requirement is in the allowlist', async () => {
35+
const balanceRequirement: BalanceERC20Requirement = {
36+
type: ItemType.ERC20,
37+
required: {
38+
balance: BigNumber.from(10),
39+
formattedBalance: '10',
40+
token: {
41+
address: '0x65AA7a21B0f3ce9B478aAC3408fE75b423939b1F',
42+
name: 'Ethereum',
43+
symbol: 'ETH',
44+
decimals: 18,
45+
},
46+
},
47+
sufficient: false,
48+
current: {
49+
balance: BigNumber.from(0),
50+
formattedBalance: '0',
51+
token: {
52+
address: '0x65AA7a21B0f3ce9B478aAC3408fE75b423939b1F',
53+
name: 'Ethereum',
54+
symbol: 'ETH',
55+
decimals: 18,
56+
},
57+
},
58+
delta: {
59+
balance: BigNumber.from(10),
60+
formattedBalance: '10',
61+
},
62+
} as BalanceERC20Requirement;
63+
64+
const route = await onRampRoute(
65+
config,
66+
{
67+
onRamp: true,
68+
},
69+
balanceRequirement,
70+
);
71+
72+
expect(route)
73+
.toEqual({
74+
type: FundingRouteType.ONRAMP,
75+
chainId: ChainId.IMTBL_ZKEVM_TESTNET,
76+
asset: {
77+
balance: BigNumber.from(10),
78+
formattedBalance: '10',
79+
token: {
80+
address: '0x65AA7a21B0f3ce9B478aAC3408fE75b423939b1F',
81+
name: 'Ethereum',
82+
symbol: 'ETH',
83+
decimals: 18,
84+
},
85+
},
86+
});
87+
});
88+
89+
it('should return undefined if the ERC20 balance requirement is not in the allowlist', async () => {
90+
const balanceRequirement: BalanceERC20Requirement = {
91+
type: ItemType.ERC20,
92+
required: {
93+
balance: BigNumber.from(10),
94+
formattedBalance: '10',
95+
token: {
96+
address: '0x65AA7a21B0f3ce9B478aAC3408fE75b423939b1F',
97+
name: 'Ethereum',
98+
symbol: 'ETH',
99+
decimals: 18,
100+
},
101+
},
102+
sufficient: false,
103+
current: {
104+
balance: BigNumber.from(0),
105+
formattedBalance: '0',
106+
token: {
107+
address: '0x65AA7a21B0f3ce9B478aAC3408fE75b423939b1F',
108+
name: 'Ethereum',
109+
symbol: 'ETH',
110+
decimals: 18,
111+
},
112+
},
113+
delta: {
114+
balance: BigNumber.from(10),
115+
formattedBalance: '10',
116+
},
117+
} as BalanceERC20Requirement;
118+
119+
(allowListCheckForOnRamp as jest.Mock).mockResolvedValue({
120+
[OnRampProvider.TRANSAK]: [],
121+
});
122+
123+
const route = await onRampRoute(
124+
config,
125+
{
126+
onRamp: true,
127+
},
128+
balanceRequirement,
129+
);
130+
131+
expect(route).toBeUndefined();
132+
});
133+
134+
it('should return undefined if the balance requirement is an ERC721', async () => {
135+
const balanceRequirement: BalanceERC721Requirement = {
136+
type: ItemType.ERC721,
137+
required: {
138+
type: ItemType.ERC721,
139+
balance: BigNumber.from(1),
140+
formattedBalance: '1',
141+
id: '1',
142+
contractAddress: '0xADDRESS',
143+
},
144+
sufficient: false,
145+
current: {
146+
type: ItemType.ERC721,
147+
balance: BigNumber.from(0),
148+
formattedBalance: '0',
149+
id: '1',
150+
contractAddress: '0xADDRESS',
151+
},
152+
delta: {
153+
balance: BigNumber.from(1),
154+
formattedBalance: '1',
155+
},
156+
} as BalanceERC721Requirement;
157+
158+
(allowListCheckForOnRamp as jest.Mock).mockResolvedValue({
159+
[OnRampProvider.TRANSAK]: [],
160+
});
161+
162+
const route = await onRampRoute(
163+
config,
164+
{
165+
onRamp: true,
166+
},
167+
balanceRequirement,
168+
);
169+
170+
expect(route).toBeUndefined();
171+
});
172+
});
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { CheckoutConfiguration, getL2ChainId } from '../../../config';
2+
import { FundingRouteType, ItemType, RoutingOptionsAvailable } from '../../../types';
3+
import { BalanceRequirement } from '../../balanceCheck/types';
4+
import { FundingRouteStep } from '../types';
5+
import { allowListCheckForOnRamp } from '../../allowList';
6+
7+
export const onRampRoute = async (
8+
config: CheckoutConfiguration,
9+
availableRoutingOptions: RoutingOptionsAvailable,
10+
balanceRequirement: BalanceRequirement,
11+
): Promise<FundingRouteStep | undefined> => {
12+
if (balanceRequirement.type !== ItemType.ERC20 && balanceRequirement.type !== ItemType.NATIVE) return undefined;
13+
const requiredBalance = balanceRequirement.required;
14+
15+
let hasAllowList = false;
16+
const onRampProvidersAllowList = await allowListCheckForOnRamp(config, availableRoutingOptions);
17+
Object.values(onRampProvidersAllowList).forEach((onRampAllowList) => {
18+
if (onRampAllowList.length > 0 && !hasAllowList) {
19+
hasAllowList = !!onRampAllowList.find((token) => token.address === requiredBalance.token?.address);
20+
}
21+
});
22+
if (!hasAllowList) return undefined;
23+
24+
return {
25+
type: FundingRouteType.ONRAMP,
26+
chainId: getL2ChainId(config),
27+
asset: {
28+
balance: requiredBalance.balance,
29+
formattedBalance: requiredBalance.formattedBalance,
30+
token: {
31+
...requiredBalance.token,
32+
},
33+
},
34+
};
35+
};

0 commit comments

Comments
 (0)