near-ca
Version:
An SDK for controlling Ethereum Accounts from a Near Account.
131 lines (130 loc) • 4.28 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.toPayload = toPayload;
exports.fromPayload = fromPayload;
exports.buildTxPayload = buildTxPayload;
exports.populateTx = populateTx;
exports.addSignature = addSignature;
exports.relaySignedTransaction = relaySignedTransaction;
exports.broadcastSignedTransaction = broadcastSignedTransaction;
const viem_1 = require("viem");
const network_1 = require("../network");
/**
* Converts a message hash to a payload array
*
* @param msgHash - The message hash to convert
* @returns Array of numbers representing the payload
* @throws Error if the payload length is not 32 bytes
*/
function toPayload(msgHash) {
const bytes = (0, viem_1.isBytes)(msgHash) ? msgHash : (0, viem_1.toBytes)(msgHash);
if (bytes.length !== 32) {
throw new Error(`Payload must have 32 bytes: ${msgHash}`);
}
return Array.from(bytes);
}
/**
* Converts a payload array back to a hexadecimal string
*
* @param payload - The payload array to convert
* @returns Hexadecimal string representation
* @throws Error if the payload length is not 32 bytes
*/
function fromPayload(payload) {
if (payload.length !== 32) {
throw new Error(`Payload must have 32 bytes: ${payload}`);
}
// Convert number[] back to Uint8Array
return (0, viem_1.toHex)(new Uint8Array(payload));
}
/**
* Builds a transaction payload from a serialized transaction
*
* @param serializedTx - The serialized transaction
* @returns Array of numbers representing the transaction payload
*/
function buildTxPayload(serializedTx) {
return toPayload((0, viem_1.keccak256)(serializedTx));
}
/**
* Populates a transaction with necessary data
*
* @param tx - The base transaction data
* @param from - The sender's address
* @param client - Optional public client
* @returns Complete transaction data
* @throws Error if chain IDs don't match
*/
async function populateTx(tx, from, client) {
const provider = client || network_1.Network.fromChainId(tx.chainId).client;
const chainId = await provider.getChainId();
if (chainId !== tx.chainId) {
// Can only happen when client is provided.
throw new Error(`client chainId=${chainId} mismatch with tx.chainId=${tx.chainId}`);
}
const transactionData = {
nonce: tx.nonce ?? (await provider.getTransactionCount({ address: from })),
account: from,
to: tx.to,
value: tx.value ?? 0n,
data: tx.data ?? "0x",
};
const [estimatedGas, { maxFeePerGas, maxPriorityFeePerGas }] = await Promise.all([
// Only estimate gas if not provided.
tx.gas || provider.estimateGas(transactionData),
provider.estimateFeesPerGas(),
]);
return {
...transactionData,
gas: estimatedGas,
maxFeePerGas,
maxPriorityFeePerGas,
chainId,
};
}
/**
* Adds a signature to a transaction
*
* @param params - Object containing transaction and signature
* @returns Serialized signed transaction
*/
function addSignature({ transaction, signature, }) {
const txData = (0, viem_1.parseTransaction)(transaction);
const signedTx = {
...signature,
...txData,
};
return (0, viem_1.serializeTransaction)(signedTx);
}
/**
* Relays a signed transaction to the Ethereum mempool
*
* @param serializedTransaction - The signed transaction to relay
* @param wait - Whether to wait for confirmation
* @returns Transaction hash
*/
async function relaySignedTransaction(serializedTransaction, wait = true) {
const tx = (0, viem_1.parseTransaction)(serializedTransaction);
const network = network_1.Network.fromChainId(tx.chainId);
if (wait) {
return network.client.sendRawTransaction({
serializedTransaction,
});
}
else {
network.client.sendRawTransaction({
serializedTransaction,
});
return (0, viem_1.keccak256)(serializedTransaction);
}
}
/**
* Broadcasts a signed transaction to the Ethereum mempool
*
* @param tx - The signed transaction to broadcast
* @returns Transaction hash
*/
async function broadcastSignedTransaction(tx) {
const signedTx = addSignature(tx);
return relaySignedTransaction(signedTx);
}