Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Demo : Native meta-transaction via Biconomy #1

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions contracts/SapienChildERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,27 @@ contract SapienChildERC20 is ChildERC20 {
return transferWithPurpose(to, value, hex"");
}

function transferWithPurposeAndSig(address to, uint256 value, bytes memory purpose,
bytes memory sig, bytes32 data, uint256 expiration) public returns (bool) {

require(expiration == 0 || block.number <= expiration, "Signature is expired");

bytes32 dataHash = getTokenTransferOrderHash(
to,
value,
data,
expiration
);
require(disabledHashes[dataHash] == false, "Sig deactivated");
disabledHashes[dataHash] = true;

address from = ecrecovery(dataHash, sig);
if (parent != address(0x0) && !ISapienParentToken(parent).beforeTransfer(from, to, value, purpose)) {
return false;
}
return _transferFrom(from, to, value);
}

/// @dev Function that is called when a user or another contract wants to transfer funds, including a purpose.
/// @param to Address of token receiver.
/// @param value Number of tokens to transfer.
Expand Down
128 changes: 128 additions & 0 deletions demo-script/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
var sigUtil = require('eth-sig-util');
const Biconomy = require("@biconomy/mexa");
const Web3 = require("web3");
const {abi} = require("./abi");

let tokenAddress = "SapienChildERC20_contract_address";

//Initialize Biconomy
// register on biconomy dashboard to create dapp_id & api_key
const biconomy = new Biconomy(new Web3.providers.HttpProvider("https://betav2.matic.network"),
{dappId: "dapp_id", apiKey: "api_key",debug:true});

//initialise web3 with Biconomy
web3 = new Web3(biconomy);

let contract = new web3.eth.Contract(abi , tokenAddress);
let data = "4" //dynamic data
let toAddress = "receiver_address";
let fromAddress = "spender_address";
let privateKey = "spender_private_key";

biconomy.onEvent(biconomy.READY, () => {
// Initialize your dapp here like getting user accounts etc
sendSignedTransactionToSapien();
}).onEvent(biconomy.ERROR, (error, message) => {
// Handle error while initializing mexa
console.log("error while initialising biconomy")
console.log(error);
});

async function sendSignedTransactionToSapien(){
//Sign Data
let transferSigResult = getTransferSig(
privateKey,
toAddress,
data,
tokenAddress,
"1", //Transferring 1 sapien token
0
);

let result = contract.methods.transferWithPurposeAndSig(
toAddress,
"1",
web3.utils.hexToBytes(web3.utils.stringToHex("0")),
transferSigResult.sig,
web3.utils.hexToBytes(web3.utils.stringToHex(data)),
0
).encodeABI();

let txParams = {
"from": fromAddress,
"gasLimit": web3.utils.toHex(210000),
"to": tokenAddress,
"value": "0x0",
"data": result
};

// Sign Transaction
const signedTx = await web3.eth.accounts.signTransaction(txParams, `0x${privateKey}`);
let receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction, (error, txHash)=>{
if(error) {
return console.error(error);
}
console.log(txHash);
});

}

function getTransferSig(
privateKey,
spender,
data,
tokenAddress,
tokenIdOrAmount,
expiration
) {
const typedData = getTransferTypedData({
tokenAddress,
tokenIdOrAmount,
spender,
data,
expiration
});

const sig = sigUtil.signTypedMessage(new Buffer.from(privateKey,'hex'), {
data: typedData
},'V3')
return { sig };
}

function getTransferTypedData({
tokenAddress,
spender,
tokenIdOrAmount,
data,
expiration
}) {
return {
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "contract", type: "address" }
],
TokenTransferOrder: [
{ name: "spender", type: "address" },
{ name: "tokenIdOrAmount", type: "uint256" },
{ name: "data", type: "bytes32" },
{ name: "expiration", type: "uint256" }
]
},
domain: {
name: "Matic Network",
version: "1",
chainId: 16110,
contract: tokenAddress
},
primaryType: "TokenTransferOrder",
message: {
spender,
tokenIdOrAmount,
data,
expiration
}
}
}
17 changes: 17 additions & 0 deletions demo-script/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "script",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@biconomy/mexa": "^1.5.1",
"eth-sig-util": "^2.5.3",
"ethereumjs-util": "^6.2.0",
"web3": "^1.2.6"
}
}