@stable-io/cctp-sdk-cctpr-evm
Version:
EVM support for the CCTPR corridor of the CCTP SDK
90 lines • 4.26 kB
JavaScript
// Copyright (c) 2025 Stable Technologies Inc
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
import * as cctpr from "@stable-io/cctp-sdk-cctpr-definitions";
import { duration, v1, v2, genericGasToken } from "@stable-io/cctp-sdk-definitions";
import { assertDistinct, assertEqual } from "@stable-io/utils";
import { CctpR as CctpRContract } from "./contractSdk/index.js";
async function getFastCost(network, source, destination, corridor) {
const fastBurnDestination = corridor === "avaxHop" ? "Avalanche" : destination;
const { minimumFee } = await v2.fetchFastBurnFeeFactory(network)(source, fastBurnDestination);
return minimumFee;
}
function getSensibleCorridors(network, source, destination) {
const universalCorridors = ["v1"];
return !v2.isSupportedDomain(network)(source) || v2.isFastDomain(source)
? universalCorridors
: [
...universalCorridors,
(v2.isSupportedDomain(network)(destination)
? "v2Direct"
: "avaxHop"),
];
}
const calculateSpeed = (network, source, destination, corridor) => {
return duration((() => {
switch (corridor) {
case "v1":
return v1.attestationTimeEstimates[network][source];
case "v2Direct":
return v2.attestationTimeEstimates[network][source];
case "avaxHop":
return v2.attestationTimeEstimates[network][source]
+ cctpr.relayOverheadOf[network]["Avalanche"]
+ v1.attestationTimeEstimates[network]["Avalanche"];
default:
throw new Error("Invalid corridor");
}
})() + cctpr.relayOverheadOf[network][destination], "sec");
};
async function getCorridorStats(network, cctprContract, destination, corridors, gasDropoff) {
const gasDropoffRequest = genericGasToken(gasDropoff ? gasDropoff.toUnit("human") : 0);
const gasDropoffLimit = genericGasToken(cctpr.gasDropoffLimitOf[network][destination]);
if (gasDropoffRequest.gt(gasDropoffLimit))
throw new Error("Gas Drop Off Limit Exceeded");
const source = cctprContract.client.domain;
const fastCostsPromise = Promise.all(corridors.map(corridor => corridor === "v1"
? undefined
: getFastCost(network, source, destination, corridor)));
const variants = ["inUsdc", "inGasToken"];
const quoteRelays = corridors.flatMap(corridor => variants.map(variant => ({
quoteRelay: variant,
destinationDomain: destination,
corridor,
gasDropoff: gasDropoffRequest,
})));
const allQuotesPromise = cctprContract.quoteOnChainRelay(quoteRelays);
const [fastCosts, allQuotes,] = await Promise.all([fastCostsPromise, allQuotesPromise]);
assertEqual(allQuotes.length, corridors.length * variants.length, "Invalid number of quotes");
const stats = corridors.map((corridor, i) => {
const quotesIndex = i * variants.length;
const [usdcCost, gasCost] = allQuotes.slice(quotesIndex, quotesIndex + variants.length);
const costWithRelay = { relay: [usdcCost, gasCost] };
const fastCost = fastCosts[i];
const cost = (fastCost ? { ...costWithRelay, fast: fastCost } : costWithRelay);
const transferTime = calculateSpeed(network, source, destination, corridor);
return {
corridor,
cost,
transferTime,
};
});
return [...stats];
}
export const getCorridors = () => async function (client, destination, gasDropoff) {
const network = client.network;
const source = client.domain;
assertDistinct(source, destination);
const corridors = getSensibleCorridors(network, source, destination);
const cctprContract = new CctpRContract(client);
const [{ allowance: fastBurnAllowance }, stats] = await Promise.all([
v2.fetchFastBurnAllowanceFactory(network)(),
getCorridorStats(network, cctprContract, destination, corridors, gasDropoff),
]);
return {
fastBurnAllowance,
stats,
};
};
//# sourceMappingURL=getCorridors.js.map