-
Notifications
You must be signed in to change notification settings - Fork 28
/
sample-test.ts
309 lines (259 loc) · 11.6 KB
/
sample-test.ts
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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
import { expect } from "chai";
import { starknet } from "hardhat";
import { StarknetContractFactory, Account } from "hardhat/types/runtime";
import { TIMEOUT } from "./constants";
import { BigNumber } from "ethers";
import {
expectFeeEstimationStructure,
expectStarknetPluginError,
expectStarknetPluginErrorContain,
OK_TX_STATUSES,
expectAddressEquality,
getOZAccount
} from "./util";
describe("Starknet", function () {
this.timeout(TIMEOUT);
let preservedAddress: string;
let preservedDeployTxHash: string;
let contractFactory: StarknetContractFactory;
let eventsContractFactory: StarknetContractFactory;
let account: Account;
const MAX_FEE = BigInt(1e18); // should be enough for all cases
before(async function () {
account = await getOZAccount();
console.log(`Using account at ${account.address} with public key ${account.publicKey}`);
contractFactory = await starknet.getContractFactory("contract");
await account.declare(contractFactory);
eventsContractFactory = await starknet.getContractFactory("events");
await account.declare(eventsContractFactory);
console.log("Declared classes");
console.log("Started deployment");
const contract = await account.deploy(contractFactory, { initial_balance: 0 });
console.log("Deployment transaction hash:", contract.deployTxHash);
expect(contract.deployTxHash.startsWith("0x")).to.be.true;
preservedDeployTxHash = contract.deployTxHash;
console.log("Deployed at", contract.address);
expect(contract.address.startsWith("0x")).to.be.true;
preservedAddress = contract.address;
const { res: balanceBefore } = await contract.call("get_balance");
expect(balanceBefore).to.deep.equal(0n);
});
it("should invoke and call on a loaded contract", async function () {
const contract = contractFactory.getContractAt(preservedAddress);
const { res: balanceBefore } = await contract.call("get_balance");
const txHash = await account.invoke(contract, "increase_balance", {
amount1: 10,
amount2: 20
});
expect(txHash.startsWith("0x")).to.be.true;
console.log("Invoke tx hash: ", txHash);
console.log("Increased by 10 + 20");
const { res: balanceAfter } = await contract.call("get_balance");
expect(balanceAfter).to.deep.equal(balanceBefore + 30n);
});
it("should fail on invoke", async function () {
const contract = contractFactory.getContractAt(preservedAddress);
try {
await account.invoke(
contract,
"increase_balance",
{ amount1: 10, amount2: 20 },
{ maxFee: MAX_FEE, overhead: 2 }
);
expect.fail("Should have failed on invoking using options with maxFee and overhead.");
} catch (err) {
expectStarknetPluginErrorContain(
err,
"maxFee and overhead cannot be specified together"
);
}
});
it("should work with tuples", async function () {
const contract = contractFactory.getContractAt(preservedAddress);
// passing Points (1, 2) and (3, 4) in a tuple
const { res: sum } = await contract.call("sum_points_to_tuple", {
points: [
{ x: 1, y: 2 },
{ x: 3, y: 4 }
]
});
expect(sum).to.deep.equal([4n, 6n]);
});
it("should work with complex tuples", async function () {
const contract = contractFactory.getContractAt(preservedAddress);
// passing PointPair ((1, 2), (3, 4), 5)
// the five is an extra number added to each member of the sum Point
const { res: sum } = await contract.call("sum_point_pair", {
pointPair: {
p1: { x: 1, y: 2 },
p2: { x: 3, y: 4 },
extra: 5
}
});
expect(sum).to.deep.equal({ x: 9n, y: 11n });
});
async function testArray(args: { a: number[] }, expected: bigint) {
const contract = contractFactory.getContractAt(preservedAddress);
const { res: sum } = await contract.call("sum_array", args);
expect(sum).to.deep.equal(expected);
}
it("should work with a non-empty array", async function () {
await testArray({ a: [1, 2, 3, 4] }, 10n);
});
it("should work with an empty array", async function () {
await testArray({ a: [] }, 0n);
});
it("should work with returned arrays", async function () {
const contract = contractFactory.getContractAt(preservedAddress);
const a = [1n, 2n, 3n];
const execution = await contract.call("identity", { a });
const arrLengthSquared = a.length * a.length;
expect(execution).to.deep.equal({
res: a,
res_len: BigInt(a.length),
res_len_squared: BigInt(arrLengthSquared)
});
});
it("should work with imported custom functions", async function () {
const contract = contractFactory.getContractAt(preservedAddress);
const { res: res0 } = await contract.call("use_almost_equal", { a: 1, b: 3 });
expect(res0).to.deep.equal(0n); // 0 as in false
const { res: res1 } = await contract.call("use_almost_equal", { a: 1, b: 2 });
expect(res1).to.deep.equal(1n); // 1 as in true
});
it("should work with number, BigInt, decimal string, hex string, BigNumber", async function () {
const contract = contractFactory.getContractAt(preservedAddress);
const a = [
10, // number
10n, // BigInt with -n syntax
BigInt(10), // BigInt with wrapper function
"10", // decimal string
"0xa", // hex string
"0xA", // capital hex string
BigNumber.from(10) // BigNumber
];
const { res } = await contract.call("sum_array", { a });
expect(res).to.deep.equal(70n);
});
it("should handle reverted transactions", async function () {
const contract = contractFactory.getContractAt(preservedAddress);
const { res: balanceBeforeEven } = await contract.call("get_balance");
// should pass
const txHash = await account.invoke(contract, "increase_balance_with_even", { amount: 2n });
expect(txHash.startsWith("0x")).to.be.true;
console.log("Tx hash: ", txHash);
const { res: balanceAfterEven } = await contract.call("get_balance");
expect(balanceAfterEven).to.deep.equal(balanceBeforeEven + 2n);
try {
await account.invoke(
contract,
"increase_balance_with_even",
{ amount: 3 },
{ maxFee: MAX_FEE }
);
expect.fail("Should have failed on invoking with an odd number.");
} catch (err) {
const error = expectStarknetPluginError(err);
expect(error.message).to.deep.contain("REVERTED");
expect(error.message).to.deep.contain("An ASSERT_EQ instruction failed: 1 != 0.");
}
});
it("should deploy to the same address if using salt", async function () {
const salt = "0xa0";
const contract = await account.deploy(contractFactory, { initial_balance: 0 }, { salt });
console.log("Deployed at", contract.address);
try {
await account.deploy(contractFactory, { initial_balance: 0 }, { salt });
} catch (err) {
const error = expectStarknetPluginError(err);
expect(error.message).to.include("CONTRACT_ADDRESS_UNAVAILABLE");
expect(error.message).to.include(
`Requested contract address ${contract.address} is unavailable for deployment`
);
}
});
it("should work with negative inputs", async function () {
const contract = contractFactory.getContractAt(preservedAddress);
const { res: currentBalance } = await contract.call("get_balance");
const amount1 = -1;
const amount2 = -3;
const expectedBalance = currentBalance + BigInt(amount1) + BigInt(amount2);
const txHash = await account.invoke(contract, "increase_balance", { amount1, amount2 });
expect(txHash.startsWith("0x")).to.be.true;
console.log("Tx hash: ", txHash);
const { res: sum } = await contract.call("get_balance");
expect(sum).to.deep.equal(expectedBalance);
const { res: sumArray } = await contract.call("sum_array", { a: [-1, -2, -3, -4] });
expect(sumArray).to.deep.equal(-10n);
});
it("should work with an array of struct", async function () {
const contract = contractFactory.getContractAt(preservedAddress);
const { res: res } = await contract.call("increment_point_array", {
a: [
{ x: -1, y: -3 },
{ x: 2, y: -2 }
],
i: 1
});
// Array for this function is returned in reverse due to cairo limitations
const respArray = [
{ x: 3n, y: -1n },
{ x: 0n, y: -2n }
];
expect(res).to.deep.equal(respArray);
const pointsArray = [
{ x: -1n, y: -3n },
{ x: 2n, y: -2n }
];
const complexArray = [
{ i: 1n, point: { x: 4n, y: 6n }, m: 2n },
{ i: 3n, point: { x: 9n, y: 8n }, m: 3n }
];
const { points: pointsResp, complex_struct: complexResp } = await contract.call(
"complex_array",
{ a: pointsArray, i: 1, b: complexArray }
);
expect(pointsResp).to.deep.equal(pointsArray);
expect(complexResp).to.deep.equal(complexArray);
});
it("should retrieve transaction details", async function () {
const contract = await account.deploy(eventsContractFactory);
const txHash = await account.invoke(
contract,
"increase_balance",
{ amount: 10 },
{ maxFee: MAX_FEE }
);
const tx = await starknet.getTransaction(txHash);
console.log(tx);
expect(tx.transaction.transaction_hash).to.deep.equal(txHash);
expect(tx.status).to.be.oneOf(OK_TX_STATUSES);
expect(BigInt(tx.transaction.max_fee)).to.deep.equal(MAX_FEE);
expectAddressEquality(tx.transaction.sender_address, account.address);
const receipt = await starknet.getTransactionReceipt(txHash);
console.log(receipt);
expect(receipt.transaction_hash).to.deep.equal(txHash);
expect(receipt.status).to.be.oneOf(OK_TX_STATUSES);
expectAddressEquality(receipt.events[0].from_address, contract.address);
});
it("should estimate fee", async function () {
const contract = contractFactory.getContractAt(preservedAddress);
const fee = await account.estimateFee(contract, "increase_balance", {
amount1: 10,
amount2: 20
});
expectFeeEstimationStructure(fee);
});
it("should handle block data", async function () {
const tx = await starknet.getTransaction(preservedDeployTxHash);
// Get block by hash
const blockByHash = await starknet.getBlock({ blockHash: tx.block_hash });
expect(blockByHash.transactions).to.include(preservedDeployTxHash);
// Get block by number
const blockByNumber = await starknet.getBlock({ blockNumber: tx.block_number });
expect(blockByHash).to.deep.equal(blockByNumber);
// Get latest block data
const latestBlock = await starknet.getBlock();
expect(latestBlock.block_number).to.be.greaterThanOrEqual(blockByHash.block_number);
});
});