Skip to content

Instantly share code, notes, and snippets.

@JTraversa
Last active September 8, 2020 20:52
Show Gist options
  • Save JTraversa/43f1c09ba79b41f9ff1aa9110e4f1b95 to your computer and use it in GitHub Desktop.
Save JTraversa/43f1c09ba79b41f9ff1aa9110e4f1b95 to your computer and use it in GitHub Desktop.
struct RPCSig{
uint8 v;
bytes32 r;
bytes32 s;
}
struct EIP712Domain {
string name;
string version;
uint256 chainId;
address verifyingContract;
}
struct Offer {
address maker;
address taker;
uint256 side;
address tokenAddress;
uint256 duration;
uint256 rate;
uint256 interest;
uint256 base;
}
// Offer + EIP Domain Hash Schema
bytes32 constant EIP712DOMAIN_TYPEHASH = keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
bytes32 constant OFFER_TYPEHASH = keccak256(
"Offer(address maker,address taker,uint256 side,address tokenAddress,uint256 duration,uint256 rate,uint256 interest,uint256 base)"
);
function fillOffer(address maker, address taker, uint side, address tokenAddress, uint duration, uint rate, uint interest, uint base, bytes memory makerSignature) public returns (uint256){
/// Instantiate offer
Offer memory filledOffer = Offer(
maker,
address(0x0000000000000000000000000000000000000000),
side,
tokenAddress,
duration,
rate,
interest,
base
);
// Parse signature into R,S,V
RPCSig memory RPCsig = signatureRPC(makerSignature);
// Validate offer signature & ensure it was created by maker
require(maker == ecrecover(
keccak256(abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
hashOffer(filledOffer)
)),
RPCsig.v,
RPCsig.r,
RPCsig.s), "Invalid Signature");
// Require correct taker
require(msg.sender == taker, "Invalid Calling Address");
// Create unique offer hash
bytes32 offerKey = keccak256(abi.encodePacked((now),msg.sender));
uint value = interest.add(base);
// Settle Response
offerSettle(maker,taker,side,tokenAddress,duration,interest,base,value,offerKey);
offerMapping[offerKey].rate = rate;
offerList.push(offerKey);
emit newLockedOffer(offerKey,maker,taker,side,tokenAddress,duration,rate,interest,base);
function hashDomain(EIP712Domain memory eip712Domain) internal pure returns (bytes32) {
return keccak256(abi.encode(
EIP712DOMAIN_TYPEHASH,
keccak256(bytes(eip712Domain.name)),
keccak256(bytes(eip712Domain.version)),
eip712Domain.chainId,
eip712Domain.verifyingContract
));
}
function hashOffer(Offer memory _offer)private pure returns(bytes32){
return keccak256(abi.encode(
OFFER_TYPEHASH,
_offer.maker,
_offer.taker,
_offer.side,
_offer.tokenAddress,
_offer.duration,
_offer.rate,
_offer.interest,
_offer.base
));
}
function signatureRPC(bytes memory sig)internal pure returns (RPCSig memory RPCsig){
bytes32 r;
bytes32 s;
uint8 v;
if (sig.length != 65) {
return RPCSig(0,'0','0');
}
assembly {
r := mload(add(sig, 32))
s := mload(add(sig, 64))
v := and(mload(add(sig, 65)), 255)
}
if (v < 27) {
v += 27;
}
if (v == 39 || v == 40) {
v = v-12;
}
if (v != 27 && v != 28) {
return RPCSig(0,'0','0');
}
return RPCSig(v,r,s);
}
}
@JTraversa
Copy link
Author

Its probably more gas efficient to split the signature off-chain and submit it than submit it as 1 bytes string and split it on-chain like I am here.

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