@f5i23q999d/cow-sdk
Version:
<p align="center"> <img width="400" src="https://github.com/cowprotocol/cow-sdk/raw/main/docs/images/CoW.png" /> </p>
149 lines • 6.29 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AcrossApi = void 0;
const log_1 = require("../../../common/utils/log.js");
const ACROSS_API_URL = 'https://app.across.to/api';
class AcrossApi {
options;
constructor(options = {}) {
this.options = options;
}
/**
* Retrieve available routes for transfers
*
* Returns available routes based on specified parameters. If no parameters are provided, available routes on all
* chains are returned.
*
* See https://docs.across.to/reference/api-reference#available-routes
*/
async getAvailableRoutes({ originChainId, originToken, destinationChainId, destinationToken, }) {
const params = {};
if (originChainId)
params.originChainId = originChainId;
if (originToken)
params.originToken = originToken;
if (destinationChainId)
params.destinationChainId = destinationChainId;
if (destinationToken)
params.destinationToken = destinationToken;
return this.fetchApi('/available-routes', params, isValidRoutes);
}
/**
* Retrieve suggested fee quote for a deposit.
*
* Returns suggested fees based inputToken+outputToken, originChainId, destinationChainId, and amount.
* Also includes data used to compute the fees.
*
* * See https://docs.across.to/reference/api-reference#suggested-fees
*/
async getSuggestedFees(request) {
const params = {
token: request.token,
originChainId: request.originChainId.toString(),
destinationChainId: request.destinationChainId.toString(),
amount: request.amount.toString(),
};
if (request.recipient) {
params.recipient = request.recipient;
}
// Get the quote from the Across API (see https://docs.across.to/reference/api-reference#suggested-fees)
// Example: https://app.across.to/api/suggested-fees?token=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913&originChainId=8453&destinationChainId=137&amount=100000000
//
// TODO: The API documented params don't match with the example above. Ideally I would use 'inputToken' and 'outputToken', but the example above uses 'token'. This will work for current implementation, since we bridge the canonical token, but this will need to be reviewed
// https://app.across.to/api/suggested-fees?inputToken=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913&originChainId=8453&destinationChainId=137&outputToken=0xc2132D05D31c914a87C6611C10748AEb04B58e8F&amount=100000000
const fees = await this.fetchApi('/suggested-fees', params, isValidSuggestedFeesResponse);
return fees;
}
async fetchApi(path, params, isValidResponse) {
const baseUrl = this.options.apiBaseUrl || ACROSS_API_URL;
const url = `${baseUrl}${path}?${new URLSearchParams(params).toString()}`;
(0, log_1.log)(`Fetching Across API: GET ${url}. Params: ${JSON.stringify(params)}`);
const response = await fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
if (!response.ok) {
const errorBody = await response.text();
throw new Error(`HTTP error! Status: ${response.status}, Body: ${errorBody}`);
}
// Validate the response
const json = await response.json();
if (isValidResponse) {
if (isValidResponse(json)) {
return json;
}
else {
throw new Error(`Invalid response for Across API call ${path}. The response doesn't pass the validation. Did the API change? Result: ${JSON.stringify(json)}`);
}
}
return json;
}
}
exports.AcrossApi = AcrossApi;
/**
* Validate the response from the Across API is a SuggestedFeesResponse
*
* @param response - The response from the Across API
* @returns True if the response is a SuggestedFeesResponse, false otherwise
*/
function isValidSuggestedFeesResponse(response) {
return (typeof response === 'object' &&
response !== null &&
'totalRelayFee' in response &&
isValidPctFee(response.totalRelayFee) &&
'relayerCapitalFee' in response &&
isValidPctFee(response.relayerCapitalFee) &&
'relayerGasFee' in response &&
isValidPctFee(response.relayerGasFee) &&
'lpFee' in response &&
isValidPctFee(response.lpFee) &&
'timestamp' in response &&
'isAmountTooLow' in response &&
'quoteBlock' in response &&
'spokePoolAddress' in response &&
'exclusiveRelayer' in response &&
'exclusivityDeadline' in response &&
'estimatedFillTimeSec' in response &&
'fillDeadline' in response &&
'limits' in response &&
isValidSuggestedFeeLimits(response.limits));
}
function isValidPctFee(pctFee) {
return typeof pctFee === 'object' && pctFee !== null && 'pct' in pctFee && 'total' in pctFee;
}
function isValidSuggestedFeeLimits(limits) {
return (typeof limits === 'object' &&
limits !== null &&
'minDeposit' in limits &&
'maxDeposit' in limits &&
'maxDepositInstant' in limits &&
'maxDepositShortDelay' in limits &&
'recommendedDepositInstant' in limits);
}
/**
* Validate the response from the Across API is an AvailableRoutesResponse
*
* @param response - The response from the Across API
* @returns True if the response is an AvailableRoutesResponse, false otherwise
*/
function isValidRoutes(response) {
// make sure the response is an array
if (!Array.isArray(response)) {
return false;
}
// make sure each item in the array is an AvailableRoutesResponseItem
return response.every((item) => isValidRoute(item));
}
function isValidRoute(item) {
return (typeof item === 'object' &&
item !== null &&
'originChainId' in item &&
'originToken' in item &&
'destinationChainId' in item &&
'destinationToken' in item &&
'originTokenSymbol' in item &&
'destinationTokenSymbol' in item);
}
//# sourceMappingURL=AcrossApi.js.map