UNPKG

@0xfutbol/id

Version:

React component library with shared providers for 0xFutbol ID

364 lines (363 loc) 14.4 kB
'use strict';var eth_sendRawTransaction=require('./eth_sendRawTransaction-BernmwlE.js'),index=require('./index-DwkZmKdT.js'),concatHex=require('./concat-hex-DJMxTlMl.js'),sha256$1=require('./sha256-CnhWMqX6.js');function toRlp(bytes, to = 'hex') { const encodable = getEncodable(bytes); const cursor = index.b0(new Uint8Array(encodable.length)); encodable.encode(cursor); if (to === 'hex') return index.e(cursor.bytes); return cursor.bytes; } function getEncodable(bytes) { if (Array.isArray(bytes)) return getEncodableList(bytes.map((x) => getEncodable(x))); return getEncodableBytes(bytes); } function getEncodableList(list) { const bodyLength = list.reduce((acc, x) => acc + x.length, 0); const sizeOfBodyLength = getSizeOfLength(bodyLength); const length = (() => { if (bodyLength <= 55) return 1 + bodyLength; return 1 + sizeOfBodyLength + bodyLength; })(); return { length, encode(cursor) { if (bodyLength <= 55) { cursor.pushByte(0xc0 + bodyLength); } else { cursor.pushByte(0xc0 + 55 + sizeOfBodyLength); if (sizeOfBodyLength === 1) cursor.pushUint8(bodyLength); else if (sizeOfBodyLength === 2) cursor.pushUint16(bodyLength); else if (sizeOfBodyLength === 3) cursor.pushUint24(bodyLength); else cursor.pushUint32(bodyLength); } for (const { encode } of list) { encode(cursor); } }, }; } function getEncodableBytes(bytesOrHex) { const bytes = typeof bytesOrHex === 'string' ? index.b1(bytesOrHex) : bytesOrHex; const sizeOfBytesLength = getSizeOfLength(bytes.length); const length = (() => { if (bytes.length === 1 && bytes[0] < 0x80) return 1; if (bytes.length <= 55) return 1 + bytes.length; return 1 + sizeOfBytesLength + bytes.length; })(); return { length, encode(cursor) { if (bytes.length === 1 && bytes[0] < 0x80) { cursor.pushBytes(bytes); } else if (bytes.length <= 55) { cursor.pushByte(0x80 + bytes.length); cursor.pushBytes(bytes); } else { cursor.pushByte(0x80 + 55 + sizeOfBytesLength); if (sizeOfBytesLength === 1) cursor.pushUint8(bytes.length); else if (sizeOfBytesLength === 2) cursor.pushUint16(bytes.length); else if (sizeOfBytesLength === 3) cursor.pushUint24(bytes.length); else cursor.pushUint32(bytes.length); cursor.pushBytes(bytes); } }, }; } function getSizeOfLength(length) { if (length < 2 ** 8) return 1; if (length < 2 ** 16) return 2; if (length < 2 ** 24) return 3; if (length < 2 ** 32) return 4; throw new index.B('Length is too large.'); }const maxUint16 = 2n ** 16n - 1n;function sha256(value, to_) { const bytes = sha256$1.s(index.V(value, { strict: false }) ? index.a0(value) : value); return index.ak(bytes); }/** * Provides error checking on string or number bigint inputs. * @param value - A possibly integer-like string, number, or bigint. * @returns The bigint representation of the input. * @example * ```ts * toBigInt("2") * // 2n */ function toBigInt(value) { if (["string", "number"].includes(typeof value) && !Number.isInteger(Number(value))) { throw new Error(`Expected value to be an integer to convert to a bigint, got ${value} of type ${typeof value}`); } if (value instanceof Uint8Array) { return BigInt(index.N(value)); } return BigInt(value); } const replaceBigInts = (obj, replacer) => { if (typeof obj === "bigint") return replacer(obj); if (Array.isArray(obj)) return obj.map((x) => replaceBigInts(x, replacer)); if (obj && typeof obj === "object") return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, replaceBigInts(v, replacer)])); return obj; };const maxBytecodeSize = maxUint16 * 32n;class BytecodeLengthExceedsMaxSizeError extends index.B { constructor({ givenLength, maxBytecodeSize, }) { super(`Bytecode cannot be longer than ${maxBytecodeSize} bytes. Given length: ${givenLength}`, { name: 'BytecodeLengthExceedsMaxSizeError' }); } } class BytecodeLengthInWordsMustBeOddError extends index.B { constructor({ givenLengthInWords }) { super(`Bytecode length in 32-byte words must be odd. Given length in words: ${givenLengthInWords}`, { name: 'BytecodeLengthInWordsMustBeOddError' }); } } class BytecodeLengthMustBeDivisibleBy32Error extends index.B { constructor({ givenLength }) { super(`The bytecode length in bytes must be divisible by 32. Given length: ${givenLength}`, { name: 'BytecodeLengthMustBeDivisibleBy32Error' }); } }function hashBytecode(bytecode) { const bytecodeBytes = index.a0(bytecode); if (bytecodeBytes.length % 32 !== 0) throw new BytecodeLengthMustBeDivisibleBy32Error({ givenLength: bytecodeBytes.length, }); if (bytecodeBytes.length > maxBytecodeSize) throw new BytecodeLengthExceedsMaxSizeError({ givenLength: bytecodeBytes.length, maxBytecodeSize, }); const hashStr = sha256(bytecodeBytes); const hash = index.a0(hashStr); // Note that the length of the bytecode // should be provided in 32-byte words. const bytecodeLengthInWords = bytecodeBytes.length / 32; if (bytecodeLengthInWords % 2 === 0) { throw new BytecodeLengthInWordsMustBeOddError({ givenLengthInWords: bytecodeLengthInWords, }); } const bytecodeLength = index.a0(bytecodeLengthInWords); // The bytecode should always take the first 2 bytes of the bytecode hash, // so we pad it from the left in case the length is smaller than 2 bytes. const bytecodeLengthPadded = index.aj(bytecodeLength, { size: 2 }); const codeHashVersion = new Uint8Array([1, 0]); hash.set(codeHashVersion, 0); hash.set(bytecodeLengthPadded, 2); return hash; }const gasPerPubdataDefault = 50000n; const getEip712Domain = (transaction) => { const message = transactionToMessage(transaction); return { domain: { name: "zkSync", version: "2", chainId: transaction.chainId, }, types: { Transaction: [ { name: "txType", type: "uint256" }, { name: "from", type: "uint256" }, { name: "to", type: "uint256" }, { name: "gasLimit", type: "uint256" }, { name: "gasPerPubdataByteLimit", type: "uint256" }, { name: "maxFeePerGas", type: "uint256" }, { name: "maxPriorityFeePerGas", type: "uint256" }, { name: "paymaster", type: "uint256" }, { name: "nonce", type: "uint256" }, { name: "value", type: "uint256" }, { name: "data", type: "bytes" }, { name: "factoryDeps", type: "bytes32[]" }, { name: "paymasterInput", type: "bytes" }, ], }, primaryType: "Transaction", message: message, }; }; function transactionToMessage(transaction) { const { gas, nonce, to, from, value, maxFeePerGas, maxPriorityFeePerGas, paymaster, paymasterInput, gasPerPubdata, data, factoryDeps, } = transaction; return { txType: 113n, from: BigInt(from), to: to ? BigInt(to) : 0n, gasLimit: gas ?? 0n, gasPerPubdataByteLimit: gasPerPubdata ?? gasPerPubdataDefault, maxFeePerGas: maxFeePerGas ?? 0n, maxPriorityFeePerGas: maxPriorityFeePerGas ?? 0n, paymaster: paymaster ? BigInt(paymaster) : 0n, nonce: nonce ? BigInt(nonce) : 0n, value: value ?? 0n, data: data ? data : "0x0", factoryDeps: factoryDeps?.map((dep) => index.i(hashBytecode(dep))) ?? [], paymasterInput: paymasterInput ? paymasterInput : "0x", }; }/** * Sends a transaction using the provided wallet. * @param options - The options for sending the transaction. * @returns A promise that resolves to the transaction hash. * @throws An error if the wallet is not connected. * @transaction * @example * ```ts * import { sendTransaction } from "thirdweb"; * * const { transactionHash } = await sendTransaction({ * account, * transaction * }); * ``` */ async function sendEip712Transaction(options) { const { account, transaction } = options; const eip712Transaction = await populateEip712Transaction(options); const hash = await signEip712Transaction({ account, eip712Transaction, chainId: transaction.chain.id, }); const rpc = index.f(transaction); const result = await eth_sendRawTransaction.e(rpc, hash); return { transactionHash: result, chain: transaction.chain, client: transaction.client, }; } async function signEip712Transaction(options) { const { account, eip712Transaction, chainId } = options; // EIP712 signing of the serialized tx const eip712Domain = getEip712Domain(eip712Transaction); const customSignature = await account.signTypedData({ // biome-ignore lint/suspicious/noExplicitAny: TODO type properly ...eip712Domain, }); return serializeTransactionEIP712({ ...eip712Transaction, chainId, customSignature, }); } /** * Populate a prepared transaction to be serialized as a EIP712 transaction * @param options * @internal */ async function populateEip712Transaction(options) { const { account, transaction } = options; const { gas, maxFeePerGas, maxPriorityFeePerGas, gasPerPubdata } = await getZkGasFees({ transaction, from: index.d(account.address) }); // serialize the transaction (with fees, gas, nonce) const serializableTransaction = await index.aH({ transaction: { ...transaction, gas, maxFeePerGas, maxPriorityFeePerGas, }, from: account.address, }); return { ...serializableTransaction, ...transaction.eip712, gasPerPubdata, from: account.address, }; } function serializeTransactionEIP712(transaction) { const { chainId, gas, nonce, to, from, value, maxFeePerGas, maxPriorityFeePerGas, customSignature, factoryDeps, paymaster, paymasterInput, gasPerPubdata, data, } = transaction; const serializedTransaction = [ nonce ? index.i(nonce) : "0x", maxPriorityFeePerGas ? index.i(maxPriorityFeePerGas) : "0x", maxFeePerGas ? index.i(maxFeePerGas) : "0x", gas ? index.i(gas) : "0x", to ?? "0x", value ? index.i(value) : "0x", data ?? "0x0", index.i(chainId), index.i(""), index.i(""), index.i(chainId), from ?? "0x", gasPerPubdata ? index.i(gasPerPubdata) : index.i(gasPerPubdataDefault), factoryDeps ?? [], customSignature ?? "0x", // EIP712 signature paymaster && paymasterInput ? [paymaster, paymasterInput] : [], ]; // @ts-ignore - TODO: fix types return concatHex.concatHex(["0x71", toRlp(serializedTransaction)]); } async function getZkGasFees(args) { const { transaction, from } = args; let [gas, maxFeePerGas, maxPriorityFeePerGas, eip712] = await Promise.all([ index.aq(transaction.gas), index.aq(transaction.maxFeePerGas), index.aq(transaction.maxPriorityFeePerGas), index.aq(transaction.eip712), ]); let gasPerPubdata = eip712?.gasPerPubdata; if (gas === undefined || maxFeePerGas === undefined || maxPriorityFeePerGas === undefined) { const rpc = index.f(transaction); const params = await formatTransaction({ transaction, from }); const result = (await rpc({ // biome-ignore lint/suspicious/noExplicitAny: TODO add to RPC method types method: "zks_estimateFee", // biome-ignore lint/suspicious/noExplicitAny: TODO add to RPC method types params: [replaceBigInts(params, index.i)], })); gas = toBigInt(result.gas_limit) * 2n; // overestimating to avoid issues when not accounting for paymaster extra gas ( we should really pass the paymaster input above for better accuracy ) const baseFee = toBigInt(result.max_fee_per_gas); maxFeePerGas = baseFee * 2n; // bumping the base fee per gas to ensure fast inclusion maxPriorityFeePerGas = toBigInt(result.max_priority_fee_per_gas) || 1n; gasPerPubdata = toBigInt(result.gas_per_pubdata_limit) * 2n; // doubling for fast inclusion; if (gasPerPubdata < 50000n) { // enforce a minimum gas per pubdata limit gasPerPubdata = 50000n; } } return { gas, maxFeePerGas, maxPriorityFeePerGas, gasPerPubdata, }; } async function formatTransaction(args) { const { transaction, from } = args; const [data, to, value, eip712] = await Promise.all([ index.ap(transaction), index.aq(transaction.to), index.aq(transaction.value), index.aq(transaction.eip712), ]); const gasPerPubdata = eip712?.gasPerPubdata; return { from, to, data, value, gasPerPubdata, eip712Meta: { ...eip712, gasPerPubdata: gasPerPubdata || 50000n, factoryDeps: eip712?.factoryDeps?.map((dep) => Array.from(index.b1(dep))), }, type: "0x71", }; }var sendEip712Transaction$1=/*#__PURE__*/Object.freeze({__proto__:null,getZkGasFees:getZkGasFees,populateEip712Transaction:populateEip712Transaction,sendEip712Transaction:sendEip712Transaction,signEip712Transaction:signEip712Transaction});exports.a=sendEip712Transaction$1;exports.p=populateEip712Transaction;exports.s=signEip712Transaction;exports.t=toBigInt;//# sourceMappingURL=send-eip712-transaction-B3DIfS-8.js.map