-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathUnlockProof.js
More file actions
93 lines (77 loc) · 3.5 KB
/
UnlockProof.js
File metadata and controls
93 lines (77 loc) · 3.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
const { Utils } = require("alchemy-sdk");
const { ethers } = require('hardhat');
const { Web3 } = require("web3");
const {Header, Account} = require('eth-object');
const _utils = require('ethereumjs-util');
const borsh = require('borsh')
const mappingSlotNumber = 302;
function hexToBytes(str) {
return Utils.arrayify("0x" + str);
}
function processedHash(_token, _recipient, _nonce, _amount) {
let encodedData = ethers.solidityPacked(["address", "address", "uint256", "uint256"],[_token, _recipient, _nonce, _amount]);
return ethers.solidityPackedKeccak256(["bytes"],[encodedData]);
}
function getProcessedHashSlotKey(processedHash){
const paddedSlot = ethers.zeroPadValue(ethers.toBeArray(mappingSlotNumber), 32);
const paddedKey = ethers.zeroPadValue(processedHash, 32);
return ethers.keccak256(paddedKey + paddedSlot.slice(2));
}
async function getProofOfData(contractAddress, slotKey, blockNumber, web3) {
return await web3.eth.getProof(contractAddress, [slotKey], blockNumber);
}
async function getBlockData(blockNumber, ethRpcEndpointURL) {
const response = await fetch(ethRpcEndpointURL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: '2.0',
method: `eth_getBlockByNumber`,
params: ["0x" + parseInt(blockNumber).toString(16), false],
id: 0
})
});
return (await response.json())["result"];
}
async function generateUnlockProof(getProofResponse, block, web3){
let headerRlp = (Header.fromRpc(block).serialize()).toString("hex");
let accountProof = getProofResponse.accountProof.map((proof_data) => (hexToBytes(_utils.toBuffer(proof_data).toString('hex')))); //converts to bytes array of account proof
let res = getProofResponse;
res.nonce = web3.utils.toHex(res.nonce); // done for fixing error in eth-object for Account
res.balance = web3.utils.toHex(res.balance); // done for fixing error in eth-object for Account
let accountData = (Account.fromRpc(res).serialize()).toString('hex');
let storageProof = getProofResponse.storageProof[0].proof.map((proof_data) => (hexToBytes(_utils.toBuffer(proof_data).toString('hex'))));
const unlockProof = {
header_data: hexToBytes(headerRlp),
account_proof: accountProof,
account_data: hexToBytes(accountData),
storage_proof: storageProof,
}
return unlockProof;
}
class Assignable {
constructor(properties) {
Object.keys(properties).map((key) => {
this[key] = properties[key];
});
}
}
class Test extends Assignable { }
async function getUnlockProof(contractAddress, data, blockNumber, ethRpcEndpointURL) {
const web3 = new Web3(ethRpcEndpointURL);
let processHash = processedHash(data.token, data.recipient, data.nonce, data.amount);
let slotKeyOfProcessedHash = getProcessedHashSlotKey(processHash);
let responseData = await getProofOfData(contractAddress, slotKeyOfProcessedHash, blockNumber, web3);
let block = await getBlockData(blockNumber, ethRpcEndpointURL);
let unlockProof = await generateUnlockProof(responseData, block, web3);
let borshSer = borsh.serialize(
new Map([[Test, {kind: 'struct',
fields: [['header_data', ['u8']],
['account_proof', [['u8']]],
['account_data', ['u8']],
['storage_proof', [['u8']]]]}]]), new Test(unlockProof));
return borshSer.toString("base64");
}
exports.getUnlockProof = getUnlockProof;