@0xfacet/sdk
Version:
A toolkit for Facet blockchain integration.
103 lines (102 loc) • 4.34 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.sendRawFacetTransaction = void 0;
const viem_1 = require("viem");
const chains_1 = require("viem/chains");
const addresses_1 = require("../constants/addresses");
const viem_2 = require("../viem");
const calculateInputGasCost_1 = require("./calculateInputGasCost");
const computeFacetTransactionHash_1 = require("./computeFacetTransactionHash");
const getFctMintRate_1 = require("./getFctMintRate");
/**
* Sends a raw Facet transaction by preparing the transaction data and submitting it to L1.
*
* @param l1ChainId - The chain ID of the L1 network (1 for mainnet, 11155111 for Sepolia)
* @param account - The address of the account initiating the transaction
* @param params - Transaction parameters including to, value, and data
* @param sendL1Transaction - Function to send the L1 transaction and return the transaction hash
* @param l1RpcUrl - Optional L1 RPC URL
* @returns Object containing the L1 transaction hash, Facet transaction hash, FCT mint amount, and FCT mint rate
* @throws Error if L1 chain is invalid, account is missing, or L2 chain is not configured
*/
const sendRawFacetTransaction = async (l1ChainId, account, params, sendL1Transaction, l1RpcUrl) => {
if (l1ChainId !== 1 && l1ChainId !== 11_155_111) {
throw new Error("Invalid L1 chain");
}
if (!account) {
throw new Error("No account");
}
const facetPublicClient = (0, viem_1.createPublicClient)({
chain: l1ChainId === 1 ? viem_2.facetMainnet : viem_2.facetSepolia,
transport: (0, viem_1.http)(),
});
if (!facetPublicClient.chain) {
throw new Error("L2 chain not configured");
}
const [estimateGasRes, fctBalance, fctMintRate] = await Promise.all([
facetPublicClient.estimateGas({
account,
to: params.to,
value: params.value,
data: params.data,
stateOverride: [{ address: account, balance: viem_1.maxUint256 }],
}),
facetPublicClient.getBalance({
address: account,
}),
(0, getFctMintRate_1.getFctMintRate)(l1ChainId),
]);
const gasLimit = estimateGasRes;
const transactionData = [
(0, viem_1.toHex)(facetPublicClient.chain.id),
params.to ?? "0x",
params.value ? (0, viem_1.toHex)(params.value) : "0x",
gasLimit ? (0, viem_1.toHex)(gasLimit) : "0x",
params.data ?? "0x",
params.mineBoost ?? "0x",
];
const encodedTransaction = (0, viem_1.concatHex)([(0, viem_1.toHex)(70), (0, viem_1.toRlp)(transactionData)]);
const inputCost = (0, calculateInputGasCost_1.calculateInputGasCost)((0, viem_1.toBytes)(encodedTransaction));
const fctMintAmount = inputCost * fctMintRate;
// Call estimateGas again but with an accurate future balance
// This will allow it to correctly revert when necessary
await facetPublicClient.estimateGas({
account,
to: params.to,
value: params.value,
data: params.data,
stateOverride: [
{
address: account,
balance: fctBalance + fctMintAmount,
},
],
});
const l1Transaction = {
account,
to: addresses_1.FACET_INBOX_ADDRESS,
value: 0n,
data: encodedTransaction,
chainId: l1ChainId,
};
const l1TransportUrl = l1ChainId === 1
? "https://ethereum-rpc.publicnode.com"
: "https://ethereum-sepolia-rpc.publicnode.com";
const l1PublicClient = (0, viem_1.createPublicClient)({
chain: l1ChainId === 1 ? chains_1.mainnet : chains_1.sepolia,
transport: (0, viem_1.http)(l1RpcUrl || l1TransportUrl),
});
const estimateL1Gas = await l1PublicClient.estimateGas(l1Transaction);
const l1TransactionHash = await sendL1Transaction({
...l1Transaction,
gas: estimateL1Gas,
});
const facetTransactionHash = (0, computeFacetTransactionHash_1.computeFacetTransactionHash)(l1TransactionHash, account, params.to ?? "0x", params.value ?? 0n, params.data ?? "0x", gasLimit, fctMintAmount);
return {
l1TransactionHash,
facetTransactionHash,
fctMintAmount,
fctMintRate,
};
};
exports.sendRawFacetTransaction = sendRawFacetTransaction;