Last active
November 4, 2024 16:12
-
-
Save Theo6890/7f05ba4581ad632514e3d57dc992c143 to your computer and use it in GitHub Desktop.
EIP712 Solidity & JS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/////////////// Ethers 5.x.x /////////////// | |
const { ethers } = require('ethers'); | |
/** | |
* Same data to be signed by both parties to make the exchange | |
* | |
* @param {ethers.Wallet} signer - Wallet instance | |
* | |
* @param {Object} domain - Domain of `EIP712` | |
* @param {string} domain.name - Name passed in EIP712 constructor | |
* @param {string} domain.version - Version passed in EIP712 constructor | |
* @param {ethers.BigNumber} domain.chaindId - Chain id where the contract is deployed | |
* @param {string} domain.contractAddr - Address of the contract | |
* | |
* @param {Object} exchange - Defined in interface {src/ISwapInternal.sol} | |
*/ | |
async function signExchange(signer, domain, exchange) { | |
const types = { | |
Data: [ | |
{ type: 'address', name: 'nft' }, | |
{ type: 'uint256', name: 'nftId' }, | |
{ type: 'address', name: 'to' }, | |
], | |
Exchange: [ | |
{ type: 'Data', name: 'partyOne' }, | |
{ type: 'Data', name: 'partyTwo' }, | |
{ type: 'uint256', name: 'deadline' }, | |
{ type: 'uint256', name: 'id' }, | |
], | |
}; | |
return await signer._signTypedData(domain, types, { | |
...exchange, | |
}); | |
} | |
module.exports = { signExchange }; | |
////////// Signer example ////////// | |
// const wallet = new ethers.Wallet.fromMnemonic(process.env.SEED); | |
////////// Domain example ////////// | |
/* const domain = { | |
name: 'Hand 2 Hand Exchange', // name used in Swap contract | |
version: '1', // version used in Swap contract | |
chainId: ethers.BigNumber.from('97'), | |
verifyingContract: '0x690B9A9E9aa1C9dB991C7721a92d351Db4FaC990', // Swap contract | |
}; */ | |
////////// Exchange example ////////// | |
/* | |
const exchange = { | |
partyOne: { | |
nft: '0x326374475908FC640C3DDE59981C721CafF9c828', // WincityPGC | |
nftId: 1, | |
to: '0x1f9090aaE28b8a3dCeaDf281B0F12828e676c326', | |
}, | |
partyTwo: { | |
nft: '0x326374475908FC640C3DDE59981C721CafF9c828', // WincityPGC | |
nftId: 20, | |
to: '0xE94f1fa4F27D9d288FFeA234bB62E1fBC086CA0c', | |
}, | |
deadline: 1627776000, | |
id: 234189124 // random id to define an exchange | |
} | |
*/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity 0.8.23; | |
import {EIP712} from "openzeppelin-contracts/utils/cryptography/EIP712.sol"; | |
import {ECDSA} from "openzeppelin-contracts/utils/cryptography/ECDSA.sol"; | |
contract Swap is EIP712 { | |
constructor() EIP712("Hand 2 Hand Exchange", "1") {} | |
struct Data { | |
IERC721 nft; | |
uint256 nftId; | |
address to; | |
} | |
struct Exchange { | |
// Data for party one - tx initiator | |
Data partyOne; | |
// Data for party two - tx validator | |
Data partyTwo; | |
uint256 deadline; | |
uint256 id; | |
} | |
function swap( | |
Exchange calldata exchange, | |
bytes calldata sigPartyOne, | |
bytes calldata sigPartyTwo | |
) external { | |
Data memory one = exchange.partyOne; | |
Data memory two = exchange.partyTwo; | |
// the one setting up `Exchange` data | |
address initiator = two.to; | |
// the one validating `Exchange` data and paying gas fee to make the swap | |
address validator = one.to; | |
bytes32 digest = _hashTypedDataV4(_hashSwap(exchange)); | |
require( | |
ECDSA.recover(digest, sigPartyOne) == initiator, | |
"Tx Initiator Recovery Failed" | |
); | |
require( | |
ECDSA.recover(digest, sigPartyTwo) == validator, | |
"TX Validator Recovery Failed" | |
); | |
... | |
rest of code logic | |
... | |
} | |
bytes32 internal constant _EXCHANGE_TYPEHASH = | |
keccak256( | |
"Exchange(bytes partyOne,bytes partyTwo,uint256 deadline,uint256 id)" | |
); | |
function _hashSwap( | |
Exchange calldata exchange | |
) internal pure returns (bytes32) { | |
return keccak256(abi.encode(_EXCHANGE_TYPEHASH, exchange)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment