-
Notifications
You must be signed in to change notification settings - Fork 7
/
test-utils.js
187 lines (152 loc) · 5.33 KB
/
test-utils.js
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
const hre = require("hardhat");
const ethers = hre.ethers;
const { keccak256, RLP } = ethers.utils;
function getEvent(receipt, factory, eventName) {
let found = false;
const eventFragment = factory.interface.fragments.filter((e) => e.name == eventName);
const iface = new ethers.utils.Interface(eventFragment);
for (const log in receipt.logs) {
const topics = receipt.logs[log].topics;
for (const index in topics) {
const encodedTopic = topics[index];
try {
// CHECK IF TOPIC CORRESPONDS TO THE EVENT GIVEN TO FN
const event = iface.getEvent(encodedTopic);
if (event.name == eventName) {
found = true;
const eventArgs = iface.parseLog(receipt.logs[log]).args;
return eventArgs;
}
} catch (e) {
if (e.message.includes("no matching event")) continue;
console.log("event error: ", e);
throw new Error(e);
}
}
}
if (!found) {
throw new Error(`Event with name ${eventName} was not emitted!`);
}
}
function eventEmittedWithArgs(receipt, factory, eventName, args) {
let found = false;
let match = false;
const eventFragment = factory.interface.fragments.filter((e) => e.name == eventName);
const iface = new ethers.utils.Interface(eventFragment);
for (const log in receipt.logs) {
const topics = receipt.logs[log].topics;
for (const index in topics) {
const encodedTopic = topics[index];
try {
// CHECK IF TOPIC CORRESPONDS TO THE EVENT GIVEN TO FN
const event = iface.getEvent(encodedTopic);
if (event.name == eventName) {
found = true;
const eventArgs = iface.parseLog(receipt.logs[log]).args;
match = compareArgs(eventArgs, args);
return match;
}
} catch (e) {
if (e.message.includes("no matching event")) continue;
console.log("event error: ", e);
throw new Error(e);
}
}
}
if (!found) {
throw new Error(`Event with name ${eventName} was not emitted!`);
}
}
function compareArgs(eventArgs, args) {
//loop over args because eventArgs always have 2 entries for each argument
let i = args.length;
while (i--) {
if (args[i] != eventArgs[i]) return false;
}
return true;
}
async function setNextBlockTimestamp(timestamp) {
await ethers.provider.send("evm_setNextBlockTimestamp", [timestamp]);
await ethers.provider.send("evm_mine", []);
}
function getSignatureParameters(signature) {
if (!ethers.utils.isHexString(signature)) {
throw new Error('Given value "'.concat(signature, '" is not a valid hex string.'));
}
signature = signature.substring(2);
const r = "0x" + signature.substring(0, 64);
const s = "0x" + signature.substring(64, 128);
const v = parseInt(signature.substring(128, 130), 16);
return {
r: r,
s: s,
v: v,
};
}
async function prepareDataSignatureParameters(
user,
customTransactionTypes,
primaryType,
message,
metaTransactionsHandlerAddress
) {
// Initialize data
const domainType = [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "verifyingContract", type: "address" },
{ name: "salt", type: "bytes32" },
];
const domainData = {
name: "Boson Protocol",
version: "V2",
verifyingContract: metaTransactionsHandlerAddress,
salt: ethers.utils.hexZeroPad(ethers.BigNumber.from(31337).toHexString(), 32), //hardhat default chain id is 31337
};
// Prepare the types
let metaTxTypes = {
EIP712Domain: domainType,
};
metaTxTypes = Object.assign({}, metaTxTypes, customTransactionTypes);
// Prepare the data to sign
let dataToSign = JSON.stringify({
types: metaTxTypes,
domain: domainData,
primaryType: primaryType,
message: message,
});
// Sign the data
const signature = await ethers.provider.send("eth_signTypedData_v4", [user.address, dataToSign]);
// Collect the Signature components
const { r, s, v } = getSignatureParameters(signature);
return {
r: r,
s: s,
v: v,
};
}
function calculateVoucherExpiry(block, voucherRedeemableFromDate, voucherValidDuration) {
const startDate = ethers.BigNumber.from(block.timestamp).gte(ethers.BigNumber.from(voucherRedeemableFromDate))
? ethers.BigNumber.from(block.timestamp)
: ethers.BigNumber.from(voucherRedeemableFromDate);
return startDate.add(ethers.BigNumber.from(voucherValidDuration)).toString();
}
function applyPercentage(base, percentage) {
return ethers.BigNumber.from(base).mul(percentage).div("10000").toString();
}
function calculateContractAddress(senderAddress, senderNonce) {
const nonce = ethers.BigNumber.from(senderNonce);
const nonceHex = nonce.eq(0) ? "0x" : nonce.toHexString();
const input_arr = [senderAddress, nonceHex];
const rlp_encoded = RLP.encode(input_arr);
const contract_address_long = keccak256(rlp_encoded);
const contract_address = "0x" + contract_address_long.substring(26); //Trim the first 24 characters.
return ethers.utils.getAddress(contract_address);
}
exports.setNextBlockTimestamp = setNextBlockTimestamp;
exports.getEvent = getEvent;
exports.eventEmittedWithArgs = eventEmittedWithArgs;
exports.prepareDataSignatureParameters = prepareDataSignatureParameters;
exports.calculateVoucherExpiry = calculateVoucherExpiry;
exports.calculateContractAddress = calculateContractAddress;
exports.applyPercentage = applyPercentage;