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
2 changes: 1 addition & 1 deletion sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@gobob/bob-sdk",
"version": "3.3.0",
"version": "3.3.1",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
Expand Down
5 changes: 5 additions & 0 deletions sdk/src/gateway/abi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ export const offrampCreateOrderCaller = [
type: 'address',
internalType: 'address',
},
{
name: 'orderOwner',
type: 'address',
internalType: 'address',
},
],
},
],
Expand Down
43 changes: 43 additions & 0 deletions sdk/src/gateway/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
OfframpRawOrder,
OfframpOrderStatus,
EnrichedToken,
OfframpLiquidity,
} from './types';
import { createBitcoinPsbt, getAddressInfo } from '../wallet';
import { SYMBOL_LOOKUP, ADDRESS_LOOKUP, getTokenDecimals } from './tokens';
Expand Down Expand Up @@ -200,6 +201,47 @@ export class GatewayApiClient {
return JSON.parse(await response.text()) as Address;
}

/**
* Fetches an offramp liquidity for the given token.
*
* @param token ERC20 token address.
* @returns Offramp liquidity details.
*/
async fetchOfframpLiquidity(token: string): Promise<OfframpLiquidity> {
let outputTokenAddress = '';
const toToken = token.toLowerCase();

if (isAddress(toToken)) {
outputTokenAddress = toToken;
} else if (SYMBOL_LOOKUP[this.chainId][toToken]) {
outputTokenAddress = SYMBOL_LOOKUP[this.chainId][toToken].address;
} else {
throw new Error('Unknown output token');
}

const response = await fetch(`${this.baseUrl}/offramp-liquidity/${outputTokenAddress}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
});

if (!response.ok) {
const errorData = await response.json().catch(() => null);
const errorMessage = errorData?.message || 'Failed to get offramp liquidity';
throw new Error(`Offramp liquidity API Error: ${errorMessage}`);
}

const rawLiquidity = await response.json();

return {
token: rawLiquidity.tokenAddress as Address,
maxOrderAmount: BigInt(rawLiquidity.maxOrderAmount),
totalOfframpLiquidity: BigInt(rawLiquidity.totalOfframpLiquidity),
};
}

/**
* Fetches an offramp quote for the given token and amount.
*
Expand Down Expand Up @@ -312,6 +354,7 @@ export class GatewayApiClient {
orderCreationDeadline: offrampQuote.deadline,
outputScript: receiverAddress,
token: offrampQuote.token,
orderOwner: params.fromUserAddress as Address,
},
],
};
Expand Down
12 changes: 12 additions & 0 deletions sdk/src/gateway/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,16 @@ export interface OfframpQuote {
token: Address;
}

/** @dev Offramp Available Liquidity */
export interface OfframpLiquidity {
/** @dev Token address used for payment */
token: Address;
/** @dev Max token amount a *single* order can be served with (in token decimals) */
maxOrderAmount: bigint;
/** @dev Total liquidity across all solver addresses (in token decimals) */
totalOfframpLiquidity: bigint;
}

/** @dev Params used for createOrder call on the off-ramp contract */
export type OfframpCreateOrderParams = {
quote: OfframpQuote;
Expand All @@ -390,6 +400,8 @@ export type OfframpCreateOrderParams = {
outputScript: string;
/** @dev Token to use for payment */
token: Address;
/** @dev EVM address of the user who can unlock the order or bump its fee */
orderOwner: Address;
},
];
};
Expand Down
27 changes: 27 additions & 0 deletions sdk/test/gateway.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,7 @@ describe('Gateway Tests', () => {
orderCreationDeadline: result.offrampArgs[0].orderCreationDeadline,
outputScript: '0x1600149d5e60f3b5cc2d246f990692ee4b267d1cd58477',
token: '0xda472456b1a6a2fc9ae7edb0e007064224d4284c',
orderOwner: '0xFAEe001465dE6D7E8414aCDD9eF4aC5A35B2B808',
});
});

Expand Down Expand Up @@ -676,4 +677,30 @@ describe('Gateway Tests', () => {
// Assert the result is true (claim delay has passed)
expect(result).toBe(true);
});

it('fetches the correct offramp liquidity', async () => {
const gatewaySDK = new GatewaySDK('signet');
const tokenAddress = '0x4496ebE7C8666a8103713EE6e0c08cA0cD25b888'.toLowerCase();
nock(SIGNET_GATEWAY_BASE_URL).persist().get(`/offramp-liquidity/${tokenAddress}`).reply(200, {
tokenAddress,
maxOrderAmount: '861588',
totalOfframpLiquidity: '861588',
});

const offrampLiquidityTokenAddressAsParam = await gatewaySDK.fetchOfframpLiquidity(tokenAddress);

expect(offrampLiquidityTokenAddressAsParam).toEqual({
token: tokenAddress,
maxOrderAmount: BigInt('861588'),
totalOfframpLiquidity: BigInt('861588'),
});

const offrampLiquidityTokenSymbolAsParam = await gatewaySDK.fetchOfframpLiquidity('bobBTC');

expect(offrampLiquidityTokenSymbolAsParam).toEqual({
token: tokenAddress,
maxOrderAmount: BigInt('861588'),
totalOfframpLiquidity: BigInt('861588'),
});
});
});
Loading