Skip to content

Instantly share code, notes, and snippets.

@livingrock7
Created July 15, 2021 06:59
Show Gist options
  • Save livingrock7/b7bdd6502912b085300af45697c2471d to your computer and use it in GitHub Desktop.
Save livingrock7/b7bdd6502912b085300af45697c2471d to your computer and use it in GitHub Desktop.
USDC double permit (permit & executePermitWithDeposit) idle deposit forwarder client side code integration
import React, { useState, useEffect } from "react";
import "../App.css";
import Button from "@material-ui/core/Button";
import {
NotificationContainer,
NotificationManager
} from "react-notifications";
import "react-notifications/lib/notifications.css";
import Backdrop from '@material-ui/core/Backdrop';
import CircularProgress from '@material-ui/core/CircularProgress';
import { ethers, providers } from "ethers";
import { Biconomy } from "@biconomy/mexa";
import { makeStyles } from '@material-ui/core/styles';
import Link from '@material-ui/core/Link';
import Typography from '@material-ui/core/Typography';
import { Box } from "@material-ui/core";
let sigUtil = require("eth-sig-util");
let config = {
contract: {
address: "0x43bD6a78b37b50E3f52CAcec53F1202dbDe6a761",
abi: [{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"Foo","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_to","type":"address"}],"name":"emergencyWithdrawToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"foo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"idleToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_trustedForwarder","type":"address"},{"internalType":"address","name":"_idleToken","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permitAndDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permitEIP2612AndDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"trustedForwarder","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"versionRecipient","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]
},
apiKey: {
test: "9ZT_-ZGFb.ab81c572-91c2-4c6f-8cce-ed024828dc13",
prod: "8nvA_lM_Q.0424c54e-b4b2-4550-98c5-8b437d3118a9"
}
}
config.erc20ForwarderAddress = "0xfaadbe5f0a19f0ebf92aeb73534cbc96b96e2bda";
config.daiAddress = "0x4F96Fe3b7A6Cf9725f59d353F723c1bDb64CA6Aa";
config.usdtAddress = "0x8e1084f3599ba90991C3b2f9e25D920738C1496D";
config.usdc = {
address: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
abi: [{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"initialBalance","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"authorizer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"AuthorizationCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"authorizer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"AuthorizationUsed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_account","type":"address"}],"name":"Blacklisted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newBlacklister","type":"address"}],"name":"BlacklisterChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"burner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newMasterMinter","type":"address"}],"name":"MasterMinterChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"minterAllowedAmount","type":"uint256"}],"name":"MinterConfigured","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldMinter","type":"address"}],"name":"MinterRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[],"name":"Pause","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newAddress","type":"address"}],"name":"PauserChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newRescuer","type":"address"}],"name":"RescuerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_account","type":"address"}],"name":"UnBlacklisted","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpause","type":"event"},{"inputs":[],"name":"APPROVE_WITH_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CANCEL_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DECREASE_ALLOWANCE_WITH_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INCREASE_ALLOWANCE_WITH_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TRANSFER_WITH_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validBefore","type":"uint256"},{"internalType":"bytes32","name":"nonce","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"approveWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"authorizer","type":"address"},{"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"authorizationState","outputs":[{"internalType":"enumGasAbstraction.AuthorizationState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"blacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"blacklister","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"authorizer","type":"address"},{"internalType":"bytes32","name":"nonce","type":"bytes32"},
{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"cancelAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minter","type":"address"},{"internalType":"uint256","name":"minterAllowedAmount","type":"uint256"}],"name":"configureMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currency","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"decrement","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"decrement","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validBefore","type":"uint256"},{"internalType":"bytes32","name":"nonce","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"decreaseAllowanceWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"increment","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"increment","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validBefore","type":"uint256"},{"internalType":"bytes32","name":"nonce","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"increaseAllowanceWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"tokenName","type":"string"},{"internalType":"string","name":"tokenSymbol","type":"string"},{"internalType":"string","name":"tokenCurrency","type":"string"},{"internalType":"uint8","name":"tokenDecimals","type":"uint8"},{"internalType":"address","name":"newMasterMinter","type":"address"},{"internalType":"address","name":"newPauser","type":"address"},{"internalType":"address","name":"newBlacklister","type":"address"},{"internalType":"address","name":"newOwner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newName","type":"string"}],"name":"initializeV2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isBlacklisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"masterMinter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minter","type":"address"}],"name":"minterAllowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauser","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minter","type":"address"}],"name":"removeMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contractIERC20","name":"tokenContract","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"rescueERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rescuer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},
{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validBefore","type":"uint256"},{"internalType":"bytes32","name":"nonce","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"transferWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"unBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newBlacklister","type":"address"}],"name":"updateBlacklister","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newMasterMinter","type":"address"}],"name":"updateMasterMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newPauser","type":"address"}],"name":"updatePauser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newRescuer","type":"address"}],"name":"updateRescuer","outputs":[],"stateMutability":"nonpayable","type":"function"}]
};
config.dai = {
address: "0x4F96Fe3b7A6Cf9725f59d353F723c1bDb64CA6Aa",
abi: [{"inputs":[{"internalType":"uint256","name":"chainId_","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":true,"internalType":"address","name":"guy","type":"address"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":true,"inputs":[{"indexed":true,"internalType":"bytes4","name":"sig","type":"bytes4"},{"indexed":true,"internalType":"address","name":"usr","type":"address"},{"indexed":true,"internalType":"bytes32","name":"arg1","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"arg2","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"LogNote","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":true,"internalType":"address","name":"dst","type":"address"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"}],"name":"Transfer","type":"event"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"usr","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"usr","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"burn","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"guy","type":"address"}],"name":"deny","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"usr","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"mint","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"move","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"bool","name":"allowed","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"usr","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"pull","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"usr","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"push","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"guy","type":"address"}],"name":"rely","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"wards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]
};
let usdcDomainData = {
name: "USD Coin",
version: "2",
chainId: 1,
verifyingContract: config.usdc.address,
};
let daiDomainType = [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" },
];
let daiPermitType = [
{ name: "holder", type: "address" },
{ name: "spender", type: "address" },
{ name: "nonce", type: "uint256" },
{ name: "expiry", type: "uint256" },
{ name: "allowed", type: "bool" },
];
let daiDomainData = {
name: "Dai Stablecoin",
version: "1",
chainId: 42,
verifyingContract: config.daiAddress,
};
let domainType = [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" },
];
let eip2612PermitType = [
{ name: "owner", type: "address" },
{ name: "spender", type: "address" },
{ name: "value", type: "uint256" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" },
];
let walletProvider, walletSigner, ethersProvider;
let contract, contractInterface;
let ercForwarderClient, permitClient;
let usdcToken, daiToken;
const useStyles = makeStyles((theme) => ({
root: {
'& > * + *': {
marginLeft: theme.spacing(2),
},
},
link: {
marginLeft: "5px"
},
backdrop: {
zIndex: theme.zIndex.drawer + 1,
color: '#fff',
opacity: '.85!important',
background: '#000'
},
}));
let biconomy, userAddress;
function App() {
const classes = useStyles();
const [backdropOpen, setBackdropOpen] = React.useState(true);
const [loadingMessage, setLoadingMessage] = React.useState(" Loading Application ...");
const [quote, setQuote] = useState("This is a default quote");
const [owner, setOwner] = useState("Default Owner Address");
const [newQuote, setNewQuote] = useState("");
const [newToken, setNewToken] = useState("");
const [selectedAddress, setSelectedAddress] = useState("");
const [metaTxEnabled] = useState(true);
const [transactionHash, setTransactionHash] = useState("");
const handleClose = () => {
setBackdropOpen(false);
};
useEffect(() => {
async function init() {
if (
typeof window.ethereum !== "undefined" &&
window.ethereum.isMetaMask
) {
// Ethereum user detected. You can now use the provider.
debugger;
const provider = window["ethereum"];
await provider.enable();
setLoadingMessage("Initializing Biconomy ...");
// We're creating biconomy provider linked to your network of choice where your contract is deployed
let jsonRpcProvider = new ethers.providers.JsonRpcProvider("https://mainnet.infura.io/v3/d126f392798444609246423b06116c77");
biconomy = new Biconomy(provider, {
walletProvider: window.ethereum,
apiKey: config.apiKey.test,
debug: true
});
/*
This provider is linked to your wallet.
If needed, substitute your wallet solution in place of window.ethereum
*/
ethersProvider = new ethers.providers.Web3Provider(biconomy);
walletProvider = new ethers.providers.Web3Provider(window.ethereum);
walletSigner = walletProvider.getSigner();
userAddress = await walletSigner.getAddress()
setSelectedAddress(userAddress);
biconomy.onEvent(biconomy.READY, async () => {
// Initialize your dapp here like getting user accounts etc
contract = new ethers.Contract(
config.contract.address,
config.contract.abi,
biconomy.getSignerByAddress(userAddress)
);
usdcToken = new ethers.Contract(
config.usdc.address,
config.usdc.abi,
biconomy.getSignerByAddress(userAddress)
);
/*daiToken = new ethers.Contract(
config.dai.address,
config.dai.abi,
biconomy.getSignerByAddress(userAddress)
);*/
ercForwarderClient = biconomy.erc20ForwarderClient;
permitClient = biconomy.permitClient;
contractInterface = new ethers.utils.Interface(config.contract.abi);
//getQuoteFromNetwork();
}).onEvent(biconomy.ERROR, (error, message) => {
// Handle error while initializing mexa
console.log(message);
console.log(error);
});
} else {
showErrorMessage("Metamask not installed");
}
}
init();
}, []);
const onQuoteChange = event => {
setNewQuote(event.target.value);
};
const onTokenChange = event => {
setNewToken(event.target.value);
};
const onPermitAndSubmitWithEIP712Sign = async () => {
if (newQuote != "" && contract) {
setTransactionHash("");
if (metaTxEnabled) {
debugger;
let userAddress = selectedAddress;
console.log(usdcDomainData);
//If your provider is not a signer with accounts then you must pass userAddress in the permit options
const usdcPermitOptions = {
spender: config.contract.address,
domainData: usdcDomainData,
value: "10000000",
userAddress: userAddress,
deadline: Number(Math.floor(Date.now() / 1000 + 3600)),
};
console.log(usdcPermitOptions);
console.log("getting permit to spend usdc tokens");
showInfoMessage(
`Getting signature and permit transaction to spend usdc token by ERC20 Forwarder contract`
);
console.log("Sending meta transaction");
showInfoMessage("Building transaction to forward");
// txGas should be calculated and passed here or calculate within the method
const nonceFirst = await usdcToken.nonces(userAddress);
console.log(`nonce is : ${nonceFirst}`);
const permitDataToSignFirst = {
types: {
EIP712Domain: domainType,
Permit: eip2612PermitType,
},
domain: usdcDomainData,
primaryType: "Permit",
message: {
owner: userAddress,
spender: usdcPermitOptions.spender,
nonce: parseInt(nonceFirst),
value: usdcPermitOptions.value,
deadline: parseInt(usdcPermitOptions.deadline),
},
};
let resultFirst = await ethersProvider.send("eth_signTypedData_v3", [
userAddress,
JSON.stringify(permitDataToSignFirst),
]);
console.log(resultFirst);
const signatureFirst = resultFirst.substring(2);
const rR = "0x" + signatureFirst.substring(0, 64);
const sS = "0x" + signatureFirst.substring(64, 128);
const vV = parseInt(signatureFirst.substring(128, 130), 16);
debugger;
let { data } = await contract.populateTransaction.permitEIP2612AndDeposit(ethers.BigNumber.from("10000000").toString(),parseInt(usdcPermitOptions.deadline),vV,rR,sS);
let gasPrice = await ethersProvider.getGasPrice();
let gasLimit = await ethersProvider.estimateGas({
to: config.contract.address,
from: userAddress,
data: data,
});
console.log(gasLimit.toString());
console.log(gasPrice.toString());
console.log(data);
const builtTx = await ercForwarderClient.buildTx({
to: config.contract.address,
token: config.usdc.address,
txGas: Number(gasLimit),
data,
permitType: "EIP2612_Permit",
});
const tx = builtTx.request;
const fee = builtTx.cost;
console.log(tx);
console.log(fee);
showInfoMessage(`Signing message for meta transaction`);
alert(
`You will be charged maximum ${fee} amount of USDC ${config.usdc.address} for this transaction`
);
showInfoMessage(`Signing message for meta transaction`);
const nonce = await usdcToken.nonces(userAddress);
console.log(`nonce is : ${nonce}`);
const permitDataToSign = {
types: {
EIP712Domain: domainType,
Permit: eip2612PermitType,
},
domain: usdcDomainData,
primaryType: "Permit",
message: {
owner: userAddress,
spender: config.erc20ForwarderAddress,
nonce: parseInt(nonce) + 1,
value: "1000000000",
deadline: parseInt(usdcPermitOptions.deadline),
},
};
let result = await ethersProvider.send("eth_signTypedData_v3", [
userAddress,
JSON.stringify(permitDataToSign),
]);
console.log(result);
let metaInfo = {};
let permitOptions = {};
const signature = result.substring(2);
const r = "0x" + signature.substring(0, 64);
const s = "0x" + signature.substring(64, 128);
const v = parseInt(signature.substring(128, 130), 16);
permitOptions.holder = userAddress;
permitOptions.spender = config.erc20ForwarderAddress;
permitOptions.value = "1000000000";
permitOptions.nonce = parseInt(nonce.toString()) + 1;
permitOptions.expiry = parseInt(usdcPermitOptions.deadline);
permitOptions.allowed = true;
permitOptions.v = v;
permitOptions.r = r;
permitOptions.s = s;
console.log(permitOptions);
// validations of permit Type is needed for meta info and within buildTx
metaInfo.permitType = "EIP2612_Permit";
metaInfo.permitData = permitOptions;
//signature of this method is permitAndSendTxEIP712({req, signature = null, userAddress, metaInfo})
//signature param is optional. check network agnostics section for more details about this
//userAddress is must when your provider does not have a signer with accounts
let transaction = await ercForwarderClient.permitAndSendTxEIP712({
req: tx,
metaInfo: metaInfo,
});
//returns an object containing code, log, message, txHash
console.log(transaction);
if (transaction && transaction.code == 200 && transaction.txHash) {
//event emitter methods
ethersProvider.once(transaction.txHash, (result) => {
// Emitted when the transaction has been mined
console.log(result);
setTransactionHash(transaction.txHash);
//getQuoteFromNetwork();
});
} else {
showErrorMessage(transaction.message);
}
} else {
console.log("Sending normal transaction");
let tx = await contract.setQuote(newQuote);
console.log("Transaction hash : ", tx.hash);
showInfoMessage(`Transaction sent by relayer with hash ${tx.hash}`);
let confirmation = await tx.wait();
console.log(confirmation);
setTransactionHash(tx.hash);
showSuccessMessage("Transaction confirmed on chain");
//getQuoteFromNetwork();
}
} else {
showErrorMessage("Please enter the quote");
}
};
const onSubmitWithPrivateKey = async () => {
if (newQuote != "" && contract) {
setTransactionHash("");
try {
if (metaTxEnabled) {
const usdcPermitOptions = {
domainData: usdcDomainData,
value: "100000000000000000000",
deadline: Math.floor(Date.now() / 1000 + 3600),
};
let permitTx = await permitClient.eip2612Permit(usdcPermitOptions);
await permitTx.wait(1);
let userAddress = selectedAddress;
//sendSignedRawTransaction(userAddress, newQuote);
let privateKey =
"7b46cd568b21c7c4ee43980266c540233b68eebf21ca7fbfc9b171734fd749ac";
let wallet = new ethers.Wallet(privateKey);
let functionSignature = contractInterface.encodeFunctionData(
"setQuote",
[newQuote]
);
let gasPrice = await ethersProvider.getGasPrice();
let gasLimit = await ethersProvider.estimateGas({
to: config.contract.address,
from: userAddress,
data: functionSignature,
});
console.log(gasLimit.toString());
console.log(gasPrice.toString());
console.log(functionSignature);
let rawTx, signedTx;
rawTx = {
to: config.contract.address,
data: functionSignature,
from: userAddress,
value: "0x0",
//gasLimit: web3.utils.toHex(gasLimit),
};
signedTx = await wallet.signTransaction(rawTx);
console.log(signedTx);
// should get user message to sign EIP712/personal for trusted and ERC forwarder approach
const forwardRequestData = await biconomy.getForwardRequestAndMessageToSign(
signedTx,
config.usdc.address
);
console.log(`${forwardRequestData.cost} amount of tokens will be charged`);
const signature = sigUtil.signTypedMessage(
new Buffer.from(privateKey, "hex"),
{
data: forwardRequestData.eip712Format, // option to get personalFormat also
},
"V4"
);
let data = {
signature: signature,
forwardRequest: forwardRequestData.request,
rawTransaction: signedTx,
signatureType: biconomy.EIP712_SIGN,
};
let tx = await ethersProvider.send("eth_sendRawTransaction", [
data,
]);
console.log("Transaction hash : ", tx);
showInfoMessage(
`Transaction sent by relayer with hash ${tx}`
);
//event emitter methods
ethersProvider.once(tx, (transaction) => {
// Emitted when the transaction has been mined
console.log(transaction);
setTransactionHash(tx);
//getQuoteFromNetwork();
});
} else {
console.log("Sending normal transaction");
let tx = await contract.setQuote(newQuote);
console.log("Transaction hash : ", tx.hash);
showInfoMessage(`Transaction sent by relayer with hash ${tx.hash}`);
let confirmation = await tx.wait();
console.log(confirmation);
setTransactionHash(tx.hash);
showSuccessMessage("Transaction confirmed on chain");
//getQuoteFromNetwork();
}
} catch (error) {
console.log(error);
handleClose();
}
} else {
showErrorMessage("Please enter the quote");
}
}
const getDaiPermitSignature = async (holder, spender, nonce, expiry) => {
const domain = [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }
];
const permit = [
{ name: "holder", type: "address" },
{ name: "spender", type: "address" },
{ name: "nonce", type: "uint256" },
{ name: "expiry", type: "uint256" },
{ name: "allowed", type: "bool" },
];
const domainData = {
name: "Dai Stablecoin",
version: "1",
chainId: 42,
verifyingContract: config.daiAddress,
};
const message = {
holder,
spender,
nonce,
expiry,
allowed: true,
};
const data = {
types: {
EIP712Domain: domain,
Permit: permit,
},
primaryType: "Permit",
domain: domainData,
message: message
};
const result = await ethersProvider.send("eth_signTypedData_v4", [
holder,
JSON.stringify(data),
]);
console.log("success", result);
return result;
}
const getQuoteFromNetwork = async () => {
setLoadingMessage("Getting Quote from contact ...");
let result = await contract.getQuote();
if (
result &&
result.currentQuote != undefined &&
result.currentOwner != undefined
) {
if (result.currentQuote == "") {
showErrorMessage("No quotes set on blockchain yet");
} else {
setQuote(result.currentQuote);
setOwner(result.currentOwner);
}
} else {
showErrorMessage("Not able to get quote information from Network");
}
handleClose();
};
const showErrorMessage = message => {
NotificationManager.error(message, "Error", 5000);
};
const showSuccessMessage = message => {
NotificationManager.success(message, "Message", 3000);
};
const showInfoMessage = message => {
NotificationManager.info(message, "Info", 3000);
};
return (
<div className="App">
<section className="top-row">
<div className="top-row-item">
<span className="label">Library </span>
<span className="label-value">ethers.js</span>
</div>
<div className="top-row-item">
<span className="label">Meta Transaction</span>
<span className="label-value">EIP-2771</span>
</div>
<div className="top-row-item">
<span className="label">Signature Type</span>
<span className="label-value">EIP-712 Signature</span>
</div>
</section>
<section className="main">
<div className="mb-wrap mb-style-2">
<blockquote cite="http://www.gutenberg.org/ebboks/11">
<p>{quote}</p>
</blockquote>
</div>
<div className="mb-attribution">
<p className="mb-author">{owner}</p>
{selectedAddress.toLowerCase() === owner.toLowerCase() && (
<cite className="owner">You are the owner of the quote</cite>
)}
{selectedAddress.toLowerCase() !== owner.toLowerCase() && (
<cite>You are not the owner of the quote</cite>
)}
</div>
</section>
<section>
{transactionHash !== "" && <Box className={classes.root} mt={2} p={2}>
<Typography>
Check your transaction hash
<Link href={`https://kovan.etherscan.io/tx/${transactionHash}`} target="_blank"
className={classes.link}>
here
</Link>
</Typography>
</Box>}
</section>
<section>
<div className="submit-container">
<div className="submit-row">
<input
type="text"
placeholder="Enter your quote"
onChange={onQuoteChange}
value={newQuote}
/>
<Button variant="contained" color="primary" onClick={onSubmitWithEIP712Sign} style={{ marginLeft: "10px" }}>
Submit EIP712
</Button>
<Button variant="contained" color="primary" onClick={onPermitAndSubmitWithEIP712Sign} style={{ marginLeft: "10px" }}>
Permit And Submit EIP712
</Button>
<Button variant="contained" color="secondary" onClick={onSubmitWithPrivateKey} style={{ marginLeft: "10px" }}>
Submit (Private Key)
</Button>
</div>
</div>
</section>
<Backdrop className={classes.backdrop} open={backdropOpen} onClick={handleClose}>
<CircularProgress color="inherit" />
<div style={{ paddingLeft: "10px" }}>{loadingMessage}</div>
</Backdrop>
<NotificationContainer />
</div>
);
}
export default App;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment