Skip to content

Instantly share code, notes, and snippets.

@arefaslani
Created August 13, 2020 14:05
Show Gist options
  • Save arefaslani/bfffae9df0ec848d47f6f4d39cd7d570 to your computer and use it in GitHub Desktop.
Save arefaslani/bfffae9df0ec848d47f6f4d39cd7d570 to your computer and use it in GitHub Desktop.
Biconomy contract
import Web3 from "web3";
import axios from "axios";
import config from "utilities/config";
import biconomy from "utilities/biconomy";
import { sleep } from "utilities";
const domainType = [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }
];
const metaTransactionType = [
{ name: "nonce", type: "uint256" },
{ name: "from", type: "address" },
{ name: "functionSignature", type: "bytes" }
];
const domainData = {
name: "ERC1155",
version: "1",
verifyingContract: config.contractAddress,
chainId: process.env.TRUFFLE_NETWORK_ID
};
class MintingError extends Error {
constructor(message) {
super(message);
this.name = "MintingError";
}
}
const web3 = new Web3(biconomy);
const contract = new web3.eth.Contract(
config.contractABI,
config.contractAddress
);
const getSignatureParameters = signature => {
if (!web3.utils.isHexStrict(signature)) {
throw new Error(`Given value "${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 = web3.utils.hexToNumber(v);
if (![27, 28].includes(v)) v += 27;
return { r, s, v };
};
const sendMetaTransaction = async ({
from,
functionSignature,
r,
s,
v,
onTransactionCreated,
onComplete,
resolve = () => { }
}) => {
try {
const { data } = await axios.post(
"https://api.biconomy.io/api/v2/meta-tx/native",
{
to: config.contractAddress,
apiId: process.env.BICONOMY_API_ID,
params: [from, functionSignature, r, s, v],
from,
gasLimit: "31039709"
},
{
headers: {
"x-api-key": process.env.BICONOMY_API_KEY,
"Content-Type": "application/json;charset=utf-8"
}
}
);
onTransactionCreated(data.txHash);
resolve(data.txHash);
let result;
do {
/* eslint-disable no-await-in-loop */
result = await web3.eth.getTransactionReceipt(data.txHash);
await sleep(2000);
/* eslint-enable no-await-in-loop */
} while (result === null);
onComplete(result.transactionHash);
} catch (error) {
throw new MintingError(error.message);
}
};
export default {
safeTransferFrom: async ({
from,
to,
id,
amount,
onTransactionCreated = () => { },
onComplete = () => { }
}) =>
new Promise(resolve => {
contract.methods
.getNonce(from)
.call()
.then(nonce => {
const functionSignature = contract.methods
.safeTransferFrom(from, to, id, amount, "0x0")
.encodeABI();
const message = {
nonce: parseInt(nonce, 10),
from,
functionSignature
};
const dataToSign = JSON.stringify({
types: {
EIP712Domain: domainType,
MetaTransaction: metaTransactionType
},
domain: domainData,
primaryType: "MetaTransaction",
message
});
web3.currentProvider.send(
{
jsonrpc: "2.0",
method: "eth_signTypedData_v4",
params: [from, dataToSign]
},
(error, response) => {
const { r, s, v } = getSignatureParameters(response.result);
sendMetaTransaction({
from,
functionSignature,
r,
s,
v,
onTransactionCreated,
onComplete,
resolve
});
}
);
});
})
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment