Gasless SDK (EOA) 3
The new TypeScript Gasless SDK (EOA) is here!
Changes in the new SDK:
Typescript based SDK
Using event listeners you can monitor the state change of a transaction. One can get notified on transaction hash creation, transaction being mined or on any error.
How to build and send transaction with Ethers:
https://github.com/bcnmy/gasless-playground/blob/master/src/components/Ethers_EIP2771_EIP712Sign.tsx
const provider = await biconomy.provider;
const contractInstance = new ethers.Contract(
config.contract.address,
config.contract.abi,
biconomy.ethersProvider
);
let { data } = await contractInstance.populateTransaction.setQuote(arg);
let txParams = {
data: data,
to: config.contract.address,
from: userAddress,
signatureType: "EIP712_SIGN",
};
await provider.send("eth_sendTransaction", [txParams]);
// Listen to transaction updates:
biconomy.on("txHashGenerated", data: { transactionId: string; transactionHash: string; }) => {
console.log(data);
showSuccessMessage(`tx hash ${data.hash}`);
});
biconomy.on("txMined", (data: {msg: string; id: string; hash: string; receipt: string}) => {
console.log(data);
});
biconomy.on("onError", (data: {error: any; transactionId: string}) => {
console.log(data);
});
bicnomy.on("txHashChanged", (data: {transactionId: string, transactionHash: string}) => {
console.log(data);
});
const provider = await biconomy.provider;
const contractInstance = new ethers.Contract(
config.contract.address,
config.contract.abi,
biconomy.ethersProvider
);
let { data } = await contractInstance.populateTransaction.setQuote(arg);
let txParams = {
data: data,
to: config.contract.address,
from: userAddress,
signatureType: "PERSONAL_SIGN",
};
await provider.send("eth_sendTransaction", [txParams]);
// Listen to transaction updates:
biconomy.on("txHashGenerated", data: { transactionId: string; transactionHash: string; }) => {
console.log(data);
showSuccessMessage(`tx hash ${data.hash}`);
});
biconomy.on("txMined", (data: {msg: string; id: string; hash: string; receipt: string}) => {
console.log(data);
});
biconomy.on("onError", (data: {error: any; transactionId: string}) => {
console.log(data);
});
bicnomy.on("txHashChanged", (data: {transactionId: string, transactionHash: string}) => {
console.log(data);
});
https://github.com/bcnmy/gasless-playground/blob/master/src/components/Ethers_Custom_EIP712Sign.tsx
// Getting the signatures based on EIP 712 Signature Scheme:
const domainType = [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "verifyingContract", type: "address" },
{ name: "salt", type: "bytes32" },
];
const metaTransactionType = [
{ name: "nonce", type: "uint256" },
{ name: "from", type: "address" },
{ name: "functionSignature", type: "bytes" },
];
let domainData = {
name: "TestContract",
version: "1",
verifyingContract: config.contract.address,
salt: "0x" + (42).toString(16).padStart(64, "0"),
};
const contractInstance = new ethers.Contract(
config.contract.address,
config.contract.abi as ContractInterface,
signer!
);
let nonce = await contractInstance.getNonce(userAddress);
const contractInterface = new ethers.utils.Interface(config.contract.abi);
let functionSignature = contractInterface.encodeFunctionData("setQuote", [
newQuote,
]);
let message = {
nonce: parseInt(nonce),
from: userAddress,
functionSignature: functionSignature,
};
const dataToSign = JSON.stringify({
types: {
EIP712Domain: domainType,
MetaTransaction: metaTransactionType,
},
domain: domainData,
primaryType: "MetaTransaction",
message: message,
});
let signature = await ethersProvider.send("eth_signTypedData_v3", [
userAddress,
dataToSign,
]);
let { r, s, v } = (signature: any) => {
if (!ethers.utils.isHexString(signature)) {
throw new Error(
'Given value "'.concat(signature, '" is not a valid hex string.')
);
}
const r = signature.slice(0, 66);
const s = "0x".concat(signature.slice(66, 130));
let v = "0x".concat(signature.slice(130, 132));
v = ethers.BigNumber.from(v).toString();
if (![27, 28].includes(Number(v))) v += 27;
return {
r: r,
s: s,
v: Number(v),
};
};
const provider = await biconomy.provider;
let { data } =
await contractInstance.populateTransaction.executeMetaTransaction(
userAddress,
functionData,
r,
s,
v
);
let txParams = {
data: data,
to: contractAddress,
from: userAddress,
signatureType: "EIP712_SIGN",
};
await provider.send("eth_sendTransaction", [txParams]);
// Listen to transaction updates:
biconomy.on("txHashGenerated", data: { transactionId: string; transactionHash: string; }) => {
console.log(data);
showSuccessMessage(`tx hash ${data.hash}`);
});
biconomy.on("txMined", (data: {msg: string; id: string; hash: string; receipt: string}) => {
console.log(data);
});
biconomy.on("onError", (data: {error: any; transactionId: string}) => {
console.log(data);
});
bicnomy.on("txHashChanged", (data: {transactionId: string, transactionHash: string}) => {
console.log(data);
});
const contractInstance = await new web3.eth.Contract(
abi,
contractAddress
);
const nonce = await contractInstance.methods.getNonce(address).call();
let functionSignature = await contractInstance.methods
.setQuote('test')
.encodeABI();
let messageToSign = (
nonce: number,
chainId: number,
functionSignature: string,
contractAddress: string
) => {
return abi.soliditySHA3(
["uint256", "address", "uint256", "bytes"],
[nonce, contractAddress, chainId, toBuffer(functionSignature)]
);
};
const signature = await walletProvider.signMessage(messageToSign);
let { r, s, v } = (signature: any) => {
if (!ethers.utils.isHexString(signature)) {
throw new Error(
'Given value "'.concat(signature, '" is not a valid hex string.')
);
}
const r = signature.slice(0, 66);
const s = "0x".concat(signature.slice(66, 130));
let v = "0x".concat(signature.slice(130, 132));
v = ethers.BigNumber.from(v).toString();
if (![27, 28].includes(Number(v))) v += 27;
return {
r: r,
s: s,
v: Number(v),
};
};
const provider = await biconomy.provider;
let { data } =
await contractInstance.populateTransaction.executeMetaTransaction(
userAddress,
functionData,
r,
s,
v
);
let txParams = {
data: data,
to: config.contract.address,
from: userAddress,
signatureType: "PERSONAL_SIGN",
};
await provider.send("eth_sendTransaction", [txParams]);
// Listen to transaction updates:
biconomy.on("txHashGenerated", data: { transactionId: string; transactionHash: string; }) => {
console.log(data);
showSuccessMessage(`tx hash ${data.hash}`);
});
biconomy.on("txMined", (data: {msg: string; id: string; hash: string; receipt: string}) => {
console.log(data);
});
biconomy.on("onError", (data: {error: any; transactionId: string}) => {
console.log(data);
});
bicnomy.on("txHashChanged", (data: {transactionId: string, transactionHash: string}) => {
console.log(data);
});
How to build and send transactions with Web3:
https://github.com/bcnmy/gasless-playground/blob/master/src/components/Web3_EIP2771_EIP712Sign.tsx
const web3 = new Web3(biconomy.provider);
const contractInstance = new web3.eth.Contract(
abi
contractAddress
);
await contractInstance.methods.setQuote(newQuote).send({
from: address,
signatureType: "EIP712_SIGN",
});
// Listen to transaction updates:
biconomy.on("txHashGenerated", data: { transactionId: string; transactionHash: string; }) => {
console.log(data);
showSuccessMessage(`tx hash ${data.hash}`);
});
biconomy.on("txMined", (data: {msg: string; id: string; hash: string; receipt: string}) => {
console.log(data);
});
biconomy.on("onError", (data: {error: any; transactionId: string}) => {
console.log(data);
});
bicnomy.on("txHashChanged", (data: {transactionId: string, transactionHash: string}) => {
console.log(data);
});
https://github.com/bcnmy/gasless-playground/blob/master/src/components/Web3_EIP2771_PersonalSign.tsx
const web3 = new Web3(biconomy.provider as any);
const contractInstance = new web3.eth.Contract(
config.contract.abi as AbiItem[],
config.contract.address
);
await contractInstance.methods
.setQuote(newQuote)
.send("eth_sendTransaction", {
from: address,
signatureType: "PERSONAL_SIGN",
});
// Listen to transaction updates:
biconomy.on("txHashGenerated", data: { transactionId: string; transactionHash: string; }) => {
console.log(data);
showSuccessMessage(`tx hash ${data.hash}`);
});
biconomy.on("txMined", (data: {msg: string; id: string; hash: string; receipt: string}) => {
console.log(data);
});
biconomy.on("onError", (data: {error: any; transactionId: string}) => {
console.log(data);
});
bicnomy.on("txHashChanged", (data: {transactionId: string, transactionHash: string}) => {
console.log(data);
});
https://github.com/bcnmy/gasless-playground/blob/master/src/components/Web3_Custom_EIP712Sign.tsx
const domainType = [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "verifyingContract", type: "address" },
{ name: "salt", type: "bytes32" },
];
const metaTransactionType = [
{ name: "nonce", type: "uint256" },
{ name: "from", type: "address" },
{ name: "functionSignature", type: "bytes" },
];
let domainData = {
name: "TestContract",
version: "1",
verifyingContract: config.contract.address,
salt: "0x" + (42).toString(16).padStart(64, "0"),
};
const contractInstance = await new web3.eth.Contract(
config.contract.abi as AbiItem[],
config.contract.address
);
const web3 = new Web3(biconomy.provider);
let nonce = await contractInstance.methods.getNonce(address).call();
let functionSignature = await contractInstance.methods
.setQuote(newQuote)
.encodeABI();
let message = {
nonce: parseInt(nonce),
from: address,
functionSignature: functionSignature,
};
const dataToSign = JSON.stringify({
types: {
EIP712Domain: domainType,
MetaTransaction: metaTransactionType,
},
domain: domainData,
primaryType: "MetaTransaction",
message: message,
});
web3.currentProvider.send(
{
jsonrpc: "2.0",
id: 999999999999,
method: "eth_signTypedData_v4",
params: [address, dataToSign],
},
let { r, s, v } = (signature: any) => {
if (!ethers.utils.isHexString(signature)) {
throw new Error(
'Given value "'.concat(signature, '" is not a valid hex string.')
);
}
const r = signature.slice(0, 66);
const s = "0x".concat(signature.slice(66, 130));
let v = "0x".concat(signature.slice(130, 132));
v = ethers.BigNumber.from(v).toString();
if (![27, 28].includes(Number(v))) v += 27;
return {
r: r,
s: s,
v: Number(v),
};
};
const contractInstance = new web3.eth.Contract(
abi
contractAddress
);
await contractInstance.methods
.executeMetaTransaction(userAddress, functionData, r, s, v)
.send({
from: userAddress,
});
// Listen to transaction updates:
biconomy.on("txHashGenerated", data: { transactionId: string; transactionHash: string; }) => {
console.log(data);
showSuccessMessage(`tx hash ${data.hash}`);
});
biconomy.on("txMined", (data: {msg: string; id: string; hash: string; receipt: string}) => {
console.log(data);
});
biconomy.on("onError", (data: {error: any; transactionId: string}) => {
console.log(data);
});
bicnomy.on("txHashChanged", (data: {transactionId: string, transactionHash: string}) => {
console.log(data);
});
https://github.com/bcnmy/gasless-playground/blob/master/src/components/Web3_Custom_PersonalSign.tsx
const web3 = new Web3(biconomy.provider);
const contractInstance = await new web3.eth.Contract(
abi,
contractAddress
);
const nonce = await contractInstance.methods.getNonce(address).call();
let functionSignature = await contractInstance.methods
.setQuote('test')
.encodeABI();
let messageToSign = (
nonce: number,
chainId: number,
functionSignature: string,
contractAddress: string
) => {
return abi.soliditySHA3(
["uint256", "address", "uint256", "bytes"],
[nonce, contractAddress, chainId, toBuffer(functionSignature)]
);
};
const signature = await walletProvider.signMessage(messageToSign);
const signature = await web3.eth.personal.sign(
"0x" + messageToSign.toString("hex"),
address
);
let { r, s, v } = (signature: any) => {
if (!ethers.utils.isHexString(signature)) {
throw new Error(
'Given value "'.concat(signature, '" is not a valid hex string.')
);
}
const r = signature.slice(0, 66);
const s = "0x".concat(signature.slice(66, 130));
let v = "0x".concat(signature.slice(130, 132));
v = ethers.BigNumber.from(v).toString();
if (![27, 28].includes(Number(v))) v += 27;
return {
r: r,
s: s,
v: Number(v),
};
};
const tx = await contractInstance.methods
.executeMetaTransaction(userAddress, functionData, r, s, v)
.send({
from: userAddress,
});
// Listen to transaction updates:
biconomy.on("txHashGenerated", data: { transactionId: string; transactionHash: string; }) => {
console.log(data);
showSuccessMessage(`tx hash ${data.hash}`);
});
biconomy.on("txMined", (data: {msg: string; id: string; hash: string; receipt: string}) => {
console.log(data);
});
biconomy.on("onError", (data: {error: any; transactionId: string}) => {
console.log(data);
});
bicnomy.on("txHashChanged", (data: {transactionId: string, transactionHash: string}) => {
console.log(data);
});
Last updated