Last active
September 8, 2020 20:55
-
-
Save JTraversa/fe2a1363b5ec30a9b645f9545b2b5904 to your computer and use it in GitHub Desktop.
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
function createErcOffer() { | |
const typedData = { | |
types: { | |
EIP712Domain: [ | |
{ name: 'name', type: 'string' }, | |
{ name: 'version', type: 'string' }, | |
{ name: 'chainId', type: 'uint256' }, | |
{ name: 'verifyingContract', type: 'address' } | |
], | |
Offer: [ | |
{ name: "maker", type: "address" }, | |
{ name: "taker", type: "address" }, | |
{ name: "side", type: "uint256" }, | |
{ name: "tokenAddress", type: "address" }, | |
{ name: "duration", type: "uint256" }, | |
{ name: "rate", type: "uint256" }, | |
{ name: "interest", type: "uint256" }, | |
{ name: "base", type: "uint256" }, | |
], | |
}, | |
primaryType: 'Offer', | |
domain: { | |
name: 'DefiHedge', | |
version: '1', | |
chainId: 3, | |
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC' | |
}, | |
message: { | |
maker: "0x00fE460A15B49d09F39b057D0f1A7B9444F4F2BE", | |
taker: "0x0000000000000000000000000000000000000000", | |
side: 0, | |
tokenAddress: "0xc2118d4d90b274016cb7a54c03ef52e6c537d957", | |
duration: _duration, | |
rate: _rate, | |
interest: _interest, | |
base: _supplied, | |
}, | |
}; | |
const types = typedData.types; | |
// Recursively finds all the dependencies of a type | |
function dependencies(primaryType, found = []) { | |
if (found.includes(primaryType)) { | |
return found; | |
} | |
if (types[primaryType] === undefined) { | |
return found; | |
} | |
found.push(primaryType); | |
for (let field of types[primaryType]) { | |
for (let dep of dependencies(field.type, found)) { | |
if (!found.includes(dep)) { | |
found.push(dep); | |
} | |
} | |
} | |
return found; | |
} | |
function encodeType(primaryType) { | |
// Get dependencies primary first, then alphabetical | |
let deps = dependencies(primaryType); | |
deps = deps.filter(t => t != primaryType); | |
deps = [primaryType].concat(deps.sort()); | |
// Format as a string with fields | |
let result = ''; | |
for (let type of deps) { | |
result += `${type}(${types[type].map(({ name, type }) => `${type} ${name}`).join(',')})`; | |
} | |
return result; | |
} | |
function typeHash(primaryType) { | |
return EthJS.Util.keccak256(encodeType(primaryType)); | |
} | |
function encodeData(primaryType, data) { | |
let encTypes = []; | |
let encValues = []; | |
// Add typehash | |
encTypes.push('bytes32'); | |
encValues.push(typeHash(primaryType)); | |
// Add field contents | |
for (let field of types[primaryType]) { | |
let value = data[field.name]; | |
if (field.type == 'string' || field.type == 'bytes') { | |
encTypes.push('bytes32'); | |
value = EthJS.Util.keccak256(value); | |
encValues.push(value); | |
} else if (types[field.type] !== undefined) { | |
encTypes.push('bytes32'); | |
value = EthJS.Util.keccak256(encodeData(field.type, value)); | |
encValues.push(value); | |
} else if (field.type.lastIndexOf(']') === field.type.length - 1) { | |
throw 'TODO: Arrays currently unimplemented in encodeData'; | |
} else { | |
encTypes.push(field.type); | |
encValues.push(value); | |
} | |
} | |
return ethereumjs.ABI.rawEncode(encTypes, encValues); | |
} | |
function structHash(primaryType, data) { | |
return EthJS.Util.keccak256(encodeData(primaryType, data)); | |
} | |
function signHash() { | |
return EthJS.Util.keccak256( | |
Buffer.concat([ | |
Buffer.from('1901', 'hex'), | |
structHash('EIP712Domain', typedData.domain), | |
structHash(typedData.primaryType, typedData.message), | |
]), | |
); | |
} | |
var hash = signHash() | |
const privateKey = Buffer.from("REDACTED", "hex"); | |
const address = EthJS.Util.privateToAddress(privateKey); | |
const sig = EthJS.Util.ecsign(hash,privateKey); | |
console.log(sig); | |
var pub = EthJS.Util.ecrecover(hash,sig.v,sig.r,sig.s); | |
var addrBuf = EthJS.Util.pubToAddress(pub); | |
var addr = EthJS.Util.bufferToHex(addrBuf); | |
sig.r = EthJS.Util.bufferToHex(sig.r); | |
sig.s = EthJS.Util.bufferToHex(sig.s); | |
sigr = sig.r.substring(2); | |
sigs = sig.s.substring(2); | |
sigv = sig.v.toString(); | |
var signature = sigr + sigs + sigv; | |
signature = "0x".concat(signature); | |
console.log(signature); | |
DefihedgeContract.fillOffer(typedData.message.maker, | |
typedData.message.taker, | |
typedData.message.side, | |
typedData.message.tokenAddress, | |
typedData.message.duration. | |
typedData.message.rate, | |
typedData.message.interest, | |
typedData.message.base, | |
signature,{ | |
from: currentAddress, | |
gas: "900000", | |
value: "", | |
data: "" }, function(error, result){ | |
if(!error) | |
console.log(result); | |
else | |
console.error(error); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is usually separated into 2 functions (creating the offer, submitting it as a taker), but I combined them to make it easier to understand.