near-safe
Version:
An SDK for controlling Ethereum Smart Accounts via ERC4337 from a Near Account.
82 lines (81 loc) • 3.55 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MULTI_SEND_ABI = void 0;
exports.encodeMulti = encodeMulti;
exports.isMultisendTx = isMultisendTx;
exports.decodeMulti = decodeMulti;
const viem_1 = require("viem");
const types_1 = require("../types");
exports.MULTI_SEND_ABI = ["function multiSend(bytes memory transactions)"];
const MULTISEND_141 = "0x38869bf66a61cF6bDB996A6aE40D5853Fd43B526";
const MULTISEND_CALLONLY_141 = "0x9641d764fc13c8B624c04430C7356C1C7C8102e2";
/// Encodes the transaction as packed bytes of:
/// - `operation` as a `uint8` with `0` for a `call` or `1` for a `delegatecall` (=> 1 byte),
/// - `to` as an `address` (=> 20 bytes),
/// - `value` as a `uint256` (=> 32 bytes),
/// - length of `data` as a `uint256` (=> 32 bytes),
/// - `data` as `bytes`.
const encodeMetaTx = (tx) => (0, viem_1.encodePacked)(["uint8", "address", "uint256", "uint256", "bytes"], [
tx.operation || types_1.OperationType.Call,
tx.to,
BigInt(tx.value),
BigInt((0, viem_1.size)(tx.data)),
tx.data,
]);
const remove0x = (hexString) => hexString.slice(2);
// Encodes a batch of module transactions into a single multiSend module transaction.
// A module transaction is an object with fields corresponding to a Gnosis Safe's (i.e., Zodiac IAvatar's) `execTransactionFromModule` method parameters.
function encodeMulti(transactions, multiSendContractAddress = transactions.some((t) => t.operation === types_1.OperationType.DelegateCall)
? MULTISEND_141
: MULTISEND_CALLONLY_141) {
const encodedTransactions = "0x" + transactions.map(encodeMetaTx).map(remove0x).join("");
return {
operation: types_1.OperationType.DelegateCall,
to: multiSendContractAddress,
value: "0x00",
data: (0, viem_1.encodeFunctionData)({
abi: (0, viem_1.parseAbi)(exports.MULTI_SEND_ABI),
functionName: "multiSend",
args: [encodedTransactions],
}),
};
}
function isMultisendTx(args) {
const to = args[0].toLowerCase();
return (to === MULTISEND_141.toLowerCase() ||
to === MULTISEND_CALLONLY_141.toLowerCase());
}
function unpack(packed, startIndex) {
// read operation from first 8 bits (= 2 hex digits)
const operation = parseInt(packed.substring(startIndex, startIndex + 2), 16);
// the next 40 characters are the to address
const to = (0, viem_1.getAddress)(`0x${packed.substring(startIndex + 2, startIndex + 42)}`);
// then comes the uint256 value (= 64 hex digits)
const value = (0, viem_1.toHex)(BigInt(`0x${packed.substring(startIndex + 42, startIndex + 106)}`));
// and the uint256 data length (= 64 hex digits)
const hexDataLength = parseInt(packed.substring(startIndex + 106, startIndex + 170), 16);
const endIndex = startIndex + 170 + hexDataLength * 2; // * 2 because each hex item is represented with 2 digits
const data = `0x${packed.substring(startIndex + 170, endIndex)}`;
return {
operation,
to,
value,
data,
endIndex,
};
}
function decodeMulti(data) {
const tx = (0, viem_1.decodeFunctionData)({
abi: (0, viem_1.parseAbi)(exports.MULTI_SEND_ABI),
data,
});
const [transactionsEncoded] = tx.args;
const result = [];
let startIndex = 2; // skip over 0x
while (startIndex < transactionsEncoded.length) {
const { endIndex, ...tx } = unpack(transactionsEncoded, startIndex);
result.push(tx);
startIndex = endIndex;
}
return result;
}