UNPKG

@0xfutbol/id

Version:

React component library with shared providers for 0xFutbol ID

170 lines (169 loc) 6.39 kB
import {s as stringify,at as getContract,P as readContract,aL as waitForReceipt}from'./index-DNoa140s.js';import'react';import'react/jsx-runtime';import'@0xfutbol/id-sign';import'react-use';import'@0xfutbol/constants';import'thirdweb';import'@matchain/matchid-sdk-react';import'@tanstack/react-query';import'@matchain/matchid-sdk-react/index.css';import'react-dom';/** * @internal - only exported for testing */ async function prepareEngineTransaction({ account, serializableTransaction, transaction, gasless, }) { const forrwaderContract = getContract({ address: gasless.relayerForwarderAddress, chain: transaction.chain, client: transaction.client, }); const nonce = await readContract({ contract: forrwaderContract, method: "function getNonce(address) view returns (uint256)", params: [account.address], }); const [signature, message] = await (async () => { // TODO: handle special case for `approve` -> `permit` transactions if (!serializableTransaction.to) { throw new Error("engine transactions must have a 'to' address"); } if (!serializableTransaction.gas) { throw new Error("engine transactions must have a 'gas' value"); } if (!serializableTransaction.data) { throw new Error("engine transactions must have a 'data' value"); } // chainless support! if (gasless.experimentalChainlessSupport) { const message = { from: account.address, to: serializableTransaction.to, value: 0n, gas: serializableTransaction.gas, nonce: nonce, data: serializableTransaction.data, chainid: BigInt(transaction.chain.id), }; return [ await account.signTypedData({ domain: { name: "GSNv2 Forwarder", version: "0.0.1", verifyingContract: forrwaderContract.address, }, message, primaryType: "ForwardRequest", types: { ForwardRequest: ChainAwareForwardRequest }, }), message, ]; } // else non-chainless support const message = { from: account.address, to: serializableTransaction.to, value: 0n, gas: serializableTransaction.gas, nonce: nonce, data: serializableTransaction.data, }; return [ await account.signTypedData({ domain: { name: gasless.domainName ?? "GSNv2 Forwarder", version: gasless.domainVersion ?? "0.0.1", chainId: transaction.chain.id, verifyingContract: forrwaderContract.address, }, message, primaryType: "ForwardRequest", types: { ForwardRequest }, }), message, ]; })(); // TODO: handle special case for `approve` -> `permit` const messageType = "forward"; return { message, signature, messageType }; } const ForwardRequest = [ { name: "from", type: "address" }, { name: "to", type: "address" }, { name: "value", type: "uint256" }, { name: "gas", type: "uint256" }, { name: "nonce", type: "uint256" }, { name: "data", type: "bytes" }, ]; const ChainAwareForwardRequest = [ { name: "from", type: "address" }, { name: "to", type: "address" }, { name: "value", type: "uint256" }, { name: "gas", type: "uint256" }, { name: "nonce", type: "uint256" }, { name: "data", type: "bytes" }, { name: "chainid", type: "uint256" }, ]; /** * @internal */ async function relayEngineTransaction(options) { const { message, messageType, signature } = await prepareEngineTransaction(options); const response = await fetch(options.gasless.relayerUrl, { method: "POST", headers: { "Content-Type": "application/json", }, body: stringify({ request: message, type: messageType, signature, forwarderAddress: options.gasless.relayerForwarderAddress, }), }); if (!response.ok) { throw new Error(`Failed to send transaction: ${await response.text()}`); } const json = await response.json(); if (!json.result) { throw new Error(`Relay transaction failed: ${json.message}`); } const queueId = json.result.queueId; // poll for transactionHash const timeout = 60000; const interval = 1000; const endtime = Date.now() + timeout; while (Date.now() < endtime) { const receipt = await fetchReceipt({ options, queueId }); if (receipt) { return { transactionHash: receipt.transactionHash, chain: options.transaction.chain, client: options.transaction.client, }; } await new Promise((resolve) => setTimeout(resolve, interval)); } throw new Error(`Failed to find relayed transaction after ${timeout}ms`); } async function fetchReceipt(args) { const { options, queueId } = args; const url = options.gasless.relayerUrl.split("/relayer/")[0]; const res = await fetch(`${url}/transaction/status/${queueId}`, { method: "GET", }); const resJson = await res.json(); if (!res.ok) { return null; } const result = resJson.result; if (!result) { return null; } switch (result.status) { case "errored": throw new Error(`Transaction errored with reason: ${result.errorMessage}`); case "cancelled": throw new Error("Transaction execution cancelled."); case "mined": { const receipt = await waitForReceipt({ client: options.transaction.client, chain: options.transaction.chain, transactionHash: result.transactionHash, }); return receipt; } default: { return null; } } }export{prepareEngineTransaction,relayEngineTransaction};//# sourceMappingURL=engine-C7t2VS0b.js.map