@0xfutbol/id
Version:
React component library with shared providers for 0xFutbol ID
170 lines (169 loc) • 6.39 kB
JavaScript
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