Skip to content

Instantly share code, notes, and snippets.

@jdkanani
Last active March 19, 2019 17:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jdkanani/ffd27a8d11bd5178ab3451ca6a99c971 to your computer and use it in GitHub Desktop.
Save jdkanani/ffd27a8d11bd5178ab3451ca6a99c971 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.5.4+commit.9549d8ff.js&optimize=true&gist=
// pragma solidity >=0.4.22 <0.6.0;
pragma solidity >=0.5.2 <0.6.0;
import { ERC20 } from "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import { ERC20Detailed } from "openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol";
import { LibTokenTransferOrder } from "./libs/TokenTransferOrder.sol";
import { ECRecover } from "./libs/ECRecover.sol";
contract ChildERC20 is ERC20, ERC20Detailed, LibTokenTransferOrder, ECRecover {
mapping(bytes32 => bool) public disabledHashes;
constructor() public ERC20Detailed("ChildERC20", "CHE", 18) {}
function mint(uint256 amount) public {
_mint(msg.sender, amount);
}
function transferWithSig(bytes memory sig, uint256 amount, bytes32 data, uint256 expiration, address to) public returns (address) {
require(amount > 0);
require(expiration == 0 || block.number <= expiration, "Signature is expired");
bytes32 dataHash = getTokenTransferOrderHash(
msg.sender,
amount,
data,
expiration
);
require(disabledHashes[dataHash] == false, "Sig deactivated");
disabledHashes[dataHash] = true;
// recover address and send tokens
address from = recover(dataHash, sig);
_transfer(from, to, amount);
return from;
}
}
pragma solidity >=0.5.2 <0.6.0;
import { ERC721Full } from "openzeppelin-solidity/contracts/token/ERC721/ERC721Full.sol";
import { LibTokenTransferOrder } from "./libs/TokenTransferOrder.sol";
import { ECRecover } from "./libs/ECRecover.sol";
contract ChildERC721 is ERC721Full, LibTokenTransferOrder, ECRecover {
mapping(bytes32 => bool) public disabledHashes;
// constructor
constructor () ERC721Full("Test NFT", "NFT") public {
}
function mint(uint256 tokenId) public {
_mint(msg.sender, tokenId);
}
function transferWithSig(bytes memory sig, uint256 tokenId, bytes32 data, uint256 expiration, address to) public returns (address) {
require(expiration == 0 || block.number <= expiration, "Signature is expired");
bytes32 dataHash = getTokenTransferOrderHash(
msg.sender,
tokenId,
data,
expiration
);
require(disabledHashes[dataHash] == false, "Sig deactivated");
disabledHashes[dataHash] = true;
// recover address and send tokens
address from = recover(dataHash, sig);
// safeTransferFrom
_transferFrom(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, ""));
return from;
}
}
// pragma solidity >=0.4.22 <0.6.0;
pragma solidity >=0.5.2 <0.6.0;
contract ECRecover {
function recover(bytes32 dataHash, bytes memory sig) internal pure returns (address) {
bytes32 hash = dataHash; // keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", dataHash));
bytes32 r;
bytes32 s;
uint8 v;
// Check the signature length
if (sig.length != 65) {
return address(0x0);
}
assembly {
r := mload(add(sig, 32))
s := mload(add(sig, 64))
v := byte(0, mload(add(sig, 96)))
}
return ecrecover(hash, v, r, s);
}
}
// pragma solidity >=0.4.22 <0.6.0;
pragma solidity >=0.5.2 <0.6.0;
contract LibEIP712Domain {
string constant internal EIP712_DOMAIN_SCHEMA = "EIP712Domain(string name,string version,uint256 chainId,address contract)";
bytes32 constant public EIP712_DOMAIN_SCHEMA_HASH = keccak256(abi.encodePacked(EIP712_DOMAIN_SCHEMA));
string constant internal EIP712_DOMAIN_NAME = "Matic Network";
string constant internal EIP712_DOMAIN_VERSION = "1";
uint256 constant internal EIP712_DOMAIN_CHAINID = 13;
bytes32 public EIP712_DOMAIN_HASH;
constructor () public {
EIP712_DOMAIN_HASH = keccak256(abi.encode(
EIP712_DOMAIN_SCHEMA_HASH,
keccak256(bytes(EIP712_DOMAIN_NAME)),
keccak256(bytes(EIP712_DOMAIN_VERSION)),
EIP712_DOMAIN_CHAINID,
address(this)
));
}
function hashEIP712Message(bytes32 hashStruct) internal view returns (bytes32 result) {
bytes32 domainHash = EIP712_DOMAIN_HASH;
// Assembly for more efficient computing:
// keccak256(abi.encode(
// EIP191_HEADER,
// domainHash,
// hashStruct
// ));
assembly {
// Load free memory pointer
let memPtr := mload(64)
mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000) // EIP191 header
mstore(add(memPtr, 2), domainHash) // EIP712 domain hash
mstore(add(memPtr, 34), hashStruct) // Hash of struct
// Compute hash
result := keccak256(memPtr, 66)
}
return result;
}
}
pragma solidity >=0.5.2 <0.6.0;
interface MarketplaceToken {
function transferWithSig(bytes calldata sig, uint256 tokenIdOrAmount, bytes32 data, uint256 expiration, address to) external returns (address);
}
contract Marketplace {
function executeOrder(
address token1,
bytes memory sig1,
uint256 tokenIdOrAmount1,
address token2,
bytes memory sig2,
uint256 tokenIdOrAmount2,
bytes32 orderId,
uint256 expiration,
address address2 // address of second participant
) public {
// Transferring token1 tokens from `address1` to `msg.sender`
address _address1 = MarketplaceToken(token1).transferWithSig(
sig1,
tokenIdOrAmount1,
keccak256(abi.encodePacked(orderId, token2, tokenIdOrAmount2)),
expiration,
address2
);
// Transferring token2 from `msg.sender` to `msg.sender`
address _address2 = MarketplaceToken(token2).transferWithSig(
sig2,
tokenIdOrAmount2,
keccak256(abi.encodePacked(orderId, token1, tokenIdOrAmount1)),
expiration,
_address1
);
require(address2 == _address2);
}
}
// pragma solidity >=0.4.22 <0.6.0;
pragma solidity >=0.5.2 <0.6.0;
import { LibEIP712Domain } from "./EIP712.sol";
contract LibTokenTransferOrder is LibEIP712Domain {
string constant internal EIP712_TOKEN_TRANSFER_ORDER_SCHEMA = "TokenTransferOrder(address spender,uint256 tokenIdOrAmount,bytes32 data,uint256 expiration)";
bytes32 constant public EIP712_TOKEN_TRANSFER_ORDER_SCHEMA_HASH = keccak256(abi.encodePacked(EIP712_TOKEN_TRANSFER_ORDER_SCHEMA));
struct TokenTransferOrder {
address spender;
uint256 tokenIdOrAmount;
bytes32 data;
uint256 expiration;
}
function getTokenTransferOrderHash(address spender, uint256 tokenIdOrAmount, bytes32 data, uint256 expiration)
public
view
returns (bytes32 orderHash)
{
orderHash = hashEIP712Message(hashTokenTransferOrder(spender, tokenIdOrAmount, data, expiration));
}
function hashTokenTransferOrder(address spender, uint256 tokenIdOrAmount, bytes32 data, uint256 expiration)
internal
pure
returns (bytes32 result)
{
bytes32 schemaHash = EIP712_TOKEN_TRANSFER_ORDER_SCHEMA_HASH;
// Assembly for more efficiently computing:
// return keccak256(abi.encode(
// schemaHash,
// spender,
// tokenIdOrAmount,
// data,
// expiration
// ));
assembly {
// Load free memory pointer
let memPtr := mload(64)
mstore(memPtr, schemaHash) // hash of schema
mstore(add(memPtr, 32), and(spender, 0xffffffffffffffffffffffffffffffffffffffff)) // spender
mstore(add(memPtr, 64), tokenIdOrAmount) // tokenIdOrAmount
mstore(add(memPtr, 96), data) // hash of data
mstore(add(memPtr, 128), expiration) // expiration
// Compute hash
result := keccak256(memPtr, 160)
}
return result;
}
}
@jdkanani
Copy link
Author

jdkanani commented Mar 3, 2019

Starting migrations...

Network name: 'matic'
Network id: 13
Block gas limit: 1000000000000000

1_initial_migration.js


Total cost: 0 ETH

2_marketplace.js

Replacing 'ChildERC20'

transaction hash: 0x8cfb2c201b0eef81662a7011016a188a0842950ef90a0fef5a0567053fddffb5
Blocks: 9 Seconds: 10
contract address: 0x1E4E495305423c12E879cE528d59ac951835d2b6
account: 0x9fB29AAc15b9A4B7F17c3385939b007540f4d791
balance: 904625697166532776746648320380374280103671755200316892102.87468889104610481
gas used: 1940928
gas price: 0 gwei
value sent: 0 ETH
total cost: 0 ETH

Replacing 'ChildERC721'

transaction hash: 0xbc1dedefe67bd4c3c0720019fa95d51c22d5e217d39a38ea4f5893a5daa4d91c
Blocks: 5 Seconds: 6
contract address: 0xdC73315435E087aaAC7d744040641E9E04677Aaa
account: 0x9fB29AAc15b9A4B7F17c3385939b007540f4d791
balance: 904625697166532776746648320380374280103671755200316892102.87468889104610481
gas used: 2650655
gas price: 0 gwei
value sent: 0 ETH
total cost: 0 ETH

Replacing 'Marketplace'

transaction hash: 0x1e1e3174b1b3313f06c4c6b4cb490df57a41c5fea2c3166645371a5032d4b13b
Blocks: 5 Seconds: 6
contract address: 0x3186fbce3c7aF6f09d81651aA2bD163BB00AD8e5
account: 0x9fB29AAc15b9A4B7F17c3385939b007540f4d791
balance: 904625697166532776746648320380374280103671755200316892102.87468889104610481
gas used: 472303
gas price: 0 gwei
value sent: 0 ETH
total cost: 0 ETH

Saving artifacts


Total cost: 0 ETH

Summary

Total deployments: 3
Final cost: 0 ETH

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment