Skip to content

Commit 0b15751

Browse files
fix: overload getQuote method (#617)
* fix: overload getQuote method * chore: merge types for get quote --------- Co-authored-by: Slava <slava@interlay.io>
1 parent e6a977e commit 0b15751

File tree

2 files changed

+128
-73
lines changed

2 files changed

+128
-73
lines changed

sdk/src/gateway/client.ts

Lines changed: 77 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -127,82 +127,86 @@ export class GatewayApiClient {
127127
return Object.values(Chain);
128128
}
129129

130-
/**
131-
*
132-
* Get a quote from the Gateway API for swapping or staking BTC.
133-
*
134-
* @param params The parameters for the quote.
135-
*/
130+
async getQuote(params: {
131+
type: 'onramp';
132+
params: Optional<
133+
GatewayQuoteParams,
134+
'amount' | 'fromChain' | 'fromToken' | 'fromUserAddress' | 'toUserAddress'
135+
>;
136+
}): Promise<GatewayQuote & GatewayTokensInfo>;
137+
138+
async getQuote(params: {
139+
type: 'offramp';
140+
params: {
141+
tokenAddress: Address;
142+
amount: number;
143+
};
144+
}): Promise<OfframpQuote>;
136145

137-
async getQuote({
138-
type,
139-
params,
140-
}:
141-
| {
142-
type: 'onramp';
143-
params: Optional<
144-
GatewayQuoteParams,
145-
'amount' | 'fromChain' | 'fromToken' | 'fromUserAddress' | 'toUserAddress'
146-
>;
147-
}
148-
| {
149-
type: 'offramp';
150-
params: {
151-
tokenAddress: Address;
152-
amount: bigint;
153-
};
154-
}): Promise<(GatewayQuote & GatewayTokensInfo) | OfframpQuote> {
155-
if (type === 'onramp') {
156-
const isMainnet =
157-
params.toChain === ChainId.BOB ||
158-
(typeof params.toChain === 'string' && params.toChain.toLowerCase() === Chain.BOB);
159-
const isTestnet =
160-
params.toChain === ChainId.BOB_SEPOLIA ||
161-
(typeof params.toChain === 'string' && params.toChain.toLowerCase() === Chain.BOB_SEPOLIA);
162-
163-
const isInvalidNetwork = !isMainnet && !isTestnet;
164-
const isMismatchMainnet = isMainnet && this.chain !== Chain.BOB;
165-
const isMismatchTestnet = isTestnet && this.chain !== Chain.BOB_SEPOLIA;
166-
167-
// TODO: switch URL if `toChain` is different chain?
168-
if (isInvalidNetwork || isMismatchMainnet || isMismatchTestnet) {
169-
throw new Error('Invalid output chain');
170-
}
146+
async getQuote(
147+
params:
148+
| {
149+
type: 'onramp';
150+
params: Optional<
151+
GatewayQuoteParams,
152+
'amount' | 'fromChain' | 'fromToken' | 'fromUserAddress' | 'toUserAddress'
153+
>;
154+
}
155+
| {
156+
type: 'offramp';
157+
params: {
158+
tokenAddress: Address;
159+
amount: number;
160+
};
161+
}
162+
): Promise<(GatewayQuote & GatewayTokensInfo) | OfframpQuote> {
163+
if (params.type === 'onramp') {
164+
return this.getOnrampQuote(params.params);
165+
} else {
166+
return this.fetchOfframpQuote(params.params.tokenAddress, params.params.amount);
167+
}
168+
}
171169

172-
let strategyAddress: string | undefined;
170+
private async getOnrampQuote(
171+
params: Optional<GatewayQuoteParams, 'amount' | 'fromChain' | 'fromToken' | 'fromUserAddress' | 'toUserAddress'>
172+
): Promise<GatewayQuote & GatewayTokensInfo> {
173+
const isMainnet =
174+
params.toChain === ChainId.BOB ||
175+
(typeof params.toChain === 'string' && params.toChain.toLowerCase() === Chain.BOB);
176+
const isTestnet =
177+
params.toChain === ChainId.BOB_SEPOLIA ||
178+
(typeof params.toChain === 'string' && params.toChain.toLowerCase() === Chain.BOB_SEPOLIA);
173179

174-
const toToken = params.toToken.toLowerCase();
175-
const outputTokenAddress = getTokenAddress(this.chainId, toToken);
176-
if (params.strategyAddress?.startsWith('0x')) {
177-
strategyAddress = params.strategyAddress;
178-
}
180+
if (
181+
(!isMainnet && !isTestnet) ||
182+
(isMainnet && this.chain !== Chain.BOB) ||
183+
(isTestnet && this.chain !== Chain.BOB_SEPOLIA)
184+
) {
185+
throw new Error('Invalid output chain');
186+
}
179187

180-
const url = new URL(`${this.baseUrl}/quote/${outputTokenAddress}`);
181-
if (strategyAddress) {
182-
url.searchParams.append('strategy', `${strategyAddress}`);
183-
}
184-
const atomicAmount = params.amount;
185-
if (atomicAmount) {
186-
url.searchParams.append('satoshis', `${atomicAmount}`);
187-
}
188+
const toToken = params.toToken.toLowerCase();
189+
const outputTokenAddress = getTokenAddress(this.chainId, toToken);
190+
const strategyAddress = params.strategyAddress?.startsWith('0x') ? params.strategyAddress : undefined;
188191

189-
const response = await fetch(url, {
190-
headers: {
191-
'Content-Type': 'application/json',
192-
Accept: 'application/json',
193-
},
194-
});
192+
const url = new URL(`${this.baseUrl}/quote/${outputTokenAddress}`);
193+
if (strategyAddress) url.searchParams.append('strategy', strategyAddress);
194+
if (params.amount) url.searchParams.append('satoshis', `${params.amount}`);
195195

196-
const quote: GatewayQuote = await response.json();
197-
return {
198-
...quote,
199-
fee: quote.fee + (params.gasRefill || 0),
200-
baseToken: ADDRESS_LOOKUP[this.chainId][quote.baseTokenAddress],
201-
outputToken: quote.strategyAddress ? ADDRESS_LOOKUP[this.chainId][outputTokenAddress] : undefined,
202-
};
203-
} else {
204-
return this.fetchOfframpQuote(params.tokenAddress, params.amount);
205-
}
196+
const response = await fetch(url, {
197+
headers: {
198+
'Content-Type': 'application/json',
199+
Accept: 'application/json',
200+
},
201+
});
202+
203+
const quote: GatewayQuote = await response.json();
204+
return {
205+
...quote,
206+
fee: quote.fee + (params.gasRefill || 0),
207+
baseToken: ADDRESS_LOOKUP[this.chainId][quote.baseTokenAddress],
208+
outputToken: quote.strategyAddress ? ADDRESS_LOOKUP[this.chainId][outputTokenAddress] : undefined,
209+
};
206210
}
207211

208212
/**
@@ -264,7 +268,7 @@ export class GatewayApiClient {
264268
* @param amountInToken Amount specified in token decimals.
265269
* @returns Offramp quote details.
266270
*/
267-
async fetchOfframpQuote(token: string, amountInToken: bigint): Promise<OfframpQuote> {
271+
async fetchOfframpQuote(token: string, amountInToken: number): Promise<OfframpQuote> {
268272
const queryParams = new URLSearchParams({
269273
amountInWrappedToken: amountInToken.toString(),
270274
token,
@@ -322,7 +326,7 @@ export class GatewayApiClient {
322326
): Promise<OfframpCreateOrderParams> {
323327
const tokenAddress = getTokenAddress(this.chainId, params.fromToken.toLowerCase());
324328

325-
const offrampQuote: OfframpQuote = await this.fetchOfframpQuote(tokenAddress, BigInt(params.amount));
329+
const offrampQuote: OfframpQuote = await this.fetchOfframpQuote(tokenAddress, Number(params.amount));
326330

327331
// get btc script pub key
328332
let bitcoinNetwork = bitcoin.networks.regtest;
@@ -481,7 +485,7 @@ export class GatewayApiClient {
481485

482486
let offrampQuote: OfframpQuote;
483487
try {
484-
offrampQuote = await this.fetchOfframpQuote(token.toString(), amountInToken);
488+
offrampQuote = await this.fetchOfframpQuote(token.toString(), Number(amountInToken));
485489
} catch (err) {
486490
// Return false and 0n with an error message if fetching the quote fails
487491
return [false, 0n, `Error fetching offramp quote: ${err.message || err}`];

sdk/test/gateway.test.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,4 +904,55 @@ describe('Gateway Tests', () => {
904904
expect(getOnrampOrdersSpy).toHaveBeenCalledOnce();
905905
expect(getOfframpOrdersSpy).toHaveBeenCalledOnce();
906906
});
907+
908+
it('test to check getQuote types', async () => {
909+
const gatewaySDK = new GatewaySDK('mainnet');
910+
const mockQuote = {
911+
gatewayAddress: ZeroAddress,
912+
baseTokenAddress: TBTC_ADDRESS,
913+
dustThreshold: 1000,
914+
satoshis: 1000,
915+
fee: 10,
916+
bitcoinAddress: '',
917+
txProofDifficultyFactor: 3,
918+
strategyAddress: ZeroAddress,
919+
baseToken: TBTC,
920+
outputToken: TBTC,
921+
};
922+
nock(`${MAINNET_GATEWAY_BASE_URL}`).get(`/quote/${TBTC_ADDRESS}?satoshis=1000`).times(5).reply(200, mockQuote);
923+
const searchParams = new URLSearchParams({
924+
amountInWrappedToken: '1000',
925+
token: TBTC_ADDRESS,
926+
});
927+
nock(`${MAINNET_GATEWAY_BASE_URL}`).get(`/offramp-quote?${searchParams}`).reply(201, {
928+
amountLockInSat: 1000,
929+
feesInSat: 0,
930+
feeRate: 0,
931+
registryAddress: zeroAddress,
932+
});
933+
934+
const result_onramp = await gatewaySDK.getQuote({
935+
type: 'onramp',
936+
params: {
937+
toChain: 'BOB',
938+
toToken: TBTC_ADDRESS,
939+
toUserAddress: ZeroAddress,
940+
amount: 1000,
941+
},
942+
});
943+
944+
// Optionally, print keys or typeof each field
945+
console.log('Type keys offramp:', Object.keys(result_onramp));
946+
947+
const result_offramp = await gatewaySDK.getQuote({
948+
type: 'offramp',
949+
params: {
950+
tokenAddress: TBTC_ADDRESS as Address,
951+
amount: 1000,
952+
},
953+
});
954+
955+
// Optionally, print keys or typeof each field
956+
console.log('Type keys offramp:', Object.keys(result_offramp));
957+
});
907958
});

0 commit comments

Comments
 (0)