From 076d75772e24ffc2b1581b065042288df2b83a3c Mon Sep 17 00:00:00 2001 From: Jonathan Claudius Date: Mon, 17 Apr 2023 23:28:31 -0400 Subject: [PATCH 001/218] Add forge unit-tests for Math256 --- test/common/lib/math-256.test.sol | 267 ++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 test/common/lib/math-256.test.sol diff --git a/test/common/lib/math-256.test.sol b/test/common/lib/math-256.test.sol new file mode 100644 index 000000000..f1b3c6ee9 --- /dev/null +++ b/test/common/lib/math-256.test.sol @@ -0,0 +1,267 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import "forge-std/Test.sol"; +import { Math256 } from "contracts/common/lib/MemUMath256.sol"; + +contract Math256Test is Test { + + /// int256 tests for max/min + + /// Simple max case: B greater than A + function testMaxUint256Simple1() public { + uint256 a = 1; + uint256 b = 2; + + assertEq(Math256.max(a, b), b); + } + + /// Simple max case: A greater than B + function testMaxUint256Simple2() public { + uint256 a = 1; + uint256 b = 2; + + assertEq(Math256.max(b, a), b); + } + + /// Simple max case: A equal to B + function testMaxUint256Simple3() public { + uint256 a = 1; + uint256 b = 1; + + assertEq(Math256.max(b, a), b); + } + + /// Fuzzing max for A and B + function testMaxUint256Fuzz(uint256 a, uint256 b) public { + uint256 expected; + + if (a > b) { + expected = a; + } else if (a == b) { + expected = a; + } else { + expected = b; + } + + assertEq(Math256.max(b, a), expected); + } + + /// Simple min case: B less than A + function testMinUint256Simple1() public { + uint256 a = 2; + uint256 b = 1; + + assertEq(Math256.min(a, b), b); + } + + /// Simple case: A less than B + function testMinUint256Simple2() public { + uint256 a = 1; + uint256 b = 2; + + assertEq(Math256.min(b, a), a); + } + + /// Simple case: A equal to B + function testMinUint256Simple3() public { + uint256 a = 1; + uint256 b = 1; + + assertEq(Math256.max(b, a), b); + } + + /// Fuzzing A and B + function testUint256MinFuzz(uint256 a, uint256 b) public { + uint256 expected; + + if (a < b) { + expected = a; + } else if (a == b) { + expected = a; + } else { + expected = b; + } + + assertEq(Math256.min(b, a), expected); + } + + /// int256 tests for max/min + + /// Simple max case: B greater than A + function testMaxInt256Simple1() public { + int256 a = 1; + int256 b = 2; + + assertEq(Math256.max(a, b), b); + } + + /// Simple max case: A greater than B + function testMaxInt256Simple2() public { + int256 a = 1; + int256 b = 2; + + assertEq(Math256.max(b, a), b); + } + + /// Simple max case: A equal to B + function testMaxInt256Simple3() public { + int256 a = 1; + int256 b = 1; + + assertEq(Math256.max(b, a), b); + } + + /// Fuzzing max for A and B + function testMaxInt256Fuzz(int256 a, int256 b) public { + int256 expected; + + if (a > b) { + expected = a; + } else if (a == b) { + expected = a; + } else { + expected = b; + } + + assertEq(Math256.max(b, a), expected); + } + + /// Simple min case: B less than A + function testMinInt256Simple1() public { + int256 a = 2; + int256 b = 1; + + assertEq(Math256.min(a, b), b); + } + + /// Simple case: A less than B + function testMinInt256Simple2() public { + int256 a = 1; + int256 b = 2; + + assertEq(Math256.min(b, a), a); + } + + /// Simple case: A equal to B + function testMinInt256Simple3() public { + int256 a = 1; + int256 b = 1; + + assertEq(Math256.max(b, a), b); + } + + /// Fuzzing A and B + function testInt256MinFuzz(int256 a, int256 b) public { + int256 expected; + + if (a < b) { + expected = a; + } else if (a == b) { + expected = a; + } else { + expected = b; + } + + assertEq(Math256.min(b, a), expected); + } + + /// tests for ceilDiv + + /// Simple case: division by zero + function testCeilDivByZero() public { + uint256 a = 1; + uint256 b = 0; + + vm.expectRevert("Division or modulo by 0"); + Math256.ceilDiv(a, b); + } + + /// Simple case: zero divided by x + function testCeilDivZeroFromFour() public { + uint256 a = 0; + uint256 b = 4; + assertEq(Math256.ceilDiv(a, b), 0); + } + + /// Simple case: division by 1 + function testCeilDivByOne() public { + uint256 a = 2; + uint256 b = 1; + + assertEq(Math256.ceilDiv(a, b), a); + } + + /// Simple case: division by 2 + function testCeilDivByTwo() public { + uint256 a = 4; + uint256 b = 2; + + assertEq(Math256.ceilDiv(a, b), b); + } + + /// Simple case: division by 3 (demonstrating round up) + function testCeilDivByThree() public { + uint256 a = 4; + uint256 b = 3; + + assertEq(Math256.ceilDiv(a, b), 2); + } + + /// Fuzz case CeilDiv + function testCeilDivFuzz(uint256 a, uint256 b) public { + // This case should always error + if (b == 0) { + vm.expectRevert("Division or modulo by 0"); + } + + // This case should always be zero + if (a == 0) { + assertEq(Math256.ceilDiv(a, b), 0); + } + + // When they are both equal, the orientation shouldn't matter, it should be 1 + if (a == b) { + assertEq(Math256.ceilDiv(a, b), 1); + assertEq(Math256.ceilDiv(b, a), 1); + } + + // It shouldn't crash unexpectedly + Math256.ceilDiv(a, b); + } + + /// tests for absDiff + + /// Simple case: absDiff of two zeros + function testAbsDiffZeros() public { + uint256 a = 0; + uint256 b = 0; + + assertEq(Math256.absDiff(b, a), 0); + } + + /// Simple case: absDiff of two ones + function testAbsDiffOnes() public { + uint256 a = 1; + uint256 b = 1; + + assertEq(Math256.absDiff(b, a), 0); + } + + /// Simple case: absDiff of two ones + function testAbsDiffFuzz(uint256 a, uint256 b) public { + // If they are the same, it's always zero + if (a == b) { + assertEq(Math256.absDiff(b, a), 0); + } + + // If one is zero, the difference should always be the other + if (a == 0) { + assertEq(Math256.absDiff(b, a), b); + } + + // It shouldn't unexpectedly crash + Math256.absDiff(b, a); + } + +} \ No newline at end of file From 758f0ede1897df855746d0e0b765682a6f79fe16 Mon Sep 17 00:00:00 2001 From: Jonathan Claudius Date: Mon, 17 Apr 2023 23:35:04 -0400 Subject: [PATCH 002/218] Remove overly verbose comments --- test/common/lib/math-256.test.sol | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/test/common/lib/math-256.test.sol b/test/common/lib/math-256.test.sol index f1b3c6ee9..a7993c5e8 100644 --- a/test/common/lib/math-256.test.sol +++ b/test/common/lib/math-256.test.sol @@ -8,7 +8,6 @@ contract Math256Test is Test { /// int256 tests for max/min - /// Simple max case: B greater than A function testMaxUint256Simple1() public { uint256 a = 1; uint256 b = 2; @@ -16,7 +15,6 @@ contract Math256Test is Test { assertEq(Math256.max(a, b), b); } - /// Simple max case: A greater than B function testMaxUint256Simple2() public { uint256 a = 1; uint256 b = 2; @@ -24,7 +22,6 @@ contract Math256Test is Test { assertEq(Math256.max(b, a), b); } - /// Simple max case: A equal to B function testMaxUint256Simple3() public { uint256 a = 1; uint256 b = 1; @@ -32,7 +29,6 @@ contract Math256Test is Test { assertEq(Math256.max(b, a), b); } - /// Fuzzing max for A and B function testMaxUint256Fuzz(uint256 a, uint256 b) public { uint256 expected; @@ -47,7 +43,6 @@ contract Math256Test is Test { assertEq(Math256.max(b, a), expected); } - /// Simple min case: B less than A function testMinUint256Simple1() public { uint256 a = 2; uint256 b = 1; @@ -55,7 +50,6 @@ contract Math256Test is Test { assertEq(Math256.min(a, b), b); } - /// Simple case: A less than B function testMinUint256Simple2() public { uint256 a = 1; uint256 b = 2; @@ -63,7 +57,6 @@ contract Math256Test is Test { assertEq(Math256.min(b, a), a); } - /// Simple case: A equal to B function testMinUint256Simple3() public { uint256 a = 1; uint256 b = 1; @@ -71,7 +64,6 @@ contract Math256Test is Test { assertEq(Math256.max(b, a), b); } - /// Fuzzing A and B function testUint256MinFuzz(uint256 a, uint256 b) public { uint256 expected; @@ -88,7 +80,6 @@ contract Math256Test is Test { /// int256 tests for max/min - /// Simple max case: B greater than A function testMaxInt256Simple1() public { int256 a = 1; int256 b = 2; @@ -96,7 +87,6 @@ contract Math256Test is Test { assertEq(Math256.max(a, b), b); } - /// Simple max case: A greater than B function testMaxInt256Simple2() public { int256 a = 1; int256 b = 2; @@ -104,7 +94,6 @@ contract Math256Test is Test { assertEq(Math256.max(b, a), b); } - /// Simple max case: A equal to B function testMaxInt256Simple3() public { int256 a = 1; int256 b = 1; @@ -112,7 +101,6 @@ contract Math256Test is Test { assertEq(Math256.max(b, a), b); } - /// Fuzzing max for A and B function testMaxInt256Fuzz(int256 a, int256 b) public { int256 expected; @@ -127,7 +115,6 @@ contract Math256Test is Test { assertEq(Math256.max(b, a), expected); } - /// Simple min case: B less than A function testMinInt256Simple1() public { int256 a = 2; int256 b = 1; @@ -135,7 +122,6 @@ contract Math256Test is Test { assertEq(Math256.min(a, b), b); } - /// Simple case: A less than B function testMinInt256Simple2() public { int256 a = 1; int256 b = 2; @@ -143,7 +129,6 @@ contract Math256Test is Test { assertEq(Math256.min(b, a), a); } - /// Simple case: A equal to B function testMinInt256Simple3() public { int256 a = 1; int256 b = 1; @@ -151,7 +136,6 @@ contract Math256Test is Test { assertEq(Math256.max(b, a), b); } - /// Fuzzing A and B function testInt256MinFuzz(int256 a, int256 b) public { int256 expected; @@ -168,7 +152,6 @@ contract Math256Test is Test { /// tests for ceilDiv - /// Simple case: division by zero function testCeilDivByZero() public { uint256 a = 1; uint256 b = 0; @@ -177,14 +160,12 @@ contract Math256Test is Test { Math256.ceilDiv(a, b); } - /// Simple case: zero divided by x function testCeilDivZeroFromFour() public { uint256 a = 0; uint256 b = 4; assertEq(Math256.ceilDiv(a, b), 0); } - /// Simple case: division by 1 function testCeilDivByOne() public { uint256 a = 2; uint256 b = 1; @@ -192,7 +173,6 @@ contract Math256Test is Test { assertEq(Math256.ceilDiv(a, b), a); } - /// Simple case: division by 2 function testCeilDivByTwo() public { uint256 a = 4; uint256 b = 2; @@ -200,7 +180,6 @@ contract Math256Test is Test { assertEq(Math256.ceilDiv(a, b), b); } - /// Simple case: division by 3 (demonstrating round up) function testCeilDivByThree() public { uint256 a = 4; uint256 b = 3; @@ -208,7 +187,6 @@ contract Math256Test is Test { assertEq(Math256.ceilDiv(a, b), 2); } - /// Fuzz case CeilDiv function testCeilDivFuzz(uint256 a, uint256 b) public { // This case should always error if (b == 0) { @@ -232,7 +210,6 @@ contract Math256Test is Test { /// tests for absDiff - /// Simple case: absDiff of two zeros function testAbsDiffZeros() public { uint256 a = 0; uint256 b = 0; @@ -240,7 +217,6 @@ contract Math256Test is Test { assertEq(Math256.absDiff(b, a), 0); } - /// Simple case: absDiff of two ones function testAbsDiffOnes() public { uint256 a = 1; uint256 b = 1; @@ -248,7 +224,6 @@ contract Math256Test is Test { assertEq(Math256.absDiff(b, a), 0); } - /// Simple case: absDiff of two ones function testAbsDiffFuzz(uint256 a, uint256 b) public { // If they are the same, it's always zero if (a == b) { @@ -263,5 +238,4 @@ contract Math256Test is Test { // It shouldn't unexpectedly crash Math256.absDiff(b, a); } - } \ No newline at end of file From 6bec866a007e762b7924c59c559a2afdbf8dc23e Mon Sep 17 00:00:00 2001 From: Jonathan Claudius Date: Tue, 18 Apr 2023 11:22:12 -0400 Subject: [PATCH 003/218] Fix import for Math256 --- test/common/lib/math-256.test.sol | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/common/lib/math-256.test.sol b/test/common/lib/math-256.test.sol index a7993c5e8..048e53d54 100644 --- a/test/common/lib/math-256.test.sol +++ b/test/common/lib/math-256.test.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.13; import "forge-std/Test.sol"; -import { Math256 } from "contracts/common/lib/MemUMath256.sol"; +import { Math256 } from "contracts/common/lib/Math256.sol"; contract Math256Test is Test { @@ -237,5 +237,4 @@ contract Math256Test is Test { // It shouldn't unexpectedly crash Math256.absDiff(b, a); - } -} \ No newline at end of file + } \ No newline at end of file From 3e52131938634108d16a60bb63ff17480c2b84e9 Mon Sep 17 00:00:00 2001 From: Jonathan Claudius Date: Wed, 19 Apr 2023 19:07:02 -0400 Subject: [PATCH 004/218] Fix review feedback items --- contracts/common/lib/Math256.sol | 1 + test/common/lib/math-256.test.sol | 122 +++++++++++++++++++++++------- 2 files changed, 95 insertions(+), 28 deletions(-) diff --git a/contracts/common/lib/Math256.sol b/contracts/common/lib/Math256.sol index 366a014cf..8f7455bcc 100644 --- a/contracts/common/lib/Math256.sol +++ b/contracts/common/lib/Math256.sol @@ -33,6 +33,7 @@ library Math256 { /// This differs from standard division with `/` in that it rounds up instead /// of rounding down. function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { + require(b != 0, "Division by modulo by 0"); // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } diff --git a/test/common/lib/math-256.test.sol b/test/common/lib/math-256.test.sol index 048e53d54..ee3ee70a8 100644 --- a/test/common/lib/math-256.test.sol +++ b/test/common/lib/math-256.test.sol @@ -1,28 +1,28 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.13; +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; import "forge-std/Test.sol"; import { Math256 } from "contracts/common/lib/Math256.sol"; contract Math256Test is Test { - /// int256 tests for max/min + /// uint256 tests for max/min - function testMaxUint256Simple1() public { + function testMaxUint256_a_b() public { uint256 a = 1; uint256 b = 2; assertEq(Math256.max(a, b), b); } - function testMaxUint256Simple2() public { + function testMaxUint256_b_a() public { uint256 a = 1; uint256 b = 2; assertEq(Math256.max(b, a), b); } - function testMaxUint256Simple3() public { + function testMaxUint256_a_b_equal() public { uint256 a = 1; uint256 b = 1; @@ -34,30 +34,35 @@ contract Math256Test is Test { if (a > b) { expected = a; - } else if (a == b) { - expected = a; } else { expected = b; } + // Must not crash + Math256.min(b, a); + + // Must be commutative + assertEq(Math256.min(b, a), Math256.min(a, b)); + + // Must be expected assertEq(Math256.max(b, a), expected); } - function testMinUint256Simple1() public { + function testMinUint256_a_b() public { uint256 a = 2; uint256 b = 1; assertEq(Math256.min(a, b), b); } - function testMinUint256Simple2() public { + function testMinUint256_b_a() public { uint256 a = 1; uint256 b = 2; assertEq(Math256.min(b, a), a); } - function testMinUint256Simple3() public { + function testMinUint256_a_b_equal() public { uint256 a = 1; uint256 b = 1; @@ -69,67 +74,112 @@ contract Math256Test is Test { if (a < b) { expected = a; - } else if (a == b) { - expected = a; } else { expected = b; } + // Must not crash + Math256.min(b, a); + + // Must be commutative + assertEq(Math256.min(b, a), Math256.min(a, b)); + + // Must be expected assertEq(Math256.min(b, a), expected); } /// int256 tests for max/min - function testMaxInt256Simple1() public { + function testMaxInt256_a_b() public { int256 a = 1; int256 b = 2; assertEq(Math256.max(a, b), b); } - function testMaxInt256Simple2() public { + function testMaxInt256_b_a() public { int256 a = 1; int256 b = 2; assertEq(Math256.max(b, a), b); } - function testMaxInt256Simple3() public { + function testMaxInt256_a_b_equal() public { int256 a = 1; int256 b = 1; assertEq(Math256.max(b, a), b); } + function testMaxInt256_a_b_negative() public { + int256 a = -1; + int256 b = -2; + + assertEq(Math256.max(a, b), a); + } + + function testMaxInt256_a_b_positive_negative() public { + int256 a = 1; + int256 b = -2; + + assertEq(Math256.max(a, b), a); + } + + function testMaxInt256_b_a_negative() public { + int256 a = -1; + int256 b = -2; + + assertEq(Math256.max(b, a), a); + } + + function testMaxInt256_b_a_postive_negative() public { + int256 a = 1; + int256 b = -2; + + assertEq(Math256.max(b, a), a); + } + + function testMaxInt256_a_b_equal_negative() public { + int256 a = -1; + int256 b = -1; + + assertEq(Math256.max(b, a), b); + } + function testMaxInt256Fuzz(int256 a, int256 b) public { int256 expected; if (a > b) { expected = a; - } else if (a == b) { - expected = a; } else { expected = b; } + // Must not crash + Math256.max(b, a); + + // Must be commutative + assertEq(Math256.max(b, a), Math256.max(a, b)); + + // Must be exepcted assertEq(Math256.max(b, a), expected); } - function testMinInt256Simple1() public { + function testMinInt256_a_b() public { int256 a = 2; int256 b = 1; assertEq(Math256.min(a, b), b); } - function testMinInt256Simple2() public { + function testMinInt256_b_a() public { int256 a = 1; int256 b = 2; assertEq(Math256.min(b, a), a); } - function testMinInt256Simple3() public { + function testMinInt256_b_a_equal() public { int256 a = 1; int256 b = 1; @@ -141,12 +191,17 @@ contract Math256Test is Test { if (a < b) { expected = a; - } else if (a == b) { - expected = a; } else { expected = b; } + // Must not crash + Math256.min(b, a); + + // Must be commutative + assertEq(Math256.min(b, a), assertEq(Math256.min(a, b))); + + // Must be expected assertEq(Math256.min(b, a), expected); } @@ -193,6 +248,9 @@ contract Math256Test is Test { vm.expectRevert("Division or modulo by 0"); } + // It shouldn't crash unexpectedly + Math256.ceilDiv(a, b); + // This case should always be zero if (a == 0) { assertEq(Math256.ceilDiv(a, b), 0); @@ -203,9 +261,6 @@ contract Math256Test is Test { assertEq(Math256.ceilDiv(a, b), 1); assertEq(Math256.ceilDiv(b, a), 1); } - - // It shouldn't crash unexpectedly - Math256.ceilDiv(a, b); } /// tests for absDiff @@ -225,16 +280,27 @@ contract Math256Test is Test { } function testAbsDiffFuzz(uint256 a, uint256 b) public { + + // It shouldn't unexpectedly crash + Math256.absDiff(b, a); + // If they are the same, it's always zero if (a == b) { assertEq(Math256.absDiff(b, a), 0); } + // They are different + if (b > a) { + assertEq(Math256.absDiff(b, a), b - a); + } else { + assertEq(Math256.absDiff(a, b), a - b); + } + // If one is zero, the difference should always be the other if (a == 0) { assertEq(Math256.absDiff(b, a), b); } - // It shouldn't unexpectedly crash - Math256.absDiff(b, a); + // Must be commutative + assertEq(Math256.absDiff(b, a), Math256.absDiff(a, b)); } \ No newline at end of file From d3d08bd79d80e53169b627fdef400baf289cf99b Mon Sep 17 00:00:00 2001 From: Jonathan Claudius Date: Wed, 19 Apr 2023 19:24:06 -0400 Subject: [PATCH 005/218] Fix solidity version --- test/common/lib/math-256.test.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/common/lib/math-256.test.sol b/test/common/lib/math-256.test.sol index ee3ee70a8..df9be259c 100644 --- a/test/common/lib/math-256.test.sol +++ b/test/common/lib/math-256.test.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.9; +pragma solidity 0.8.9; import "forge-std/Test.sol"; import { Math256 } from "contracts/common/lib/Math256.sol"; From fa2e900d64bee45f9866f132e71c7f6ce5a67d1a Mon Sep 17 00:00:00 2001 From: Jonathan Claudius Date: Wed, 24 May 2023 18:00:44 -0400 Subject: [PATCH 006/218] Add check against underflow --- contracts/0.8.9/test_helpers/AccountingOracleMock.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/0.8.9/test_helpers/AccountingOracleMock.sol b/contracts/0.8.9/test_helpers/AccountingOracleMock.sol index e50c43872..198366102 100644 --- a/contracts/0.8.9/test_helpers/AccountingOracleMock.sol +++ b/contracts/0.8.9/test_helpers/AccountingOracleMock.sol @@ -22,6 +22,7 @@ contract AccountingOracleMock { AccountingOracle.ReportData calldata data, uint256 /* contractVersion */ ) external { + require(data.refSlot >= _lastRefSlot, "refSlot less than _lastRefSlot"); uint256 slotsElapsed = data.refSlot - _lastRefSlot; _lastRefSlot = data.refSlot; From 876ad294de3e7f98d662c3b8ca52c2dd972487d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 May 2023 17:29:44 +0000 Subject: [PATCH 007/218] chore(deps): bump requests from 2.30.0 to 2.31.0 Bumps [requests](https://github.com/psf/requests) from 2.30.0 to 2.31.0. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v2.30.0...v2.31.0) --- updated-dependencies: - dependency-name: requests dependency-type: indirect ... Signed-off-by: dependabot[bot] --- poetry.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index 9ee19f775..f1d67d720 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1269,14 +1269,14 @@ files = [ [[package]] name = "requests" -version = "2.30.0" +version = "2.31.0" description = "Python HTTP for Humans." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "requests-2.30.0-py3-none-any.whl", hash = "sha256:10e94cc4f3121ee6da529d358cdaeaff2f1c409cd377dbc72b825852f2f7e294"}, - {file = "requests-2.30.0.tar.gz", hash = "sha256:239d7d4458afcb28a692cdd298d87542235f4ca8d36d03a15bfc128a6559a2f4"}, + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, ] [package.dependencies] From b9fbf6c7213877616b8eb5fba948665684939c57 Mon Sep 17 00:00:00 2001 From: Jonathan Claudius Date: Thu, 1 Jun 2023 15:29:29 +0000 Subject: [PATCH 008/218] Revert implementation check for division by zero --- contracts/common/lib/Math256.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/common/lib/Math256.sol b/contracts/common/lib/Math256.sol index 8f7455bcc..366a014cf 100644 --- a/contracts/common/lib/Math256.sol +++ b/contracts/common/lib/Math256.sol @@ -33,7 +33,6 @@ library Math256 { /// This differs from standard division with `/` in that it rounds up instead /// of rounding down. function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { - require(b != 0, "Division by modulo by 0"); // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } From 06a62298636ac896511af99bb965f34561b36d6e Mon Sep 17 00:00:00 2001 From: Jonathan Claudius Date: Sat, 3 Jun 2023 04:16:03 +0000 Subject: [PATCH 009/218] Clean up math256 tests to run on forge --- test/common/lib/math-256.test.sol | 32 +++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/test/common/lib/math-256.test.sol b/test/common/lib/math-256.test.sol index df9be259c..3cbad33fa 100644 --- a/test/common/lib/math-256.test.sol +++ b/test/common/lib/math-256.test.sol @@ -199,7 +199,7 @@ contract Math256Test is Test { Math256.min(b, a); // Must be commutative - assertEq(Math256.min(b, a), assertEq(Math256.min(a, b))); + assertEq(Math256.min(b, a), Math256.min(a, b)); // Must be expected assertEq(Math256.min(b, a), expected); @@ -207,13 +207,14 @@ contract Math256Test is Test { /// tests for ceilDiv - function testCeilDivByZero() public { - uint256 a = 1; - uint256 b = 0; + // Commenting this out, as the implementation doesn't solve for this case + // function testCeilDivByZero() public { + // uint256 a = 1; + // uint256 b = 0; - vm.expectRevert("Division or modulo by 0"); - Math256.ceilDiv(a, b); - } + // vm.expectRevert("Division or modulo by 0"); + // Math256.ceilDiv(a, b); + // } function testCeilDivZeroFromFour() public { uint256 a = 0; @@ -243,14 +244,9 @@ contract Math256Test is Test { } function testCeilDivFuzz(uint256 a, uint256 b) public { - // This case should always error - if (b == 0) { - vm.expectRevert("Division or modulo by 0"); - } - - // It shouldn't crash unexpectedly - Math256.ceilDiv(a, b); - + // Skip zero, implementation is safe against division by zero + vm.assume(b != 0); + // This case should always be zero if (a == 0) { assertEq(Math256.ceilDiv(a, b), 0); @@ -261,6 +257,9 @@ contract Math256Test is Test { assertEq(Math256.ceilDiv(a, b), 1); assertEq(Math256.ceilDiv(b, a), 1); } + + // It shouldn't crash unexpectedly + Math256.ceilDiv(a, b); } /// tests for absDiff @@ -303,4 +302,5 @@ contract Math256Test is Test { // Must be commutative assertEq(Math256.absDiff(b, a), Math256.absDiff(a, b)); - } \ No newline at end of file + } +} \ No newline at end of file From 9d946931af984e055726ddadf797f86806760cf4 Mon Sep 17 00:00:00 2001 From: Jonathan Claudius Date: Sat, 3 Jun 2023 04:17:24 +0000 Subject: [PATCH 010/218] Add forge tests for signature utils --- test/common/lib/signature-utils.test.sol | 125 +++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 test/common/lib/signature-utils.test.sol diff --git a/test/common/lib/signature-utils.test.sol b/test/common/lib/signature-utils.test.sol new file mode 100644 index 000000000..2e67ddf3e --- /dev/null +++ b/test/common/lib/signature-utils.test.sol @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.24 <0.9.0; + +import "forge-std/Test.sol"; +import {ECDSA} from "contracts/common/lib/ECDSA.sol"; +import { SignatureUtils } from "contracts/common/lib/SignatureUtils.sol"; + +contract ExposedSignatureUtils { + function _isValidSignature( + address signer, + bytes32 msgHash, + uint8 v, + bytes32 r, + bytes32 s + ) public returns (bool) { + return SignatureUtils.isValidSignature(signer, msgHash, v, r, s); + } + + function hasCode(address addr) public returns (bool) { + return SignatureUtils._hasCode(addr); + } +} + +contract SignatureUtilsTest is Test { + ExposedSignatureUtils public sigUtil; + + function ethMessageHash(string memory message) internal pure returns (bytes32) { + return keccak256( + abi.encodePacked("\x19Ethereum Signed Message:\n32", message) + ); + } + + function setUp() public { + sigUtil = new ExposedSignatureUtils(); + } + + function testHasCodeFalse() public { + address eoa = 0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe; + address con = address(new ExposedSignatureUtils()); + + assertEq(sigUtil.hasCode(eoa), false); + assertEq(sigUtil.hasCode(con), true); + } + + function testEoaIsValidSignature() public { + uint256 eoaPk = 1; + address eoa = vm.addr(eoaPk); + bytes32 hash = keccak256("TEST"); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(eoaPk, hash); + + assertEq(sigUtil._isValidSignature(eoa, hash, v, r, s), true); + } + + function testIsValidSignatureFuzzMessage(bytes memory data) public { + uint256 eoaPk = 1; + address eoa = vm.addr(eoaPk); + bytes32 hash = keccak256(data); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(eoaPk, hash); + + // Regardless of the message, it should always validate + assertEq(sigUtil._isValidSignature(eoa, hash, v, r, s), true); + } + + function testIsValidSignatureFuzzV(uint8 _v) public { + uint256 eoaPk = 1; + address eoa = vm.addr(eoaPk); + bytes32 hash = keccak256("TEST"); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(eoaPk, hash); + + // Test to see if we can get valid signatures without a valid V + if (v == _v) { + assertEq(sigUtil._isValidSignature(eoa, hash, _v, r, s), true); + } else if (27 == _v) { + assertEq(sigUtil._isValidSignature(eoa, hash, _v, r, s), false); + } else { + vm.expectRevert(bytes("ECDSA: invalid signature")); + sigUtil._isValidSignature(eoa, hash, _v, r, s); + } + } + + function testIsValidSignatureFuzzR(bytes32 _r) public { + uint256 eoaPk = 1; + address eoa = vm.addr(eoaPk); + bytes32 hash = keccak256("TEST"); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(eoaPk, hash); + + // Test to see if we can get valid signatures regardless of what R is + if (r == _r) { + assertEq(sigUtil._isValidSignature(eoa, hash, v, _r, s), true); + } + } + + function testIsValidSignatureFuzzS(bytes32 _s) public { + uint256 eoaPk = 1; + address eoa = vm.addr(eoaPk); + bytes32 hash = keccak256("TEST"); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(eoaPk, hash); + + // Test to see if we can get valid signatures regardless of what S is + if (s == _s) { + assertEq(sigUtil._isValidSignature(eoa, hash, v, r, _s), true); + } + } + + function testIsValidSignatureWrongSigner(uint256 rogueSigner) public { + // Ignore the 0 case for rogue signer + vm.assume(rogueSigner != 0); + + // Ignore signers above secp256k1 curve order + vm.assume(rogueSigner < 115792089237316195423570985008687907852837564279074904382605163141518161494337); + + uint256 eoaPk = 1; + address eoa = vm.addr(eoaPk); + address eoa2 = vm.addr(rogueSigner); + + bytes32 hash = keccak256("TEST"); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(eoaPk, hash); + + if (eoa == eoa2) { + assertEq(sigUtil._isValidSignature(eoa2, hash, v, r, s), true); + } else { + assertEq(sigUtil._isValidSignature(eoa2, hash, v, r, s), false); + } + } +} \ No newline at end of file From d083a3969898e11f06ff0c9e593feceb7dc34b4d Mon Sep 17 00:00:00 2001 From: Jonathan Claudius Date: Sat, 3 Jun 2023 04:34:11 +0000 Subject: [PATCH 011/218] Further clean up on math256 --- test/common/lib/math-256.test.sol | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/test/common/lib/math-256.test.sol b/test/common/lib/math-256.test.sol index 3cbad33fa..9a82b5e34 100644 --- a/test/common/lib/math-256.test.sol +++ b/test/common/lib/math-256.test.sol @@ -78,9 +78,6 @@ contract Math256Test is Test { expected = b; } - // Must not crash - Math256.min(b, a); - // Must be commutative assertEq(Math256.min(b, a), Math256.min(a, b)); @@ -155,9 +152,6 @@ contract Math256Test is Test { expected = b; } - // Must not crash - Math256.max(b, a); - // Must be commutative assertEq(Math256.max(b, a), Math256.max(a, b)); @@ -258,8 +252,8 @@ contract Math256Test is Test { assertEq(Math256.ceilDiv(b, a), 1); } - // It shouldn't crash unexpectedly - Math256.ceilDiv(a, b); + uint256 expected = (a == 0 ? 0 : (a - 1) / b + 1); + assertEq(Math256.ceilDiv(a, b), expected); } /// tests for absDiff From 8d076a864a8cc9d7ec9ab17ba20755be046eafee Mon Sep 17 00:00:00 2001 From: Jonathan Claudius Date: Wed, 7 Jun 2023 00:38:20 +0000 Subject: [PATCH 012/218] Add forge tests for unstructured storage --- test/0.8.9/unstructured-storage.test.sol | 135 +++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 test/0.8.9/unstructured-storage.test.sol diff --git a/test/0.8.9/unstructured-storage.test.sol b/test/0.8.9/unstructured-storage.test.sol new file mode 100644 index 000000000..c3aec0d85 --- /dev/null +++ b/test/0.8.9/unstructured-storage.test.sol @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.24 <0.9.0; + +import "forge-std/Test.sol"; +import {ECDSA} from "contracts/common/lib/ECDSA.sol"; +import { UnstructuredStorage } from "contracts/0.8.9/lib/UnstructuredStorage.sol"; + +contract ExposedUnstructuredStorage { + function _getStorageBool(bytes32 position) public returns (bool) { + return UnstructuredStorage.getStorageBool(position); + } + + function _getStorageAddress(bytes32 position) public returns (address) { + return UnstructuredStorage.getStorageAddress(position); + } + + function _getStorageBytes32(bytes32 position) public returns (bytes32) { + return UnstructuredStorage.getStorageBytes32(position); + } + + function _getStorageUint256(bytes32 position) public returns (uint256) { + return UnstructuredStorage.getStorageUint256(position); + } + + function _setStorageBool(bytes32 position, bool data) public { + return UnstructuredStorage.setStorageBool(position, data); + } + + function _setStorageAddress(bytes32 position, address data) public { + return UnstructuredStorage.setStorageAddress(position, data); + } + + function _setStorageBytes32(bytes32 position, bytes32 data) public { + return UnstructuredStorage.setStorageBytes32(position, data); + } + + function _setStorageUint256(bytes32 position, uint256 data) public { + return UnstructuredStorage.setStorageUint256(position, data); + } +} + +contract ExposedUnstructuredStorageTest is Test { + ExposedUnstructuredStorage public unstructedStorage; + + function setUp() public { + unstructedStorage = new ExposedUnstructuredStorage(); + } + + function testGetStorageBool() public { + bytes32 position = keccak256("FOO"); + assertEq(unstructedStorage._getStorageBool(position), false); + } + + function testGetStorageAddress() public { + bytes32 position = keccak256("FOO"); + assertEq(unstructedStorage._getStorageAddress(position), address(0)); + } + + function testGetStorageBytes32() public { + bytes32 position = keccak256("FOO"); + bytes32 data; + assertEq(unstructedStorage._getStorageBytes32(position), data); + } + + function testGetStorageUint256() public { + bytes32 position = keccak256("FOO"); + uint256 data; + assertEq(unstructedStorage._getStorageUint256(position), data); + } + + function testSetStorageBool() public { + bytes32 position = keccak256("FOO"); + assertEq(unstructedStorage._getStorageBool(position), false); + + unstructedStorage._setStorageBool(position, true); + assertEq(unstructedStorage._getStorageBool(position), true); + + unstructedStorage._setStorageBool(position, false); + assertEq(unstructedStorage._getStorageBool(position), false); + } + + function testSetStorageAddress() public { + bytes32 position = keccak256("FOO"); + address data = vm.addr(1); + + assertEq(unstructedStorage._getStorageAddress(position), address(0)); + unstructedStorage._setStorageAddress(position, data); + assertEq(unstructedStorage._getStorageAddress(position), data); + } + + function testSetStorageAddressFuzz(uint256 num) public { + // Private key must be greater than zero + vm.assume(num > 0); + + // Private key must be less than the secp256k1 curve order + vm.assume(num < 115792089237316195423570985008687907852837564279074904382605163141518161494337); + + bytes32 position = keccak256("FOO"); + address data = vm.addr(num); + + assertEq(unstructedStorage._getStorageAddress(position), address(0)); + unstructedStorage._setStorageAddress(position, data); + assertEq(unstructedStorage._getStorageAddress(position), data); + } + + function testSetStorageBytes32() public { + bytes32 position = keccak256("FOO"); + bytes32 data = keccak256("BAR"); + bytes32 unintializedData; + + assertEq(unstructedStorage._getStorageBytes32(position), unintializedData); + unstructedStorage._setStorageBytes32(position, data); + assertEq(unstructedStorage._getStorageBytes32(position), data); + } + + function testSetStorageUint256() public { + bytes32 position = keccak256("FOO"); + uint256 data = 1; + uint256 unintializedData; + + assertEq(unstructedStorage._getStorageUint256(position), unintializedData); + unstructedStorage._setStorageUint256(position, data); + assertEq(unstructedStorage._getStorageUint256(position), data); + } + + function testSetStorageUint256Fuzz(uint256 data) public { + bytes32 position = keccak256("FOO"); + uint256 unintializedData; + + assertEq(unstructedStorage._getStorageUint256(position), unintializedData); + unstructedStorage._setStorageUint256(position, data); + assertEq(unstructedStorage._getStorageUint256(position), data); + } + +} \ No newline at end of file From aaf57772d930a6b37ed3ca7feb070c170992e5e8 Mon Sep 17 00:00:00 2001 From: Jonathan Claudius Date: Wed, 7 Jun 2023 00:46:44 +0000 Subject: [PATCH 013/218] Remove unnecessary ECDSA import --- test/0.8.9/unstructured-storage.test.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/test/0.8.9/unstructured-storage.test.sol b/test/0.8.9/unstructured-storage.test.sol index c3aec0d85..83fbf16e1 100644 --- a/test/0.8.9/unstructured-storage.test.sol +++ b/test/0.8.9/unstructured-storage.test.sol @@ -2,7 +2,6 @@ pragma solidity >=0.4.24 <0.9.0; import "forge-std/Test.sol"; -import {ECDSA} from "contracts/common/lib/ECDSA.sol"; import { UnstructuredStorage } from "contracts/0.8.9/lib/UnstructuredStorage.sol"; contract ExposedUnstructuredStorage { From c0d578a153da3867fda4b8251270ed10f3d0379e Mon Sep 17 00:00:00 2001 From: Jonathan Claudius Date: Wed, 7 Jun 2023 09:40:55 -0400 Subject: [PATCH 014/218] Update test/0.8.9/unstructured-storage.test.sol Co-authored-by: Eugene Mamin --- test/0.8.9/unstructured-storage.test.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/0.8.9/unstructured-storage.test.sol b/test/0.8.9/unstructured-storage.test.sol index 83fbf16e1..515c82579 100644 --- a/test/0.8.9/unstructured-storage.test.sol +++ b/test/0.8.9/unstructured-storage.test.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity >=0.4.24 <0.9.0; +pragma solidity 0.8.9; import "forge-std/Test.sol"; import { UnstructuredStorage } from "contracts/0.8.9/lib/UnstructuredStorage.sol"; From df50f663284cb1f3e5ceeba77a6764b157bec6c5 Mon Sep 17 00:00:00 2001 From: Jonathan Claudius Date: Wed, 7 Jun 2023 18:34:36 +0000 Subject: [PATCH 015/218] clean up signature utils tests --- test/common/lib/signature-utils.test.sol | 56 +++++++++++++++++------- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/test/common/lib/signature-utils.test.sol b/test/common/lib/signature-utils.test.sol index 2e67ddf3e..54f4e8fbf 100644 --- a/test/common/lib/signature-utils.test.sol +++ b/test/common/lib/signature-utils.test.sol @@ -6,17 +6,17 @@ import {ECDSA} from "contracts/common/lib/ECDSA.sol"; import { SignatureUtils } from "contracts/common/lib/SignatureUtils.sol"; contract ExposedSignatureUtils { - function _isValidSignature( + function isValidSignature( address signer, bytes32 msgHash, uint8 v, bytes32 r, bytes32 s - ) public returns (bool) { + ) public view returns (bool) { return SignatureUtils.isValidSignature(signer, msgHash, v, r, s); } - function hasCode(address addr) public returns (bool) { + function hasCode(address addr) public view returns (bool) { return SignatureUtils._hasCode(addr); } } @@ -48,7 +48,20 @@ contract SignatureUtilsTest is Test { bytes32 hash = keccak256("TEST"); (uint8 v, bytes32 r, bytes32 s) = vm.sign(eoaPk, hash); - assertEq(sigUtil._isValidSignature(eoa, hash, v, r, s), true); + assertEq(sigUtil.isValidSignature(eoa, hash, v, r, s), true); + } + + function testEoaIsValidSignatureFuzz(uint256 eoa_num) public { + // Private key must be less than the secp256k1 curve order + vm.assume(eoa_num < 115792089237316195423570985008687907852837564279074904382605163141518161494337); + + //Private key cannot be zero + vm.assume(eoa_num > 0); + + bytes32 hash = keccak256("TEST"); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(eoa_num, hash); + + assertEq(sigUtil.isValidSignature(vm.addr(eoa_num), hash, v, r, s), true); } function testIsValidSignatureFuzzMessage(bytes memory data) public { @@ -58,7 +71,7 @@ contract SignatureUtilsTest is Test { (uint8 v, bytes32 r, bytes32 s) = vm.sign(eoaPk, hash); // Regardless of the message, it should always validate - assertEq(sigUtil._isValidSignature(eoa, hash, v, r, s), true); + assertEq(sigUtil.isValidSignature(eoa, hash, v, r, s), true); } function testIsValidSignatureFuzzV(uint8 _v) public { @@ -69,12 +82,12 @@ contract SignatureUtilsTest is Test { // Test to see if we can get valid signatures without a valid V if (v == _v) { - assertEq(sigUtil._isValidSignature(eoa, hash, _v, r, s), true); + assertEq(sigUtil.isValidSignature(eoa, hash, _v, r, s), true); } else if (27 == _v) { - assertEq(sigUtil._isValidSignature(eoa, hash, _v, r, s), false); + assertEq(sigUtil.isValidSignature(eoa, hash, _v, r, s), false); } else { vm.expectRevert(bytes("ECDSA: invalid signature")); - sigUtil._isValidSignature(eoa, hash, _v, r, s); + sigUtil.isValidSignature(eoa, hash, _v, r, s); } } @@ -86,8 +99,13 @@ contract SignatureUtilsTest is Test { // Test to see if we can get valid signatures regardless of what R is if (r == _r) { - assertEq(sigUtil._isValidSignature(eoa, hash, v, _r, s), true); - } + assertEq(sigUtil.isValidSignature(eoa, hash, v, _r, s), true); + } else if (ecrecover(hash, v, _r, s) == address(0)) { + vm.expectRevert(bytes("ECDSA: invalid signature")); + sigUtil.isValidSignature(eoa, hash, v, _r, s); + } else { + assertEq(sigUtil.isValidSignature(eoa, hash, v, _r, s), false); + } } function testIsValidSignatureFuzzS(bytes32 _s) public { @@ -95,11 +113,19 @@ contract SignatureUtilsTest is Test { address eoa = vm.addr(eoaPk); bytes32 hash = keccak256("TEST"); (uint8 v, bytes32 r, bytes32 s) = vm.sign(eoaPk, hash); - + // Test to see if we can get valid signatures regardless of what S is if (s == _s) { - assertEq(sigUtil._isValidSignature(eoa, hash, v, r, _s), true); - } + assertEq(sigUtil.isValidSignature(eoa, hash, v, r, _s), true); + } else if (uint256(_s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { + vm.expectRevert(bytes("ECDSA: invalid signature 's' value")); + sigUtil.isValidSignature(eoa, hash, v, r, _s); + } else if (ecrecover(hash, v, r, _s) == address(0)) { + vm.expectRevert(bytes("ECDSA: invalid signature")); + sigUtil.isValidSignature(eoa, hash, v, r, _s); + } else { + assertEq(sigUtil.isValidSignature(eoa, hash, v, r, _s), false); + } } function testIsValidSignatureWrongSigner(uint256 rogueSigner) public { @@ -117,9 +143,9 @@ contract SignatureUtilsTest is Test { (uint8 v, bytes32 r, bytes32 s) = vm.sign(eoaPk, hash); if (eoa == eoa2) { - assertEq(sigUtil._isValidSignature(eoa2, hash, v, r, s), true); + assertEq(sigUtil.isValidSignature(eoa2, hash, v, r, s), true); } else { - assertEq(sigUtil._isValidSignature(eoa2, hash, v, r, s), false); + assertEq(sigUtil.isValidSignature(eoa2, hash, v, r, s), false); } } } \ No newline at end of file From 817ef9a924d296f90254b27a113582ef3f2930a5 Mon Sep 17 00:00:00 2001 From: Jonathan Claudius Date: Wed, 7 Jun 2023 18:47:11 +0000 Subject: [PATCH 016/218] Updates to unstructured storage tests per review feedback --- test/0.8.9/unstructured-storage.test.sol | 90 ++++++++++++------------ 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/test/0.8.9/unstructured-storage.test.sol b/test/0.8.9/unstructured-storage.test.sol index 83fbf16e1..b9aabe63f 100644 --- a/test/0.8.9/unstructured-storage.test.sol +++ b/test/0.8.9/unstructured-storage.test.sol @@ -5,35 +5,35 @@ import "forge-std/Test.sol"; import { UnstructuredStorage } from "contracts/0.8.9/lib/UnstructuredStorage.sol"; contract ExposedUnstructuredStorage { - function _getStorageBool(bytes32 position) public returns (bool) { + function getStorageBool(bytes32 position) public view returns (bool) { return UnstructuredStorage.getStorageBool(position); } - function _getStorageAddress(bytes32 position) public returns (address) { + function getStorageAddress(bytes32 position) public view returns (address) { return UnstructuredStorage.getStorageAddress(position); } - function _getStorageBytes32(bytes32 position) public returns (bytes32) { + function getStorageBytes32(bytes32 position) public view returns (bytes32) { return UnstructuredStorage.getStorageBytes32(position); } - function _getStorageUint256(bytes32 position) public returns (uint256) { + function getStorageUint256(bytes32 position) public view returns (uint256) { return UnstructuredStorage.getStorageUint256(position); } - function _setStorageBool(bytes32 position, bool data) public { + function setStorageBool(bytes32 position, bool data) public { return UnstructuredStorage.setStorageBool(position, data); } - function _setStorageAddress(bytes32 position, address data) public { + function setStorageAddress(bytes32 position, address data) public { return UnstructuredStorage.setStorageAddress(position, data); } - function _setStorageBytes32(bytes32 position, bytes32 data) public { + function setStorageBytes32(bytes32 position, bytes32 data) public { return UnstructuredStorage.setStorageBytes32(position, data); } - function _setStorageUint256(bytes32 position, uint256 data) public { + function setStorageUint256(bytes32 position, uint256 data) public { return UnstructuredStorage.setStorageUint256(position, data); } } @@ -45,61 +45,54 @@ contract ExposedUnstructuredStorageTest is Test { unstructedStorage = new ExposedUnstructuredStorage(); } - function testGetStorageBool() public { + function testGetStorageBoolUnitialized() public { bytes32 position = keccak256("FOO"); - assertEq(unstructedStorage._getStorageBool(position), false); + assertEq(unstructedStorage.getStorageBool(position), false); } - function testGetStorageAddress() public { + function testGetStorageAddressUnitialized() public { bytes32 position = keccak256("FOO"); - assertEq(unstructedStorage._getStorageAddress(position), address(0)); + assertEq(unstructedStorage.getStorageAddress(position), address(0)); } - function testGetStorageBytes32() public { + function testGetStorageBytes32Unitialized() public { bytes32 position = keccak256("FOO"); bytes32 data; - assertEq(unstructedStorage._getStorageBytes32(position), data); + assertEq(unstructedStorage.getStorageBytes32(position), data); } - function testGetStorageUint256() public { + function testGetStorageUint256Unitialized() public { bytes32 position = keccak256("FOO"); uint256 data; - assertEq(unstructedStorage._getStorageUint256(position), data); + assertEq(unstructedStorage.getStorageUint256(position), data); } function testSetStorageBool() public { bytes32 position = keccak256("FOO"); - assertEq(unstructedStorage._getStorageBool(position), false); + assertEq(unstructedStorage.getStorageBool(position), false); - unstructedStorage._setStorageBool(position, true); - assertEq(unstructedStorage._getStorageBool(position), true); + unstructedStorage.setStorageBool(position, true); + assertEq(unstructedStorage.getStorageBool(position), true); - unstructedStorage._setStorageBool(position, false); - assertEq(unstructedStorage._getStorageBool(position), false); + unstructedStorage.setStorageBool(position, false); + assertEq(unstructedStorage.getStorageBool(position), false); } function testSetStorageAddress() public { bytes32 position = keccak256("FOO"); address data = vm.addr(1); - assertEq(unstructedStorage._getStorageAddress(position), address(0)); - unstructedStorage._setStorageAddress(position, data); - assertEq(unstructedStorage._getStorageAddress(position), data); + assertEq(unstructedStorage.getStorageAddress(position), address(0)); + unstructedStorage.setStorageAddress(position, data); + assertEq(unstructedStorage.getStorageAddress(position), data); } - function testSetStorageAddressFuzz(uint256 num) public { - // Private key must be greater than zero - vm.assume(num > 0); - - // Private key must be less than the secp256k1 curve order - vm.assume(num < 115792089237316195423570985008687907852837564279074904382605163141518161494337); - + function testSetStorageAddressFuzz(address data) public { bytes32 position = keccak256("FOO"); - address data = vm.addr(num); - assertEq(unstructedStorage._getStorageAddress(position), address(0)); - unstructedStorage._setStorageAddress(position, data); - assertEq(unstructedStorage._getStorageAddress(position), data); + assertEq(unstructedStorage.getStorageAddress(position), address(0)); + unstructedStorage.setStorageAddress(position, data); + assertEq(unstructedStorage.getStorageAddress(position), data); } function testSetStorageBytes32() public { @@ -107,9 +100,18 @@ contract ExposedUnstructuredStorageTest is Test { bytes32 data = keccak256("BAR"); bytes32 unintializedData; - assertEq(unstructedStorage._getStorageBytes32(position), unintializedData); - unstructedStorage._setStorageBytes32(position, data); - assertEq(unstructedStorage._getStorageBytes32(position), data); + assertEq(unstructedStorage.getStorageBytes32(position), unintializedData); + unstructedStorage.setStorageBytes32(position, data); + assertEq(unstructedStorage.getStorageBytes32(position), data); + } + + function testSetStorageBytes32Fuzz(bytes32 data) public { + bytes32 position = keccak256("FOO"); + bytes32 unintializedData; + + assertEq(unstructedStorage.getStorageBytes32(position), unintializedData); + unstructedStorage.setStorageBytes32(position, data); + assertEq(unstructedStorage.getStorageBytes32(position), data); } function testSetStorageUint256() public { @@ -117,18 +119,18 @@ contract ExposedUnstructuredStorageTest is Test { uint256 data = 1; uint256 unintializedData; - assertEq(unstructedStorage._getStorageUint256(position), unintializedData); - unstructedStorage._setStorageUint256(position, data); - assertEq(unstructedStorage._getStorageUint256(position), data); + assertEq(unstructedStorage.getStorageUint256(position), unintializedData); + unstructedStorage.setStorageUint256(position, data); + assertEq(unstructedStorage.getStorageUint256(position), data); } function testSetStorageUint256Fuzz(uint256 data) public { bytes32 position = keccak256("FOO"); uint256 unintializedData; - assertEq(unstructedStorage._getStorageUint256(position), unintializedData); - unstructedStorage._setStorageUint256(position, data); - assertEq(unstructedStorage._getStorageUint256(position), data); + assertEq(unstructedStorage.getStorageUint256(position), unintializedData); + unstructedStorage.setStorageUint256(position, data); + assertEq(unstructedStorage.getStorageUint256(position), data); } } \ No newline at end of file From 28df06cfccb86d4b68b345832691026511d08d2c Mon Sep 17 00:00:00 2001 From: Jonathan Claudius Date: Wed, 7 Jun 2023 20:08:15 +0000 Subject: [PATCH 017/218] Add position fuzzing throughout --- test/0.8.9/unstructured-storage.test.sol | 28 ++++++++++++++++++------ 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/test/0.8.9/unstructured-storage.test.sol b/test/0.8.9/unstructured-storage.test.sol index 1b553cac8..0e8089f1b 100644 --- a/test/0.8.9/unstructured-storage.test.sol +++ b/test/0.8.9/unstructured-storage.test.sol @@ -50,23 +50,41 @@ contract ExposedUnstructuredStorageTest is Test { assertEq(unstructedStorage.getStorageBool(position), false); } + function testGetStorageBoolUnitializedFuzz(bytes32 position) public { + assertEq(unstructedStorage.getStorageBool(position), false); + } + function testGetStorageAddressUnitialized() public { bytes32 position = keccak256("FOO"); assertEq(unstructedStorage.getStorageAddress(position), address(0)); } + function testGetStorageAddressUnitializedFuzz(bytes32 position ) public { + assertEq(unstructedStorage.getStorageAddress(position), address(0)); + } + function testGetStorageBytes32Unitialized() public { bytes32 position = keccak256("FOO"); bytes32 data; assertEq(unstructedStorage.getStorageBytes32(position), data); } + function testGetStorageBytes32UnitializedFuzz(bytes32 position) public { + bytes32 data; + assertEq(unstructedStorage.getStorageBytes32(position), data); + } + function testGetStorageUint256Unitialized() public { bytes32 position = keccak256("FOO"); uint256 data; assertEq(unstructedStorage.getStorageUint256(position), data); } + function testGetStorageUint256UnitializedFuzz(bytes32 position) public { + uint256 data; + assertEq(unstructedStorage.getStorageUint256(position), data); + } + function testSetStorageBool() public { bytes32 position = keccak256("FOO"); assertEq(unstructedStorage.getStorageBool(position), false); @@ -87,9 +105,7 @@ contract ExposedUnstructuredStorageTest is Test { assertEq(unstructedStorage.getStorageAddress(position), data); } - function testSetStorageAddressFuzz(address data) public { - bytes32 position = keccak256("FOO"); - + function testSetStorageAddressFuzz(address data, bytes32 position) public { assertEq(unstructedStorage.getStorageAddress(position), address(0)); unstructedStorage.setStorageAddress(position, data); assertEq(unstructedStorage.getStorageAddress(position), data); @@ -105,8 +121,7 @@ contract ExposedUnstructuredStorageTest is Test { assertEq(unstructedStorage.getStorageBytes32(position), data); } - function testSetStorageBytes32Fuzz(bytes32 data) public { - bytes32 position = keccak256("FOO"); + function testSetStorageBytes32Fuzz(bytes32 data, bytes32 position) public { bytes32 unintializedData; assertEq(unstructedStorage.getStorageBytes32(position), unintializedData); @@ -124,8 +139,7 @@ contract ExposedUnstructuredStorageTest is Test { assertEq(unstructedStorage.getStorageUint256(position), data); } - function testSetStorageUint256Fuzz(uint256 data) public { - bytes32 position = keccak256("FOO"); + function testSetStorageUint256Fuzz(uint256 data, bytes32 position) public { uint256 unintializedData; assertEq(unstructedStorage.getStorageUint256(position), unintializedData); From 4ac71a8d3ae5958280d5096ceefb8557ea497532 Mon Sep 17 00:00:00 2001 From: madlabman <10616301+madlabman@users.noreply.github.com> Date: Thu, 22 Jun 2023 20:36:10 +0400 Subject: [PATCH 018/218] build: upload ABIs to a published release --- .github/workflows/release-abis.yml | 62 ++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 .github/workflows/release-abis.yml diff --git a/.github/workflows/release-abis.yml b/.github/workflows/release-abis.yml new file mode 100644 index 000000000..191cb94ec --- /dev/null +++ b/.github/workflows/release-abis.yml @@ -0,0 +1,62 @@ +--- +name: Upload ABIs to a published release + +on: + release: + types: [published] # stable and pre-releases + +permissions: + contents: write + +jobs: + release-abis: + name: Build ABIs and upload to the release + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + persist-credentials: false + + - name: Setup node.js version + uses: actions/setup-node@v3 + with: + node-version: 16 + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "dir=$(yarn config get cacheFolder)" >> "$GITHUB_OUTPUT" + + - name: Cache yarn cache + id: cache-yarn-cache + uses: actions/cache@v3 + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: yarn-${{ hashFiles('**/yarn.lock') }} + + - name: Cache node_modules + id: cache-node-modules + uses: actions/cache@v3 + with: + path: '**/node_modules' + key: node_modules-${{ hashFiles('**/yarn.lock') }} + restore-keys: node_modules-${{ hashFiles('**/yarn.lock') }} + + - name: Install modules + run: yarn + if: | + steps.cache-yarn-cache.outputs.cache-hit != 'true' || + steps.cache-node-modules.outputs.cache-hit != 'true' + + - name: Compile contracts + run: yarn compile + + - name: Make an ABIs archive + run: zip -j abis.zip lib/abi/*.json + + - name: Upload the archive to the release + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ github.ref }} # is set to the tag of the release + files: abis.zip From e03da9de307d71746e0462c22c8144ce6d96038c Mon Sep 17 00:00:00 2001 From: madlabman <10616301+madlabman@users.noreply.github.com> Date: Fri, 23 Jun 2023 16:05:30 +0400 Subject: [PATCH 019/218] chore: replace action-gh-release with gh cli --- .github/workflows/release-abis.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release-abis.yml b/.github/workflows/release-abis.yml index 191cb94ec..9ab9a069b 100644 --- a/.github/workflows/release-abis.yml +++ b/.github/workflows/release-abis.yml @@ -56,7 +56,6 @@ jobs: run: zip -j abis.zip lib/abi/*.json - name: Upload the archive to the release - uses: softprops/action-gh-release@v1 - with: - tag_name: ${{ github.ref }} # is set to the tag of the release - files: abis.zip + run: | + gh release view "$GITHUB_REF" || exit; + gh release upload "$GITHUB_REF" abis.zip; From b95fbb0559e910b6a9b25e91c81f892b3d81110f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Jul 2023 16:27:56 +0000 Subject: [PATCH 020/218] chore(deps-dev): bump aiohttp from 3.8.4 to 3.8.5 Bumps [aiohttp](https://github.com/aio-libs/aiohttp) from 3.8.4 to 3.8.5. - [Release notes](https://github.com/aio-libs/aiohttp/releases) - [Changelog](https://github.com/aio-libs/aiohttp/blob/v3.8.5/CHANGES.rst) - [Commits](https://github.com/aio-libs/aiohttp/compare/v3.8.4...v3.8.5) --- updated-dependencies: - dependency-name: aiohttp dependency-type: indirect ... Signed-off-by: dependabot[bot] --- poetry.lock | 220 +++++++++++++++++++++------------------------------- 1 file changed, 89 insertions(+), 131 deletions(-) diff --git a/poetry.lock b/poetry.lock index 9ee19f775..32f7e2e1b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,100 +1,99 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "aiohttp" -version = "3.8.4" +version = "3.8.5" description = "Async http client/server framework (asyncio)" -category = "dev" optional = false python-versions = ">=3.6" files = [ - {file = "aiohttp-3.8.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5ce45967538fb747370308d3145aa68a074bdecb4f3a300869590f725ced69c1"}, - {file = "aiohttp-3.8.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b744c33b6f14ca26b7544e8d8aadff6b765a80ad6164fb1a430bbadd593dfb1a"}, - {file = "aiohttp-3.8.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1a45865451439eb320784918617ba54b7a377e3501fb70402ab84d38c2cd891b"}, - {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a86d42d7cba1cec432d47ab13b6637bee393a10f664c425ea7b305d1301ca1a3"}, - {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee3c36df21b5714d49fc4580247947aa64bcbe2939d1b77b4c8dcb8f6c9faecc"}, - {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:176a64b24c0935869d5bbc4c96e82f89f643bcdf08ec947701b9dbb3c956b7dd"}, - {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c844fd628851c0bc309f3c801b3a3d58ce430b2ce5b359cd918a5a76d0b20cb5"}, - {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5393fb786a9e23e4799fec788e7e735de18052f83682ce2dfcabaf1c00c2c08e"}, - {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e4b09863aae0dc965c3ef36500d891a3ff495a2ea9ae9171e4519963c12ceefd"}, - {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:adfbc22e87365a6e564c804c58fc44ff7727deea782d175c33602737b7feadb6"}, - {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:147ae376f14b55f4f3c2b118b95be50a369b89b38a971e80a17c3fd623f280c9"}, - {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:eafb3e874816ebe2a92f5e155f17260034c8c341dad1df25672fb710627c6949"}, - {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c6cc15d58053c76eacac5fa9152d7d84b8d67b3fde92709195cb984cfb3475ea"}, - {file = "aiohttp-3.8.4-cp310-cp310-win32.whl", hash = "sha256:59f029a5f6e2d679296db7bee982bb3d20c088e52a2977e3175faf31d6fb75d1"}, - {file = "aiohttp-3.8.4-cp310-cp310-win_amd64.whl", hash = "sha256:fe7ba4a51f33ab275515f66b0a236bcde4fb5561498fe8f898d4e549b2e4509f"}, - {file = "aiohttp-3.8.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3d8ef1a630519a26d6760bc695842579cb09e373c5f227a21b67dc3eb16cfea4"}, - {file = "aiohttp-3.8.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b3f2e06a512e94722886c0827bee9807c86a9f698fac6b3aee841fab49bbfb4"}, - {file = "aiohttp-3.8.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a80464982d41b1fbfe3154e440ba4904b71c1a53e9cd584098cd41efdb188ef"}, - {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b631e26df63e52f7cce0cce6507b7a7f1bc9b0c501fcde69742130b32e8782f"}, - {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f43255086fe25e36fd5ed8f2ee47477408a73ef00e804cb2b5cba4bf2ac7f5e"}, - {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4d347a172f866cd1d93126d9b239fcbe682acb39b48ee0873c73c933dd23bd0f"}, - {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3fec6a4cb5551721cdd70473eb009d90935b4063acc5f40905d40ecfea23e05"}, - {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80a37fe8f7c1e6ce8f2d9c411676e4bc633a8462844e38f46156d07a7d401654"}, - {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d1e6a862b76f34395a985b3cd39a0d949ca80a70b6ebdea37d3ab39ceea6698a"}, - {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cd468460eefef601ece4428d3cf4562459157c0f6523db89365202c31b6daebb"}, - {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:618c901dd3aad4ace71dfa0f5e82e88b46ef57e3239fc7027773cb6d4ed53531"}, - {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:652b1bff4f15f6287550b4670546a2947f2a4575b6c6dff7760eafb22eacbf0b"}, - {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80575ba9377c5171407a06d0196b2310b679dc752d02a1fcaa2bc20b235dbf24"}, - {file = "aiohttp-3.8.4-cp311-cp311-win32.whl", hash = "sha256:bbcf1a76cf6f6dacf2c7f4d2ebd411438c275faa1dc0c68e46eb84eebd05dd7d"}, - {file = "aiohttp-3.8.4-cp311-cp311-win_amd64.whl", hash = "sha256:6e74dd54f7239fcffe07913ff8b964e28b712f09846e20de78676ce2a3dc0bfc"}, - {file = "aiohttp-3.8.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:880e15bb6dad90549b43f796b391cfffd7af373f4646784795e20d92606b7a51"}, - {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb96fa6b56bb536c42d6a4a87dfca570ff8e52de2d63cabebfd6fb67049c34b6"}, - {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a6cadebe132e90cefa77e45f2d2f1a4b2ce5c6b1bfc1656c1ddafcfe4ba8131"}, - {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f352b62b45dff37b55ddd7b9c0c8672c4dd2eb9c0f9c11d395075a84e2c40f75"}, - {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ab43061a0c81198d88f39aaf90dae9a7744620978f7ef3e3708339b8ed2ef01"}, - {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9cb1565a7ad52e096a6988e2ee0397f72fe056dadf75d17fa6b5aebaea05622"}, - {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:1b3ea7edd2d24538959c1c1abf97c744d879d4e541d38305f9bd7d9b10c9ec41"}, - {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:7c7837fe8037e96b6dd5cfcf47263c1620a9d332a87ec06a6ca4564e56bd0f36"}, - {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:3b90467ebc3d9fa5b0f9b6489dfb2c304a1db7b9946fa92aa76a831b9d587e99"}, - {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:cab9401de3ea52b4b4c6971db5fb5c999bd4260898af972bf23de1c6b5dd9d71"}, - {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d1f9282c5f2b5e241034a009779e7b2a1aa045f667ff521e7948ea9b56e0c5ff"}, - {file = "aiohttp-3.8.4-cp36-cp36m-win32.whl", hash = "sha256:5e14f25765a578a0a634d5f0cd1e2c3f53964553a00347998dfdf96b8137f777"}, - {file = "aiohttp-3.8.4-cp36-cp36m-win_amd64.whl", hash = "sha256:4c745b109057e7e5f1848c689ee4fb3a016c8d4d92da52b312f8a509f83aa05e"}, - {file = "aiohttp-3.8.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:aede4df4eeb926c8fa70de46c340a1bc2c6079e1c40ccf7b0eae1313ffd33519"}, - {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ddaae3f3d32fc2cb4c53fab020b69a05c8ab1f02e0e59665c6f7a0d3a5be54f"}, - {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4eb3b82ca349cf6fadcdc7abcc8b3a50ab74a62e9113ab7a8ebc268aad35bb9"}, - {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bcb89336efa095ea21b30f9e686763f2be4478f1b0a616969551982c4ee4c3b"}, - {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c08e8ed6fa3d477e501ec9db169bfac8140e830aa372d77e4a43084d8dd91ab"}, - {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c6cd05ea06daca6ad6a4ca3ba7fe7dc5b5de063ff4daec6170ec0f9979f6c332"}, - {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7a00a9ed8d6e725b55ef98b1b35c88013245f35f68b1b12c5cd4100dddac333"}, - {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:de04b491d0e5007ee1b63a309956eaed959a49f5bb4e84b26c8f5d49de140fa9"}, - {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:40653609b3bf50611356e6b6554e3a331f6879fa7116f3959b20e3528783e699"}, - {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dbf3a08a06b3f433013c143ebd72c15cac33d2914b8ea4bea7ac2c23578815d6"}, - {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:854f422ac44af92bfe172d8e73229c270dc09b96535e8a548f99c84f82dde241"}, - {file = "aiohttp-3.8.4-cp37-cp37m-win32.whl", hash = "sha256:aeb29c84bb53a84b1a81c6c09d24cf33bb8432cc5c39979021cc0f98c1292a1a"}, - {file = "aiohttp-3.8.4-cp37-cp37m-win_amd64.whl", hash = "sha256:db3fc6120bce9f446d13b1b834ea5b15341ca9ff3f335e4a951a6ead31105480"}, - {file = "aiohttp-3.8.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fabb87dd8850ef0f7fe2b366d44b77d7e6fa2ea87861ab3844da99291e81e60f"}, - {file = "aiohttp-3.8.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:91f6d540163f90bbaef9387e65f18f73ffd7c79f5225ac3d3f61df7b0d01ad15"}, - {file = "aiohttp-3.8.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d265f09a75a79a788237d7f9054f929ced2e69eb0bb79de3798c468d8a90f945"}, - {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d89efa095ca7d442a6d0cbc755f9e08190ba40069b235c9886a8763b03785da"}, - {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4dac314662f4e2aa5009977b652d9b8db7121b46c38f2073bfeed9f4049732cd"}, - {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe11310ae1e4cd560035598c3f29d86cef39a83d244c7466f95c27ae04850f10"}, - {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ddb2a2026c3f6a68c3998a6c47ab6795e4127315d2e35a09997da21865757f8"}, - {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e75b89ac3bd27d2d043b234aa7b734c38ba1b0e43f07787130a0ecac1e12228a"}, - {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6e601588f2b502c93c30cd5a45bfc665faaf37bbe835b7cfd461753068232074"}, - {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a5d794d1ae64e7753e405ba58e08fcfa73e3fad93ef9b7e31112ef3c9a0efb52"}, - {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:a1f4689c9a1462f3df0a1f7e797791cd6b124ddbee2b570d34e7f38ade0e2c71"}, - {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:3032dcb1c35bc330134a5b8a5d4f68c1a87252dfc6e1262c65a7e30e62298275"}, - {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8189c56eb0ddbb95bfadb8f60ea1b22fcfa659396ea36f6adcc521213cd7b44d"}, - {file = "aiohttp-3.8.4-cp38-cp38-win32.whl", hash = "sha256:33587f26dcee66efb2fff3c177547bd0449ab7edf1b73a7f5dea1e38609a0c54"}, - {file = "aiohttp-3.8.4-cp38-cp38-win_amd64.whl", hash = "sha256:e595432ac259af2d4630008bf638873d69346372d38255774c0e286951e8b79f"}, - {file = "aiohttp-3.8.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5a7bdf9e57126dc345b683c3632e8ba317c31d2a41acd5800c10640387d193ed"}, - {file = "aiohttp-3.8.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:22f6eab15b6db242499a16de87939a342f5a950ad0abaf1532038e2ce7d31567"}, - {file = "aiohttp-3.8.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7235604476a76ef249bd64cb8274ed24ccf6995c4a8b51a237005ee7a57e8643"}, - {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea9eb976ffdd79d0e893869cfe179a8f60f152d42cb64622fca418cd9b18dc2a"}, - {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92c0cea74a2a81c4c76b62ea1cac163ecb20fb3ba3a75c909b9fa71b4ad493cf"}, - {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:493f5bc2f8307286b7799c6d899d388bbaa7dfa6c4caf4f97ef7521b9cb13719"}, - {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a63f03189a6fa7c900226e3ef5ba4d3bd047e18f445e69adbd65af433add5a2"}, - {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10c8cefcff98fd9168cdd86c4da8b84baaa90bf2da2269c6161984e6737bf23e"}, - {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bca5f24726e2919de94f047739d0a4fc01372801a3672708260546aa2601bf57"}, - {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:03baa76b730e4e15a45f81dfe29a8d910314143414e528737f8589ec60cf7391"}, - {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:8c29c77cc57e40f84acef9bfb904373a4e89a4e8b74e71aa8075c021ec9078c2"}, - {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:03543dcf98a6619254b409be2d22b51f21ec66272be4ebda7b04e6412e4b2e14"}, - {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:17b79c2963db82086229012cff93ea55196ed31f6493bb1ccd2c62f1724324e4"}, - {file = "aiohttp-3.8.4-cp39-cp39-win32.whl", hash = "sha256:34ce9f93a4a68d1272d26030655dd1b58ff727b3ed2a33d80ec433561b03d67a"}, - {file = "aiohttp-3.8.4-cp39-cp39-win_amd64.whl", hash = "sha256:41a86a69bb63bb2fc3dc9ad5ea9f10f1c9c8e282b471931be0268ddd09430b04"}, - {file = "aiohttp-3.8.4.tar.gz", hash = "sha256:bf2e1a9162c1e441bf805a1fd166e249d574ca04e03b34f97e2928769e91ab5c"}, + {file = "aiohttp-3.8.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a94159871304770da4dd371f4291b20cac04e8c94f11bdea1c3478e557fbe0d8"}, + {file = "aiohttp-3.8.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:13bf85afc99ce6f9ee3567b04501f18f9f8dbbb2ea11ed1a2e079670403a7c84"}, + {file = "aiohttp-3.8.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2ce2ac5708501afc4847221a521f7e4b245abf5178cf5ddae9d5b3856ddb2f3a"}, + {file = "aiohttp-3.8.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96943e5dcc37a6529d18766597c491798b7eb7a61d48878611298afc1fca946c"}, + {file = "aiohttp-3.8.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ad5c3c4590bb3cc28b4382f031f3783f25ec223557124c68754a2231d989e2b"}, + {file = "aiohttp-3.8.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0c413c633d0512df4dc7fd2373ec06cc6a815b7b6d6c2f208ada7e9e93a5061d"}, + {file = "aiohttp-3.8.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df72ac063b97837a80d80dec8d54c241af059cc9bb42c4de68bd5b61ceb37caa"}, + {file = "aiohttp-3.8.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c48c5c0271149cfe467c0ff8eb941279fd6e3f65c9a388c984e0e6cf57538e14"}, + {file = "aiohttp-3.8.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:368a42363c4d70ab52c2c6420a57f190ed3dfaca6a1b19afda8165ee16416a82"}, + {file = "aiohttp-3.8.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7607ec3ce4993464368505888af5beb446845a014bc676d349efec0e05085905"}, + {file = "aiohttp-3.8.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0d21c684808288a98914e5aaf2a7c6a3179d4df11d249799c32d1808e79503b5"}, + {file = "aiohttp-3.8.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:312fcfbacc7880a8da0ae8b6abc6cc7d752e9caa0051a53d217a650b25e9a691"}, + {file = "aiohttp-3.8.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ad093e823df03bb3fd37e7dec9d4670c34f9e24aeace76808fc20a507cace825"}, + {file = "aiohttp-3.8.5-cp310-cp310-win32.whl", hash = "sha256:33279701c04351a2914e1100b62b2a7fdb9a25995c4a104259f9a5ead7ed4802"}, + {file = "aiohttp-3.8.5-cp310-cp310-win_amd64.whl", hash = "sha256:6e4a280e4b975a2e7745573e3fc9c9ba0d1194a3738ce1cbaa80626cc9b4f4df"}, + {file = "aiohttp-3.8.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ae871a964e1987a943d83d6709d20ec6103ca1eaf52f7e0d36ee1b5bebb8b9b9"}, + {file = "aiohttp-3.8.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:461908b2578955045efde733719d62f2b649c404189a09a632d245b445c9c975"}, + {file = "aiohttp-3.8.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:72a860c215e26192379f57cae5ab12b168b75db8271f111019509a1196dfc780"}, + {file = "aiohttp-3.8.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc14be025665dba6202b6a71cfcdb53210cc498e50068bc088076624471f8bb9"}, + {file = "aiohttp-3.8.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8af740fc2711ad85f1a5c034a435782fbd5b5f8314c9a3ef071424a8158d7f6b"}, + {file = "aiohttp-3.8.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:841cd8233cbd2111a0ef0a522ce016357c5e3aff8a8ce92bcfa14cef890d698f"}, + {file = "aiohttp-3.8.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ed1c46fb119f1b59304b5ec89f834f07124cd23ae5b74288e364477641060ff"}, + {file = "aiohttp-3.8.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84f8ae3e09a34f35c18fa57f015cc394bd1389bce02503fb30c394d04ee6b938"}, + {file = "aiohttp-3.8.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:62360cb771707cb70a6fd114b9871d20d7dd2163a0feafe43fd115cfe4fe845e"}, + {file = "aiohttp-3.8.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:23fb25a9f0a1ca1f24c0a371523546366bb642397c94ab45ad3aedf2941cec6a"}, + {file = "aiohttp-3.8.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0ba0d15164eae3d878260d4c4df859bbdc6466e9e6689c344a13334f988bb53"}, + {file = "aiohttp-3.8.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5d20003b635fc6ae3f96d7260281dfaf1894fc3aa24d1888a9b2628e97c241e5"}, + {file = "aiohttp-3.8.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0175d745d9e85c40dcc51c8f88c74bfbaef9e7afeeeb9d03c37977270303064c"}, + {file = "aiohttp-3.8.5-cp311-cp311-win32.whl", hash = "sha256:2e1b1e51b0774408f091d268648e3d57f7260c1682e7d3a63cb00d22d71bb945"}, + {file = "aiohttp-3.8.5-cp311-cp311-win_amd64.whl", hash = "sha256:043d2299f6dfdc92f0ac5e995dfc56668e1587cea7f9aa9d8a78a1b6554e5755"}, + {file = "aiohttp-3.8.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cae533195e8122584ec87531d6df000ad07737eaa3c81209e85c928854d2195c"}, + {file = "aiohttp-3.8.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f21e83f355643c345177a5d1d8079f9f28b5133bcd154193b799d380331d5d3"}, + {file = "aiohttp-3.8.5-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7a75ef35f2df54ad55dbf4b73fe1da96f370e51b10c91f08b19603c64004acc"}, + {file = "aiohttp-3.8.5-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e2e9839e14dd5308ee773c97115f1e0a1cb1d75cbeeee9f33824fa5144c7634"}, + {file = "aiohttp-3.8.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44e65da1de4403d0576473e2344828ef9c4c6244d65cf4b75549bb46d40b8dd"}, + {file = "aiohttp-3.8.5-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78d847e4cde6ecc19125ccbc9bfac4a7ab37c234dd88fbb3c5c524e8e14da543"}, + {file = "aiohttp-3.8.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:c7a815258e5895d8900aec4454f38dca9aed71085f227537208057853f9d13f2"}, + {file = "aiohttp-3.8.5-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:8b929b9bd7cd7c3939f8bcfffa92fae7480bd1aa425279d51a89327d600c704d"}, + {file = "aiohttp-3.8.5-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:5db3a5b833764280ed7618393832e0853e40f3d3e9aa128ac0ba0f8278d08649"}, + {file = "aiohttp-3.8.5-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:a0215ce6041d501f3155dc219712bc41252d0ab76474615b9700d63d4d9292af"}, + {file = "aiohttp-3.8.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:fd1ed388ea7fbed22c4968dd64bab0198de60750a25fe8c0c9d4bef5abe13824"}, + {file = "aiohttp-3.8.5-cp36-cp36m-win32.whl", hash = "sha256:6e6783bcc45f397fdebc118d772103d751b54cddf5b60fbcc958382d7dd64f3e"}, + {file = "aiohttp-3.8.5-cp36-cp36m-win_amd64.whl", hash = "sha256:b5411d82cddd212644cf9360879eb5080f0d5f7d809d03262c50dad02f01421a"}, + {file = "aiohttp-3.8.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:01d4c0c874aa4ddfb8098e85d10b5e875a70adc63db91f1ae65a4b04d3344cda"}, + {file = "aiohttp-3.8.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5980a746d547a6ba173fd5ee85ce9077e72d118758db05d229044b469d9029a"}, + {file = "aiohttp-3.8.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a482e6da906d5e6e653be079b29bc173a48e381600161c9932d89dfae5942ef"}, + {file = "aiohttp-3.8.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80bd372b8d0715c66c974cf57fe363621a02f359f1ec81cba97366948c7fc873"}, + {file = "aiohttp-3.8.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1161b345c0a444ebcf46bf0a740ba5dcf50612fd3d0528883fdc0eff578006a"}, + {file = "aiohttp-3.8.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd56db019015b6acfaaf92e1ac40eb8434847d9bf88b4be4efe5bfd260aee692"}, + {file = "aiohttp-3.8.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:153c2549f6c004d2754cc60603d4668899c9895b8a89397444a9c4efa282aaf4"}, + {file = "aiohttp-3.8.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4a01951fabc4ce26ab791da5f3f24dca6d9a6f24121746eb19756416ff2d881b"}, + {file = "aiohttp-3.8.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bfb9162dcf01f615462b995a516ba03e769de0789de1cadc0f916265c257e5d8"}, + {file = "aiohttp-3.8.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:7dde0009408969a43b04c16cbbe252c4f5ef4574ac226bc8815cd7342d2028b6"}, + {file = "aiohttp-3.8.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4149d34c32f9638f38f544b3977a4c24052042affa895352d3636fa8bffd030a"}, + {file = "aiohttp-3.8.5-cp37-cp37m-win32.whl", hash = "sha256:68c5a82c8779bdfc6367c967a4a1b2aa52cd3595388bf5961a62158ee8a59e22"}, + {file = "aiohttp-3.8.5-cp37-cp37m-win_amd64.whl", hash = "sha256:2cf57fb50be5f52bda004b8893e63b48530ed9f0d6c96c84620dc92fe3cd9b9d"}, + {file = "aiohttp-3.8.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:eca4bf3734c541dc4f374ad6010a68ff6c6748f00451707f39857f429ca36ced"}, + {file = "aiohttp-3.8.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1274477e4c71ce8cfe6c1ec2f806d57c015ebf84d83373676036e256bc55d690"}, + {file = "aiohttp-3.8.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:28c543e54710d6158fc6f439296c7865b29e0b616629767e685a7185fab4a6b9"}, + {file = "aiohttp-3.8.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:910bec0c49637d213f5d9877105d26e0c4a4de2f8b1b29405ff37e9fc0ad52b8"}, + {file = "aiohttp-3.8.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5443910d662db951b2e58eb70b0fbe6b6e2ae613477129a5805d0b66c54b6cb7"}, + {file = "aiohttp-3.8.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e460be6978fc24e3df83193dc0cc4de46c9909ed92dd47d349a452ef49325b7"}, + {file = "aiohttp-3.8.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb1558def481d84f03b45888473fc5a1f35747b5f334ef4e7a571bc0dfcb11f8"}, + {file = "aiohttp-3.8.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34dd0c107799dcbbf7d48b53be761a013c0adf5571bf50c4ecad5643fe9cfcd0"}, + {file = "aiohttp-3.8.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aa1990247f02a54185dc0dff92a6904521172a22664c863a03ff64c42f9b5410"}, + {file = "aiohttp-3.8.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0e584a10f204a617d71d359fe383406305a4b595b333721fa50b867b4a0a1548"}, + {file = "aiohttp-3.8.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:a3cf433f127efa43fee6b90ea4c6edf6c4a17109d1d037d1a52abec84d8f2e42"}, + {file = "aiohttp-3.8.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:c11f5b099adafb18e65c2c997d57108b5bbeaa9eeee64a84302c0978b1ec948b"}, + {file = "aiohttp-3.8.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:84de26ddf621d7ac4c975dbea4c945860e08cccde492269db4e1538a6a6f3c35"}, + {file = "aiohttp-3.8.5-cp38-cp38-win32.whl", hash = "sha256:ab88bafedc57dd0aab55fa728ea10c1911f7e4d8b43e1d838a1739f33712921c"}, + {file = "aiohttp-3.8.5-cp38-cp38-win_amd64.whl", hash = "sha256:5798a9aad1879f626589f3df0f8b79b3608a92e9beab10e5fda02c8a2c60db2e"}, + {file = "aiohttp-3.8.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a6ce61195c6a19c785df04e71a4537e29eaa2c50fe745b732aa937c0c77169f3"}, + {file = "aiohttp-3.8.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:773dd01706d4db536335fcfae6ea2440a70ceb03dd3e7378f3e815b03c97ab51"}, + {file = "aiohttp-3.8.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f83a552443a526ea38d064588613aca983d0ee0038801bc93c0c916428310c28"}, + {file = "aiohttp-3.8.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f7372f7341fcc16f57b2caded43e81ddd18df53320b6f9f042acad41f8e049a"}, + {file = "aiohttp-3.8.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea353162f249c8097ea63c2169dd1aa55de1e8fecbe63412a9bc50816e87b761"}, + {file = "aiohttp-3.8.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d47ae48db0b2dcf70bc8a3bc72b3de86e2a590fc299fdbbb15af320d2659de"}, + {file = "aiohttp-3.8.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d827176898a2b0b09694fbd1088c7a31836d1a505c243811c87ae53a3f6273c1"}, + {file = "aiohttp-3.8.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3562b06567c06439d8b447037bb655ef69786c590b1de86c7ab81efe1c9c15d8"}, + {file = "aiohttp-3.8.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4e874cbf8caf8959d2adf572a78bba17cb0e9d7e51bb83d86a3697b686a0ab4d"}, + {file = "aiohttp-3.8.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6809a00deaf3810e38c628e9a33271892f815b853605a936e2e9e5129762356c"}, + {file = "aiohttp-3.8.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:33776e945d89b29251b33a7e7d006ce86447b2cfd66db5e5ded4e5cd0340585c"}, + {file = "aiohttp-3.8.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:eaeed7abfb5d64c539e2db173f63631455f1196c37d9d8d873fc316470dfbacd"}, + {file = "aiohttp-3.8.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e91d635961bec2d8f19dfeb41a539eb94bd073f075ca6dae6c8dc0ee89ad6f91"}, + {file = "aiohttp-3.8.5-cp39-cp39-win32.whl", hash = "sha256:00ad4b6f185ec67f3e6562e8a1d2b69660be43070bd0ef6fcec5211154c7df67"}, + {file = "aiohttp-3.8.5-cp39-cp39-win_amd64.whl", hash = "sha256:c0a9034379a37ae42dea7ac1e048352d96286626251862e448933c0f59cbd79c"}, + {file = "aiohttp-3.8.5.tar.gz", hash = "sha256:b9552ec52cc147dbf1944ac7ac98af7602e51ea2dcd076ed194ca3c0d1c7d0bc"}, ] [package.dependencies] @@ -113,7 +112,6 @@ speedups = ["Brotli", "aiodns", "cchardet"] name = "aiosignal" version = "1.3.1" description = "aiosignal: a list of registered asynchronous callbacks" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -128,7 +126,6 @@ frozenlist = ">=1.1.0" name = "async-timeout" version = "4.0.2" description = "Timeout context manager for asyncio programs" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -140,7 +137,6 @@ files = [ name = "attrs" version = "23.1.0" description = "Classes Without Boilerplate" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -159,7 +155,6 @@ tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pyte name = "bitarray" version = "2.7.3" description = "efficient arrays of booleans -- C extension" -category = "dev" optional = false python-versions = "*" files = [ @@ -256,7 +251,6 @@ files = [ name = "cbor2" version = "5.4.6" description = "CBOR (de)serializer with extensive tag support" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -306,7 +300,6 @@ test = ["pytest", "pytest-cov"] name = "certifi" version = "2023.5.7" description = "Python package for providing Mozilla's CA Bundle." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -318,7 +311,6 @@ files = [ name = "charset-normalizer" version = "3.1.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "dev" optional = false python-versions = ">=3.7.0" files = [ @@ -403,7 +395,6 @@ files = [ name = "crytic-compile" version = "0.3.1" description = "Util to facilitate smart contracts compilation." -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -423,7 +414,6 @@ dev = ["black (==22.3.0)", "darglint (==1.8.0)", "mypy (==0.942)", "pylint (==2. name = "cytoolz" version = "0.12.1" description = "Cython implementation of Toolz: High performance functional utilities" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -537,7 +527,6 @@ cython = ["cython"] name = "eth-abi" version = "4.0.0" description = "eth_abi: Python utilities for working with Ethereum ABI definitions, especially encoding and decoding" -category = "dev" optional = false python-versions = ">=3.7, <4" files = [ @@ -561,7 +550,6 @@ tools = ["hypothesis (>=4.18.2,<5.0.0)"] name = "eth-account" version = "0.8.0" description = "eth-account: Sign Ethereum transactions and messages with local private keys" -category = "dev" optional = false python-versions = ">=3.6, <4" files = [ @@ -589,7 +577,6 @@ test = ["coverage", "hypothesis (>=4.18.0,<5)", "pytest (>=6.2.5,<7)", "pytest-x name = "eth-hash" version = "0.5.1" description = "eth-hash: The Ethereum hashing function, keccak256, sometimes (erroneously) called sha3" -category = "dev" optional = false python-versions = ">=3.7, <4" files = [ @@ -612,7 +599,6 @@ test = ["pytest (>=6.2.5,<7)", "pytest-xdist (>=2.4.0,<3)", "tox (>=3.14.6,<4)"] name = "eth-keyfile" version = "0.6.1" description = "A library for handling the encrypted keyfiles used to store ethereum private keys." -category = "dev" optional = false python-versions = "*" files = [ @@ -635,7 +621,6 @@ test = ["pytest (>=6.2.5,<7)"] name = "eth-keys" version = "0.4.0" description = "Common API for Ethereum key operations." -category = "dev" optional = false python-versions = "*" files = [ @@ -658,7 +643,6 @@ test = ["asn1tools (>=0.146.2,<0.147)", "eth-hash[pycryptodome]", "eth-hash[pysh name = "eth-rlp" version = "0.3.0" description = "eth-rlp: RLP definitions for common Ethereum objects in Python" -category = "dev" optional = false python-versions = ">=3.7, <4" files = [ @@ -681,7 +665,6 @@ test = ["eth-hash[pycryptodome]", "pytest (>=6.2.5,<7)", "pytest-xdist", "tox (= name = "eth-typing" version = "3.3.0" description = "eth-typing: Common type annotations for ethereum python packages" -category = "dev" optional = false python-versions = ">=3.7.2, <4" files = [ @@ -699,7 +682,6 @@ test = ["pytest (>=6.2.5,<7)", "pytest-xdist", "tox (>=2.9.1,<3)"] name = "eth-utils" version = "2.1.0" description = "eth-utils: Common utility functions for python code that interacts with Ethereum" -category = "dev" optional = false python-versions = ">=3.7,<4" files = [ @@ -723,7 +705,6 @@ test = ["hypothesis (>=4.43.0,<5.0.0)", "pytest (>=6.2.5,<7)", "pytest-xdist", " name = "frozenlist" version = "1.3.3" description = "A list-like structure which implements collections.abc.MutableSequence" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -807,7 +788,6 @@ files = [ name = "hexbytes" version = "0.3.0" description = "hexbytes: Python `bytes` subclass that decodes hex, with a readable console output" -category = "dev" optional = false python-versions = ">=3.7, <4" files = [ @@ -825,7 +805,6 @@ test = ["eth-utils (>=1.0.1,<3)", "hypothesis (>=3.44.24,<=6.31.6)", "pytest (>= name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -837,7 +816,6 @@ files = [ name = "jsonschema" version = "4.17.3" description = "An implementation of JSON Schema validation for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -857,7 +835,6 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- name = "lru-dict" version = "1.1.8" description = "An Dict like LRU container." -category = "dev" optional = false python-versions = "*" files = [ @@ -918,7 +895,6 @@ test = ["pytest"] name = "multidict" version = "6.0.4" description = "multidict implementation" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1002,7 +978,6 @@ files = [ name = "packaging" version = "23.1" description = "Core utilities for Python packages" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1014,7 +989,6 @@ files = [ name = "parsimonious" version = "0.9.0" description = "(Soon to be) the fastest pure-Python PEG parser I could muster" -category = "dev" optional = false python-versions = "*" files = [ @@ -1028,7 +1002,6 @@ regex = ">=2022.3.15" name = "prettytable" version = "3.7.0" description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1046,7 +1019,6 @@ tests = ["pytest", "pytest-cov", "pytest-lazy-fixture"] name = "protobuf" version = "4.22.4" description = "" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1069,7 +1041,6 @@ files = [ name = "pycryptodome" version = "3.17" description = "Cryptographic library for Python" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -1112,7 +1083,6 @@ files = [ name = "pyrsistent" version = "0.19.3" description = "Persistent/Functional/Immutable data structures" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1149,7 +1119,6 @@ files = [ name = "pywin32" version = "306" description = "Python for Window Extensions" -category = "dev" optional = false python-versions = "*" files = [ @@ -1173,7 +1142,6 @@ files = [ name = "regex" version = "2023.5.5" description = "Alternative regular expression module, to replace re." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1271,7 +1239,6 @@ files = [ name = "requests" version = "2.30.0" description = "Python HTTP for Humans." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1293,7 +1260,6 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] name = "rlp" version = "3.0.0" description = "A package for Recursive Length Prefix encoding and decoding" -category = "dev" optional = false python-versions = "*" files = [ @@ -1315,7 +1281,6 @@ test = ["hypothesis (==5.19.0)", "pytest (>=6.2.5,<7)", "tox (>=2.9.1,<3)"] name = "slither-analyzer" version = "0.9.3" description = "Slither is a Solidity static analysis framework written in Python 3." -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1337,7 +1302,6 @@ dev = ["black (==22.3.0)", "deepdiff", "numpy", "openai", "pdoc", "pylint (==2.1 name = "solc-select" version = "1.0.3" description = "Manage multiple Solidity compiler versions." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1353,7 +1317,6 @@ pycryptodome = ">=3.4.6" name = "toolz" version = "0.12.0" description = "List processing tools and functional utilities" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -1365,7 +1328,6 @@ files = [ name = "urllib3" version = "2.0.2" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1383,7 +1345,6 @@ zstd = ["zstandard (>=0.18.0)"] name = "wcwidth" version = "0.2.6" description = "Measures the displayed width of unicode strings in a terminal" -category = "dev" optional = false python-versions = "*" files = [ @@ -1395,7 +1356,6 @@ files = [ name = "web3" version = "6.3.0" description = "web3.py" -category = "dev" optional = false python-versions = ">=3.7.2" files = [ @@ -1429,7 +1389,6 @@ tester = ["eth-tester[py-evm] (==v0.8.0-b.3)", "py-geth (>=3.11.0)"] name = "websockets" version = "11.0.3" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1509,7 +1468,6 @@ files = [ name = "yarl" version = "1.9.2" description = "Yet another URL library" -category = "dev" optional = false python-versions = ">=3.7" files = [ From 42be07800f096cfb323efb78b1c5687244b6456c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Jul 2023 23:20:20 +0000 Subject: [PATCH 021/218] chore(deps-dev): bump certifi from 2023.5.7 to 2023.7.22 Bumps [certifi](https://github.com/certifi/python-certifi) from 2023.5.7 to 2023.7.22. - [Commits](https://github.com/certifi/python-certifi/compare/2023.05.07...2023.07.22) --- updated-dependencies: - dependency-name: certifi dependency-type: indirect ... Signed-off-by: dependabot[bot] --- poetry.lock | 50 ++++---------------------------------------------- 1 file changed, 4 insertions(+), 46 deletions(-) diff --git a/poetry.lock b/poetry.lock index 9ee19f775..33866cdd9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,9 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "aiohttp" version = "3.8.4" description = "Async http client/server framework (asyncio)" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -113,7 +112,6 @@ speedups = ["Brotli", "aiodns", "cchardet"] name = "aiosignal" version = "1.3.1" description = "aiosignal: a list of registered asynchronous callbacks" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -128,7 +126,6 @@ frozenlist = ">=1.1.0" name = "async-timeout" version = "4.0.2" description = "Timeout context manager for asyncio programs" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -140,7 +137,6 @@ files = [ name = "attrs" version = "23.1.0" description = "Classes Without Boilerplate" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -159,7 +155,6 @@ tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pyte name = "bitarray" version = "2.7.3" description = "efficient arrays of booleans -- C extension" -category = "dev" optional = false python-versions = "*" files = [ @@ -256,7 +251,6 @@ files = [ name = "cbor2" version = "5.4.6" description = "CBOR (de)serializer with extensive tag support" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -304,21 +298,19 @@ test = ["pytest", "pytest-cov"] [[package]] name = "certifi" -version = "2023.5.7" +version = "2023.7.22" description = "Python package for providing Mozilla's CA Bundle." -category = "dev" optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"}, - {file = "certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"}, + {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, + {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, ] [[package]] name = "charset-normalizer" version = "3.1.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "dev" optional = false python-versions = ">=3.7.0" files = [ @@ -403,7 +395,6 @@ files = [ name = "crytic-compile" version = "0.3.1" description = "Util to facilitate smart contracts compilation." -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -423,7 +414,6 @@ dev = ["black (==22.3.0)", "darglint (==1.8.0)", "mypy (==0.942)", "pylint (==2. name = "cytoolz" version = "0.12.1" description = "Cython implementation of Toolz: High performance functional utilities" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -537,7 +527,6 @@ cython = ["cython"] name = "eth-abi" version = "4.0.0" description = "eth_abi: Python utilities for working with Ethereum ABI definitions, especially encoding and decoding" -category = "dev" optional = false python-versions = ">=3.7, <4" files = [ @@ -561,7 +550,6 @@ tools = ["hypothesis (>=4.18.2,<5.0.0)"] name = "eth-account" version = "0.8.0" description = "eth-account: Sign Ethereum transactions and messages with local private keys" -category = "dev" optional = false python-versions = ">=3.6, <4" files = [ @@ -589,7 +577,6 @@ test = ["coverage", "hypothesis (>=4.18.0,<5)", "pytest (>=6.2.5,<7)", "pytest-x name = "eth-hash" version = "0.5.1" description = "eth-hash: The Ethereum hashing function, keccak256, sometimes (erroneously) called sha3" -category = "dev" optional = false python-versions = ">=3.7, <4" files = [ @@ -612,7 +599,6 @@ test = ["pytest (>=6.2.5,<7)", "pytest-xdist (>=2.4.0,<3)", "tox (>=3.14.6,<4)"] name = "eth-keyfile" version = "0.6.1" description = "A library for handling the encrypted keyfiles used to store ethereum private keys." -category = "dev" optional = false python-versions = "*" files = [ @@ -635,7 +621,6 @@ test = ["pytest (>=6.2.5,<7)"] name = "eth-keys" version = "0.4.0" description = "Common API for Ethereum key operations." -category = "dev" optional = false python-versions = "*" files = [ @@ -658,7 +643,6 @@ test = ["asn1tools (>=0.146.2,<0.147)", "eth-hash[pycryptodome]", "eth-hash[pysh name = "eth-rlp" version = "0.3.0" description = "eth-rlp: RLP definitions for common Ethereum objects in Python" -category = "dev" optional = false python-versions = ">=3.7, <4" files = [ @@ -681,7 +665,6 @@ test = ["eth-hash[pycryptodome]", "pytest (>=6.2.5,<7)", "pytest-xdist", "tox (= name = "eth-typing" version = "3.3.0" description = "eth-typing: Common type annotations for ethereum python packages" -category = "dev" optional = false python-versions = ">=3.7.2, <4" files = [ @@ -699,7 +682,6 @@ test = ["pytest (>=6.2.5,<7)", "pytest-xdist", "tox (>=2.9.1,<3)"] name = "eth-utils" version = "2.1.0" description = "eth-utils: Common utility functions for python code that interacts with Ethereum" -category = "dev" optional = false python-versions = ">=3.7,<4" files = [ @@ -723,7 +705,6 @@ test = ["hypothesis (>=4.43.0,<5.0.0)", "pytest (>=6.2.5,<7)", "pytest-xdist", " name = "frozenlist" version = "1.3.3" description = "A list-like structure which implements collections.abc.MutableSequence" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -807,7 +788,6 @@ files = [ name = "hexbytes" version = "0.3.0" description = "hexbytes: Python `bytes` subclass that decodes hex, with a readable console output" -category = "dev" optional = false python-versions = ">=3.7, <4" files = [ @@ -825,7 +805,6 @@ test = ["eth-utils (>=1.0.1,<3)", "hypothesis (>=3.44.24,<=6.31.6)", "pytest (>= name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -837,7 +816,6 @@ files = [ name = "jsonschema" version = "4.17.3" description = "An implementation of JSON Schema validation for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -857,7 +835,6 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- name = "lru-dict" version = "1.1.8" description = "An Dict like LRU container." -category = "dev" optional = false python-versions = "*" files = [ @@ -918,7 +895,6 @@ test = ["pytest"] name = "multidict" version = "6.0.4" description = "multidict implementation" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1002,7 +978,6 @@ files = [ name = "packaging" version = "23.1" description = "Core utilities for Python packages" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1014,7 +989,6 @@ files = [ name = "parsimonious" version = "0.9.0" description = "(Soon to be) the fastest pure-Python PEG parser I could muster" -category = "dev" optional = false python-versions = "*" files = [ @@ -1028,7 +1002,6 @@ regex = ">=2022.3.15" name = "prettytable" version = "3.7.0" description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1046,7 +1019,6 @@ tests = ["pytest", "pytest-cov", "pytest-lazy-fixture"] name = "protobuf" version = "4.22.4" description = "" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1069,7 +1041,6 @@ files = [ name = "pycryptodome" version = "3.17" description = "Cryptographic library for Python" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -1112,7 +1083,6 @@ files = [ name = "pyrsistent" version = "0.19.3" description = "Persistent/Functional/Immutable data structures" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1149,7 +1119,6 @@ files = [ name = "pywin32" version = "306" description = "Python for Window Extensions" -category = "dev" optional = false python-versions = "*" files = [ @@ -1173,7 +1142,6 @@ files = [ name = "regex" version = "2023.5.5" description = "Alternative regular expression module, to replace re." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1271,7 +1239,6 @@ files = [ name = "requests" version = "2.30.0" description = "Python HTTP for Humans." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1293,7 +1260,6 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] name = "rlp" version = "3.0.0" description = "A package for Recursive Length Prefix encoding and decoding" -category = "dev" optional = false python-versions = "*" files = [ @@ -1315,7 +1281,6 @@ test = ["hypothesis (==5.19.0)", "pytest (>=6.2.5,<7)", "tox (>=2.9.1,<3)"] name = "slither-analyzer" version = "0.9.3" description = "Slither is a Solidity static analysis framework written in Python 3." -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1337,7 +1302,6 @@ dev = ["black (==22.3.0)", "deepdiff", "numpy", "openai", "pdoc", "pylint (==2.1 name = "solc-select" version = "1.0.3" description = "Manage multiple Solidity compiler versions." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1353,7 +1317,6 @@ pycryptodome = ">=3.4.6" name = "toolz" version = "0.12.0" description = "List processing tools and functional utilities" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -1365,7 +1328,6 @@ files = [ name = "urllib3" version = "2.0.2" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1383,7 +1345,6 @@ zstd = ["zstandard (>=0.18.0)"] name = "wcwidth" version = "0.2.6" description = "Measures the displayed width of unicode strings in a terminal" -category = "dev" optional = false python-versions = "*" files = [ @@ -1395,7 +1356,6 @@ files = [ name = "web3" version = "6.3.0" description = "web3.py" -category = "dev" optional = false python-versions = ">=3.7.2" files = [ @@ -1429,7 +1389,6 @@ tester = ["eth-tester[py-evm] (==v0.8.0-b.3)", "py-geth (>=3.11.0)"] name = "websockets" version = "11.0.3" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1509,7 +1468,6 @@ files = [ name = "yarl" version = "1.9.2" description = "Yet another URL library" -category = "dev" optional = false python-versions = ">=3.7" files = [ From 4ee8adadc2edc69f7e6e15e03fe193954c4c03a6 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Thu, 31 Aug 2023 17:42:57 +0200 Subject: [PATCH 022/218] test: clone module --- test/0.4.24/clone-app.test.js | 320 ++++++++++++++++++++++++++++++++++ test/helpers/config.js | 1 + test/helpers/factories.js | 110 +++++++++++- test/helpers/protocol.js | 30 ++-- test/helpers/voting.js | 27 +++ 5 files changed, 466 insertions(+), 22 deletions(-) create mode 100644 test/0.4.24/clone-app.test.js create mode 100644 test/helpers/voting.js diff --git a/test/0.4.24/clone-app.test.js b/test/0.4.24/clone-app.test.js new file mode 100644 index 000000000..35750e16d --- /dev/null +++ b/test/0.4.24/clone-app.test.js @@ -0,0 +1,320 @@ +const { artifacts, contract, ethers, web3 } = require('hardhat') +const { assert } = require('../helpers/assert') + +const { hash } = require('eth-ens-namehash') +const { encodeCallScript } = require('@aragon/contract-helpers-test/src/aragon-os') +const { getEventAt } = require('@aragon/contract-helpers-test') + +const { EvmSnapshot } = require('../helpers/blockchain') +const { deployProtocol } = require('../helpers/protocol') +const { createVote, enactVote } = require('../helpers/voting') +const { setupNodeOperatorsRegistry, NodeOperatorsRegistry } = require('../helpers/staking-modules') +const { padRight } = require('../helpers/utils') + +const StakingRouter = artifacts.require('StakingRouter') + +const { + lidoMockFactory, + oracleReportSanityCheckerStubFactory, + votingFactory, + hashConsensusFactory, + stakingRouterFactory, + addStakingModulesWrapper, + postSetup, +} = require('../helpers/factories') + +// bytes32 0x63757261746564 +const CURATED_TYPE = padRight(web3.utils.fromAscii('curated'), 32) +// const PENALTY_DELAY = 2 * 24 * 60 * 60 // 2 days + +const KERNEL_APP_BASES_NAMESPACE = '0xf1f3eb40f5bc1ad1344716ced8b8a0431d840b5783aea1fd01786bc26f35ac0f' + +contract('Simple DVT', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody, depositor, treasury]) => { + let operators + let dao + let stakingRouter + let lidoLocator + let snapshot + let acl + let voting + let tokenManager + // let pool + + before('deploy base app', async () => { + const deployed = await deployProtocol({ + oracleReportSanityCheckerFactory: oracleReportSanityCheckerStubFactory, + lidoFactory: (protocol) => { + return lidoMockFactory({ ...protocol, voting: protocol.appManager }) + }, + stakingRouterFactory: (protocol) => { + return stakingRouterFactory({ ...protocol, voting: protocol.appManager }) + }, + hashConsensusFactory: (protocol) => { + return hashConsensusFactory({ ...protocol, voting: protocol.appManager }) + }, + postSetup: (protocol) => { + return postSetup({ ...protocol, voting: protocol.appManager }) + }, + addStakingModulesWrapper: (protocol, stakingModules) => { + return addStakingModulesWrapper({ ...protocol, voting: protocol.appManager }, stakingModules) + }, + stakingModulesFactory: async (protocol) => { + const curatedModule = await setupNodeOperatorsRegistry({ ...protocol, voting: protocol.appManager }, false) + + // await protocol.acl.grantPermission( + // protocol.appManager.address, + // curatedModule.address, + // await curatedModule.MANAGE_NODE_OPERATOR_ROLE() + // ) + // await protocol.acl.grantPermission( + // protocol.appManager.address, + // curatedModule.address, + // await curatedModule.MANAGE_NODE_OPERATOR_ROLE() + // ) + + // await protocol.acl.grantPermission( + // protocol.appManager.address, + // protocol.stakingRouter.address, + // await protocol.stakingRouter.STAKING_MODULE_MANAGE_ROLE() + // ) + + await protocol.stakingRouter.grantRole( + await protocol.stakingRouter.STAKING_MODULE_MANAGE_ROLE(), + protocol.voting.address, + { + from: protocol.appManager.address, + } + ) + + return [ + { + module: curatedModule, + name: 'Curated', + targetShares: 10000, + moduleFee: 500, + treasuryFee: 500, + }, + ] + }, + votingFactory, + depositSecurityModuleFactory: async () => { + return { address: depositor } + }, + }) + + dao = deployed.dao + acl = deployed.acl + stakingRouter = deployed.stakingRouter + operators = deployed.stakingModules[0] + lidoLocator = deployed.lidoLocator + tokenManager = deployed.tokenManager + voting = deployed.voting + // pool = deployed.pool + + snapshot = new EvmSnapshot(ethers.provider) + await snapshot.make() + }) + + afterEach(async () => { + await snapshot.rollback() + }) + + const newAppProxy = async (dao, appId) => { + const receipt = await dao.newAppProxy(dao.address, appId) + + // Find the deployed proxy address in the tx logs. + const logs = receipt.logs + const log = logs.find((l) => l.event === 'NewAppProxy') + const proxyAddress = log.args.proxy + + return proxyAddress + } + + describe('clone NOR to simple-dvt', () => { + const cloneAppName = 'simple-dvt' + const cloneAppId = hash(`${cloneAppName}.aragonpm.test`) + let cloneAppProxyAddress + let cloneApp + + const moduleName = 'SimpleDVT' + const penaltyDelay = 3600 + const targetShare = 1000 // 10% + const moduleFee = 500 + const treasuryFee = 500 + + let norAppId + let norBaseImpl + + async function checkCloneModule(tx) { + const addEvent = getEventAt(tx, 'StakingModuleAdded', { decodeForAbi: StakingRouter.abi }) + + assert.equals(addEvent.args.stakingModuleId, 2) + assert.equals(addEvent.args.stakingModule.toLowerCase(), cloneApp.address.toLowerCase()) + assert.equals(addEvent.args.name, moduleName) + + assert.equals(await stakingRouter.getStakingModulesCount(), 2) + + const moduleInfo = await stakingRouter.getStakingModule(2) + // assert.equals(moduleType, CURATED_TYPE) + + assert.equals(moduleInfo.name, moduleName) + assert.equals(moduleInfo.stakingModuleAddress, cloneApp.address) + assert.equals(moduleInfo.stakingModuleFee, moduleFee) + assert.equals(moduleInfo.treasuryFee, treasuryFee) + assert.equals(moduleInfo.targetShare, targetShare) + + const moduleSummary = await stakingRouter.getStakingModuleSummary(2) + assert.equals(moduleSummary.totalExitedValidators, 0) + assert.equals(moduleSummary.totalDepositedValidators, 0) + assert.equals(moduleSummary.depositableValidatorsCount, 0) + } + + before(async () => { + norAppId = await operators.appId() + norBaseImpl = await dao.getApp(KERNEL_APP_BASES_NAMESPACE, norAppId) + }) + + it('manual clone', async () => { + // deploy stub proxy + cloneAppProxyAddress = await newAppProxy(dao, cloneAppId) + cloneApp = await NodeOperatorsRegistry.at(cloneAppProxyAddress) + + // setup aragon app + await dao.setApp(KERNEL_APP_BASES_NAMESPACE, cloneAppId, norBaseImpl, { from: appManager }) + assert.equal(await dao.getApp(KERNEL_APP_BASES_NAMESPACE, await cloneApp.appId()), norBaseImpl) + + // initialize module + await cloneApp.initialize(lidoLocator.address, CURATED_TYPE, penaltyDelay, { from: nobody }) + assert.equal(await cloneApp.getType(), CURATED_TYPE) + assert.equal(await cloneApp.getStuckPenaltyDelay(), penaltyDelay) + + // set roles + + await Promise.all([ + // Allow voting to manage node operators registry + acl.createPermission(appManager, cloneApp.address, await operators.MANAGE_SIGNING_KEYS(), appManager, { + from: appManager, + }), + acl.createPermission(appManager, cloneApp.address, await operators.MANAGE_NODE_OPERATOR_ROLE(), appManager, { + from: appManager, + }), + acl.createPermission(appManager, cloneApp.address, await operators.SET_NODE_OPERATOR_LIMIT_ROLE(), appManager, { + from: appManager, + }), + acl.createPermission( + stakingRouter.address, + cloneApp.address, + await operators.STAKING_ROUTER_ROLE(), + appManager, + { + from: appManager, + } + ), + ]) + + // add to SR + const tx = await stakingRouter.addStakingModule( + moduleName, // name + cloneApp.address, // module name + targetShare, + moduleFee, + treasuryFee, + { from: appManager.address } + ) + + await checkCloneModule(tx) + }) + + it('via voting', async () => { + // deploy stub proxy + cloneAppProxyAddress = await newAppProxy(dao, cloneAppId) + cloneApp = await NodeOperatorsRegistry.at(cloneAppProxyAddress) + + const evmScriptCalls = [ + // { + // // registry.newRepoWithVersion(appName, aclGrantee, initialSemanticVersion, contractAddress, contentURI) + // to: apm.address, + // calldata: await apm.contract.methods + // .newRepoWithVersion(trgAppName, voting.address, version, contractAddress, contentURI) + // .encodeABI(), + // }, + // setup aragon app + { + to: dao.address, + calldata: await dao.contract.methods.setApp(KERNEL_APP_BASES_NAMESPACE, cloneAppId, norBaseImpl).encodeABI(), + }, + // initialize module + { + to: cloneApp.address, + calldata: await cloneApp.contract.methods + .initialize(lidoLocator.address, CURATED_TYPE, penaltyDelay) + .encodeABI(), + }, + + // set roles + { + to: acl.address, + calldata: await acl.contract.methods + .createPermission(voting.address, cloneApp.address, await operators.MANAGE_SIGNING_KEYS(), voting.address) + .encodeABI(), + }, + { + to: acl.address, + calldata: await acl.contract.methods + .createPermission( + voting.address, + cloneApp.address, + await operators.MANAGE_NODE_OPERATOR_ROLE(), + voting.address + ) + .encodeABI(), + }, + { + to: acl.address, + calldata: await acl.contract.methods + .createPermission( + voting.address, + cloneApp.address, + await operators.SET_NODE_OPERATOR_LIMIT_ROLE(), + voting.address + ) + .encodeABI(), + }, + { + to: acl.address, + calldata: await acl.contract.methods + .createPermission( + stakingRouter.address, + cloneApp.address, + await operators.STAKING_ROUTER_ROLE(), + voting.address + ) + .encodeABI(), + }, + + // add to SR + { + to: stakingRouter.address, + calldata: await stakingRouter.contract.methods + .addStakingModule( + moduleName, // name + cloneApp.address, // module name + targetShare, + moduleFee, + treasuryFee + ) + .encodeABI(), + }, + ] + + const voteId = await createVote(voting, tokenManager, `Clone NOR`, encodeCallScript(evmScriptCalls), { + from: appManager, + }) + await voting.vote(voteId, true, true, { from: appManager }) + + const tx = await enactVote(voting, voteId, { from: appManager }) + + await checkCloneModule(tx) + }) + }) +}) diff --git a/test/helpers/config.js b/test/helpers/config.js index 451c89a02..3d127ecf2 100644 --- a/test/helpers/config.js +++ b/test/helpers/config.js @@ -64,6 +64,7 @@ const DEFAULT_FACTORIES = { eip712StETHFactory: factories.eip712StETHFactory, withdrawalCredentialsFactory: factories.withdrawalCredentialsFactory, stakingModulesFactory: factories.stakingModulesFactory, + addStakingModulesWrapper: factories.addStakingModulesWrapper, guardiansFactory: factories.guardiansFactory, burnerFactory: factories.burnerFactory, postSetup: factories.postSetup, diff --git a/test/helpers/factories.js b/test/helpers/factories.js index a68349244..a6a2151c8 100644 --- a/test/helpers/factories.js +++ b/test/helpers/factories.js @@ -3,7 +3,7 @@ const withdrawals = require('./withdrawals') const { newApp } = require('./dao') const { artifacts } = require('hardhat') const { deployLocatorWithDummyAddressesImplementation } = require('./locator-deploy') -const { ETH } = require('./utils') +const { ETH, ZERO_ADDRESS } = require('./utils') const { SLOTS_PER_EPOCH, SECONDS_PER_SLOT, EPOCHS_PER_FRAME, CONSENSUS_VERSION } = require('./constants') @@ -27,6 +27,9 @@ const Burner = artifacts.require('Burner') const OracleReportSanityChecker = artifacts.require('OracleReportSanityChecker') const ValidatorsExitBusOracle = artifacts.require('ValidatorsExitBusOracle') const OracleReportSanityCheckerStub = artifacts.require('OracleReportSanityCheckerStub') +const Voting = artifacts.require('Voting') +const MiniMeToken = artifacts.require('MiniMeToken') +const TokenManager = artifacts.require('TokenManager') async function lidoMockFactory({ dao, appManager, acl, voting }) { const base = await LidoMock.new() @@ -74,7 +77,93 @@ async function appManagerFactory({ signers }) { } async function votingEOAFactory({ signers }) { - return signers[1] + return { voting: signers[1], govToken: null, tokenManager: null } +} + +async function votingFactory({ appManager, dao, acl, deployParams }) { + const { + govTokenDecimals = 18, + govTokenName = 'GovToken', + govTokenSymbol = 'GT', + govTotalSupply = '1000000000000000000000000', + minSupportRequired = '500000000000000000', + minAcceptanceQuorum = '50000000000000000', + voteDuration = 3600, + objectionPhaseDuration = 1800, + } = deployParams + + // deploy gov token (aka LDO) + const govToken = await MiniMeToken.new( + ZERO_ADDRESS, + ZERO_ADDRESS, + 0, + govTokenName, + govTokenDecimals, + govTokenSymbol, + true + ) + + // deploy TokenManager + const tmBase = await TokenManager.new() + const tmProxyAddress = await newApp(dao, 'aragon-token-manager', tmBase.address, appManager.address) + const tokenManager = await TokenManager.at(tmProxyAddress) + await govToken.changeController(tokenManager.address, { from: appManager.address }) + await tokenManager.initialize(govToken.address, true, 0, { from: appManager.address }) + + await Promise.all([ + acl.createPermission( + appManager.address, + tokenManager.address, + await tokenManager.ISSUE_ROLE(), + appManager.address, + { + from: appManager.address, + } + ), + acl.createPermission( + appManager.address, + tokenManager.address, + await tokenManager.ASSIGN_ROLE(), + appManager.address, + { + from: appManager.address, + } + ), + ]) + + // issue gov token to appManger + await tokenManager.issue(govTotalSupply, { from: appManager.address }) + await tokenManager.assign(appManager.address, govTotalSupply, { from: appManager.address }) + + // deploy Voting + const votingBase = await Voting.new() + const proxyAddress = await newApp(dao, 'aragon-voting', votingBase.address, appManager.address) + const voting = await Voting.at(proxyAddress) + await voting.initialize( + govToken.address, + minSupportRequired, + minAcceptanceQuorum, + voteDuration, + objectionPhaseDuration, + { from: appManager.address } + ) + + await Promise.all([ + acl.grantPermission(voting.address, acl.address, await acl.CREATE_PERMISSIONS_ROLE(), { + from: appManager.address, + }), + acl.grantPermission(voting.address, dao.address, await dao.APP_MANAGER_ROLE(), { + from: appManager.address, + }), + acl.createPermission(tokenManager.address, voting.address, await voting.CREATE_VOTES_ROLE(), appManager.address, { + from: appManager.address, + }), + // acl.createPermission(voting.address, tokenManager.address, await tokenManager.ASSIGN_ROLE(), voting.address, { + // from: appManager.address, + // }), + ]) + + return { voting, govToken, tokenManager } } async function treasuryFactory(_) { @@ -287,6 +376,21 @@ async function stakingModulesFactory(_) { return [] } +async function addStakingModulesWrapper(protocol, stakingModules = []) { + for (const stakingModule of stakingModules) { + await protocol.stakingRouter.addStakingModule( + stakingModule.name, + stakingModule.module.address, + stakingModule.targetShares, + stakingModule.moduleFee, + stakingModule.treasuryFee, + { from: protocol.voting.address } + ) + } + + return stakingModules.map(({ module }) => module) +} + async function guardiansFactory({ deployParams }) { return { privateKeys: deployParams.guardians, @@ -399,6 +503,7 @@ module.exports = { appManagerFactory, treasuryFactory, votingEOAFactory, + votingFactory, depositContractFactory, lidoMockFactory, wstethFactory, @@ -412,6 +517,7 @@ module.exports = { eip712StETHFactory, withdrawalCredentialsFactory, stakingModulesFactory, + addStakingModulesWrapper, guardiansFactory, burnerFactory, postSetup, diff --git a/test/helpers/protocol.js b/test/helpers/protocol.js index b338acef1..336dc9c0a 100644 --- a/test/helpers/protocol.js +++ b/test/helpers/protocol.js @@ -13,13 +13,17 @@ async function deployProtocol(factories = {}, deployParams = {}) { protocol.signers = await ethers.getSigners() protocol.appManager = await protocol.factories.appManagerFactory(protocol) protocol.treasury = await protocol.factories.treasuryFactory(protocol) - protocol.voting = await protocol.factories.votingFactory(protocol) - protocol.guardians = await protocol.factories.guardiansFactory(protocol) const { dao, acl } = await newDao(protocol.appManager.address) protocol.dao = dao protocol.acl = acl + const { govToken, tokenManager, voting } = await protocol.factories.votingFactory(protocol) + protocol.govToken = govToken + protocol.tokenManager = tokenManager + protocol.voting = voting + + protocol.guardians = await protocol.factories.guardiansFactory(protocol) protocol.pool = await protocol.factories.lidoFactory(protocol) protocol.token = protocol.pool protocol.wsteth = await protocol.factories.wstethFactory(protocol) @@ -42,7 +46,10 @@ async function deployProtocol(factories = {}, deployParams = {}) { protocol.withdrawalCredentials = await protocol.factories.withdrawalCredentialsFactory(protocol) protocol.stakingRouter = await protocol.factories.stakingRouterFactory(protocol) - protocol.stakingModules = await addStakingModules(protocol.factories.stakingModulesFactory, protocol) + protocol.stakingModules = await protocol.factories.addStakingModulesWrapper( + protocol, + await protocol.factories.stakingModulesFactory(protocol) + ) protocol.depositSecurityModule = await protocol.factories.depositSecurityModuleFactory(protocol) protocol.elRewardsVault = await protocol.factories.elRewardsVaultFactory(protocol) @@ -75,23 +82,6 @@ async function deployProtocol(factories = {}, deployParams = {}) { return protocol } -async function addStakingModules(stakingModulesFactory, protocol) { - const stakingModules = await stakingModulesFactory(protocol) - - for (const stakingModule of stakingModules) { - await protocol.stakingRouter.addStakingModule( - stakingModule.name, - stakingModule.module.address, - stakingModule.targetShares, - stakingModule.moduleFee, - stakingModule.treasuryFee, - { from: protocol.voting.address } - ) - } - - return stakingModules.map(({ module }) => module) -} - module.exports = { deployProtocol, } diff --git a/test/helpers/voting.js b/test/helpers/voting.js new file mode 100644 index 000000000..5f5c41bf5 --- /dev/null +++ b/test/helpers/voting.js @@ -0,0 +1,27 @@ +const { artifacts } = require('hardhat') +const { getEventArgument } = require('@aragon/contract-helpers-test') +const { encodeCallScript } = require('@aragon/contract-helpers-test/src/aragon-os') +const { advanceChainTime } = require('./blockchain') +const Voting = artifacts.require('Voting') + +async function createVote(voting, tokenManager, voteDesc, evmScript, txOpts) { + const newVoteEvmScript = encodeCallScript([ + { + to: voting.address, + calldata: await voting.contract.methods.newVote(evmScript, voteDesc).encodeABI(), + }, + ]) + const tx = await tokenManager.forward(newVoteEvmScript, txOpts) + return getEventArgument(tx, 'StartVote', 'voteId', { decodeForAbi: Voting.abi }) +} + +async function enactVote(voting, voteId, txOpts) { + const voteTime = (await voting.voteTime()).toNumber() + await advanceChainTime(voteTime) + return await voting.executeVote(voteId, txOpts) +} + +module.exports = { + createVote, + enactVote, +} From d6e87d196b45d278781563b61f16fbf09663d3f4 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Thu, 7 Sep 2023 04:03:04 +0200 Subject: [PATCH 023/218] test: refactor dao factory --- test/0.4.24/clone-app.test.js | 2 +- test/helpers/factories.js | 30 +++++++++++++++--------------- test/helpers/protocol.js | 4 ++-- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/test/0.4.24/clone-app.test.js b/test/0.4.24/clone-app.test.js index 35750e16d..b8dc6c7be 100644 --- a/test/0.4.24/clone-app.test.js +++ b/test/0.4.24/clone-app.test.js @@ -89,7 +89,7 @@ contract('Simple DVT', ([appManager, , , , , , , , , , , , user1, user2, user3, return [ { module: curatedModule, - name: 'Curated', + name: 'SimpleDVT', targetShares: 10000, moduleFee: 500, treasuryFee: 500, diff --git a/test/helpers/factories.js b/test/helpers/factories.js index a6a2151c8..1b31ae128 100644 --- a/test/helpers/factories.js +++ b/test/helpers/factories.js @@ -77,15 +77,15 @@ async function appManagerFactory({ signers }) { } async function votingEOAFactory({ signers }) { - return { voting: signers[1], govToken: null, tokenManager: null } + return { voting: signers[1], daoToken: null, tokenManager: null } } async function votingFactory({ appManager, dao, acl, deployParams }) { const { - govTokenDecimals = 18, - govTokenName = 'GovToken', - govTokenSymbol = 'GT', - govTotalSupply = '1000000000000000000000000', + daoTokenDecimals = 18, + daoTokenName = 'DAO Token', + daoTokenSymbol = 'DAOTKN', + daoTokenTotalSupply = '1000000000000000000000000', minSupportRequired = '500000000000000000', minAcceptanceQuorum = '50000000000000000', voteDuration = 3600, @@ -93,13 +93,13 @@ async function votingFactory({ appManager, dao, acl, deployParams }) { } = deployParams // deploy gov token (aka LDO) - const govToken = await MiniMeToken.new( + const daoToken = await MiniMeToken.new( ZERO_ADDRESS, ZERO_ADDRESS, 0, - govTokenName, - govTokenDecimals, - govTokenSymbol, + daoTokenName, + daoTokenDecimals, + daoTokenSymbol, true ) @@ -107,8 +107,8 @@ async function votingFactory({ appManager, dao, acl, deployParams }) { const tmBase = await TokenManager.new() const tmProxyAddress = await newApp(dao, 'aragon-token-manager', tmBase.address, appManager.address) const tokenManager = await TokenManager.at(tmProxyAddress) - await govToken.changeController(tokenManager.address, { from: appManager.address }) - await tokenManager.initialize(govToken.address, true, 0, { from: appManager.address }) + await daoToken.changeController(tokenManager.address, { from: appManager.address }) + await tokenManager.initialize(daoToken.address, true, 0, { from: appManager.address }) await Promise.all([ acl.createPermission( @@ -132,15 +132,15 @@ async function votingFactory({ appManager, dao, acl, deployParams }) { ]) // issue gov token to appManger - await tokenManager.issue(govTotalSupply, { from: appManager.address }) - await tokenManager.assign(appManager.address, govTotalSupply, { from: appManager.address }) + await tokenManager.issue(daoTokenTotalSupply, { from: appManager.address }) + await tokenManager.assign(appManager.address, daoTokenTotalSupply, { from: appManager.address }) // deploy Voting const votingBase = await Voting.new() const proxyAddress = await newApp(dao, 'aragon-voting', votingBase.address, appManager.address) const voting = await Voting.at(proxyAddress) await voting.initialize( - govToken.address, + daoToken.address, minSupportRequired, minAcceptanceQuorum, voteDuration, @@ -163,7 +163,7 @@ async function votingFactory({ appManager, dao, acl, deployParams }) { // }), ]) - return { voting, govToken, tokenManager } + return { voting, daoToken, tokenManager } } async function treasuryFactory(_) { diff --git a/test/helpers/protocol.js b/test/helpers/protocol.js index 336dc9c0a..1449df1e1 100644 --- a/test/helpers/protocol.js +++ b/test/helpers/protocol.js @@ -18,8 +18,8 @@ async function deployProtocol(factories = {}, deployParams = {}) { protocol.dao = dao protocol.acl = acl - const { govToken, tokenManager, voting } = await protocol.factories.votingFactory(protocol) - protocol.govToken = govToken + const { daoToken, tokenManager, voting } = await protocol.factories.votingFactory(protocol) + protocol.daoToken = daoToken protocol.tokenManager = tokenManager protocol.voting = voting From 1ea7f4220e6deea476bccf1a6425928114c4953f Mon Sep 17 00:00:00 2001 From: KRogLA Date: Thu, 7 Sep 2023 04:12:17 +0200 Subject: [PATCH 024/218] feat: clone NOR scripts --- scripts/cloneapp/01-deploy-app-proxy.js | 71 ++++++ scripts/cloneapp/02-clone-nor.js | 277 ++++++++++++++++++++++++ scripts/cloneapp/helpers.js | 18 ++ 3 files changed, 366 insertions(+) create mode 100644 scripts/cloneapp/01-deploy-app-proxy.js create mode 100644 scripts/cloneapp/02-clone-nor.js create mode 100644 scripts/cloneapp/helpers.js diff --git a/scripts/cloneapp/01-deploy-app-proxy.js b/scripts/cloneapp/01-deploy-app-proxy.js new file mode 100644 index 000000000..ecbb412d0 --- /dev/null +++ b/scripts/cloneapp/01-deploy-app-proxy.js @@ -0,0 +1,71 @@ +const { network } = require('hardhat') +const chalk = require('chalk') + +const runOrWrapScript = require('../helpers/run-or-wrap-script') +const { log, yl } = require('../helpers/log') +const { getDeployer, readStateAppAddress } = require('./helpers') +const { + readNetworkState, + assertRequiredNetworkState, + persistNetworkState2, +} = require('../helpers/persisted-network-state') + +const { hash: namehash } = require('eth-ens-namehash') + +const APP_TRG = process.env.APP_TRG || 'simple-dvt' +const DEPLOYER = process.env.DEPLOYER || '' + +const REQUIRED_NET_STATE = ['lidoApmAddress', 'lidoApmEnsName', 'daoAddress'] + +async function deployEmptyProxy({ web3, artifacts, trgAppName = APP_TRG }) { + const netId = await web3.eth.net.getId() + + log.splitter() + log(`Network ID: ${chalk.yellow(netId)}`) + + const deployer = await getDeployer(web3, DEPLOYER) + const state = readNetworkState(network.name, netId) + assertRequiredNetworkState(state, REQUIRED_NET_STATE) + + const trgAppFullName = `${trgAppName}.${state.lidoApmEnsName}` + const trgAppId = namehash(trgAppFullName) + + log.splitter() + log(`DAO:`, yl(state.daoAddress)) + log(`Target App:`, yl(trgAppName)) + log(`Target App ENS:`, yl(trgAppFullName)) + log(`Target App ID:`, yl(trgAppId)) + log.splitter() + + let trgProxyAddress + + if (state[`app:${trgAppName}`]) { + trgProxyAddress = readStateAppAddress(state, `app:${trgAppName}`, yl(trgProxyAddress)) + } + + if (trgProxyAddress && (await web3.eth.getCode(trgProxyAddress)) !== '0x') { + log.error(`Target app proxy is already deployed at`) + return + } + + const kernel = await artifacts.require('Kernel').at(state.daoAddress) + const tx = await log.tx( + `Deploying proxy for ${trgAppName}`, + kernel.newAppProxy(kernel.address, trgAppId, { from: deployer }) + ) + // Find the deployed proxy address in the tx logs. + const e = tx.logs.find((l) => l.event === 'NewAppProxy') + trgProxyAddress = e.args.proxy + + // upd deployed state + persistNetworkState2(network.name, netId, state, { + [`app:${trgAppName}`]: { + proxyAddress: trgProxyAddress, + }, + }) + + log(`Target app proxy deployed at`, yl(trgProxyAddress)) + log.splitter() +} + +module.exports = runOrWrapScript(deployEmptyProxy, module) diff --git a/scripts/cloneapp/02-clone-nor.js b/scripts/cloneapp/02-clone-nor.js new file mode 100644 index 000000000..c3cc94015 --- /dev/null +++ b/scripts/cloneapp/02-clone-nor.js @@ -0,0 +1,277 @@ +const { network, ethers } = require('hardhat') +const chalk = require('chalk') + +const { encodeCallScript } = require('@aragon/contract-helpers-test/src/aragon-os') +const { getEventArgument } = require('@aragon/contract-helpers-test') + +const runOrWrapScript = require('../helpers/run-or-wrap-script') + +const { log, yl, gr, rd } = require('../helpers/log') +const { saveCallTxData } = require('../helpers/tx-data') +const { getDeployer, readStateAppAddress } = require('./helpers') +const { resolveLatestVersion } = require('../components/apm') +const { + readNetworkState, + assertRequiredNetworkState, + persistNetworkState2, +} = require('../helpers/persisted-network-state') + +const { resolveEnsAddress } = require('../components/ens') +const { hash: namehash } = require('eth-ens-namehash') + +const { APP_NAMES, APP_ARTIFACTS } = require('../constants') + +const APP_TRG = process.env.APP_TRG || 'simple-dvt' +const DEPLOYER = process.env.DEPLOYER || '' +const SIMULATE = !!process.env.SIMULATE + +const REQUIRED_NET_STATE = [ + 'ensAddress', + 'lidoApmAddress', + 'lidoApmEnsName', + 'daoAddress', + 'lidoLocator', + `app:${APP_NAMES.ARAGON_VOTING}`, + `app:${APP_NAMES.ARAGON_TOKEN_MANAGER}`, +] + +const KERNEL_APP_BASES_NAMESPACE = '0xf1f3eb40f5bc1ad1344716ced8b8a0431d840b5783aea1fd01786bc26f35ac0f' + +async function deployNORClone({ web3, artifacts, trgAppName = APP_TRG }) { + const netId = await web3.eth.net.getId() + + const srcAppName = APP_NAMES.NODE_OPERATORS_REGISTRY + + log.splitter() + log(`Network ID: ${chalk.yellow(netId)}`) + + const deployer = await getDeployer(web3, DEPLOYER) + const state = readNetworkState(network.name, netId) + assertRequiredNetworkState(state, REQUIRED_NET_STATE.concat([`app:${srcAppName}`, `app:${trgAppName}`])) + + log.splitter() + + log(`Using ENS:`, yl(state.ensAddress)) + const ens = await artifacts.require('ENS').at(state.ensAddress) + const lidoLocatorAddress = readStateAppAddress(state, `lidoLocator`) + log(`Lido Locator:`, yl(lidoLocatorAddress)) + log.splitter() + + const srcAppFullName = `${srcAppName}.${state.lidoApmEnsName}` + const srcAppId = namehash(srcAppFullName) + const { semanticVersion, contractAddress, contentURI } = await resolveLatestVersion(srcAppId, ens, artifacts) + const srcVersion = semanticVersion.map((n) => n.toNumber()) + // strip 0x from content uri, then strip 'ipfs:' prefix + const ipfsCid = Buffer.from(contentURI.substring(2), 'hex').toString().substring(5) + + log(`Source App:`, yl(srcAppName)) + log(`Source App ENS:`, yl(srcAppFullName)) + log(`Source App ID:`, yl(srcAppId)) + log(`Source Contract implementation:`, yl(contractAddress)) + log(`Source Content URI:`, yl(contentURI)) + log(`Source Content IPFS CID:`, yl(ipfsCid)) + log(`Source App version:`, yl(srcVersion.join('.'))) + + log.splitter() + const trgAppFullName = `${trgAppName}.${state.lidoApmEnsName}` + const trgAppId = namehash(trgAppFullName) + const trgRepoAddress = await resolveEnsAddress(artifacts, ens, trgAppId) + const trgProxyAddress = readStateAppAddress(state, `app:${trgAppName}`) + const trgAppArtifact = APP_ARTIFACTS[srcAppName] // get source app artifact + + // set new version to 1.0.0 + const trgVersion = [1, 0, 0] + log(`Target App:`, yl(trgAppName)) + log(`Target App ENS:`, yl(trgAppFullName)) + log(`Target App ID:`, yl(trgAppId)) + log(`Target App proxy`, yl(trgProxyAddress)) + log(`Target Contract implementation:`, yl(contractAddress)) + log(`Target Content URI:`, yl(contentURI)) + log(`Target App version:`, yl(trgVersion.join('.'))) + + log.splitter() + const { + moduleName, + moduleType = 'curated', + targetShare = 1000, + moduleFee = 500, + treasuryFee = 500, + penaltyDelay, + } = state[`app:${trgAppName}`].stakingRouterModuleParams + log(`Target SR Module name`, yl(moduleName)) + log(`Target SR Module type`, yl(moduleType)) + log(`Target SR Module fee`, yl(moduleFee)) + log(`Target SR Module targetShare`, yl(targetShare)) + log(`Target SR Module treasuryFee`, yl(treasuryFee)) + log(`Target SR Module penaltyDelay`, yl(penaltyDelay)) + + if (!trgProxyAddress || (await web3.eth.getCode(trgProxyAddress)) === '0x') { + log.error(`Target app proxy is not yet deployed!`) + return + } + + if (trgRepoAddress && (await web3.eth.getCode(trgProxyAddress)) !== '0x') { + log(`Target App APM repo:`, yl(trgRepoAddress)) + log.error(`Target app is already deployed!`) + return + } + + // clone source app info + persistNetworkState2(network.name, netId, state, { + [`app:${trgAppName}`]: { + fullName: trgAppFullName, + name: trgAppName, + id: trgAppId, + ipfsCid, + contentURI, + implementation: contractAddress, + contract: trgAppArtifact, + }, + }) + + // preload voting and stakingRouter addresses + const votingAddress = readStateAppAddress(state, `app:${APP_NAMES.ARAGON_VOTING}`) + const tokenManagerAddress = readStateAppAddress(state, `app:${APP_NAMES.ARAGON_TOKEN_MANAGER}`) + const srAddress = readStateAppAddress(state, 'stakingRouter') + + const kernel = await artifacts.require('Kernel').at(state.daoAddress) + const aclAddress = await kernel.acl() + const acl = await artifacts.require('ACL').at(aclAddress) + const stakingRouter = await artifacts.require('StakingRouter').at(srAddress) + const apmRegistry = await artifacts.require('APMRegistry').at(state.lidoApmAddress) + + const trgApp = await artifacts.require(trgAppArtifact).at(trgProxyAddress) + const voteDesc = `Clone app '${srcAppName}' to '${trgAppName}'` + const voting = await artifacts.require('Voting').at(votingAddress) + const tokenManager = await artifacts.require('TokenManager').at(tokenManagerAddress) + const agentAddress = readStateAppAddress(state, `app:${APP_NAMES.ARAGON_AGENT}`) + const agent = await artifacts.require('Agent').at(agentAddress) + + const evmScriptCalls = [ + // create app repo + { + to: apmRegistry.address, + calldata: await apmRegistry.contract.methods + .newRepoWithVersion(trgAppName, votingAddress, trgVersion, contractAddress, contentURI) + .encodeABI(), + }, + // link appId with implementations + { + to: kernel.address, + calldata: await kernel.contract.methods.setApp(KERNEL_APP_BASES_NAMESPACE, trgAppId, contractAddress).encodeABI(), + }, + // initialize module + { + to: trgApp.address, + calldata: await trgApp.contract.methods + .initialize(lidoLocatorAddress, '0x' + Buffer.from(moduleType).toString('hex').padEnd(64, '0'), penaltyDelay) + .encodeABI(), + }, + ] + + // set permissions + const srcAppPerms = [ + { + grantee: votingAddress, // default to voting + roles: { + MANAGE_SIGNING_KEYS: '0x75abc64490e17b40ea1e66691c3eb493647b24430b358bd87ec3e5127f1621ee', + MANAGE_NODE_OPERATOR_ROLE: '0x78523850fdd761612f46e844cf5a16bda6b3151d6ae961fd7e8e7b92bfbca7f8', + SET_NODE_OPERATOR_LIMIT_ROLE: '0x07b39e0faf2521001ae4e58cb9ffd3840a63e205d288dc9c93c3774f0d794754', + }, + }, + { + grantee: srAddress, + roles: { STAKING_ROUTER_ROLE: '0xbb75b874360e0bfd87f964eadd8276d8efb7c942134fc329b513032d0803e0c6' }, + }, + ] + for (const group of srcAppPerms) { + for (const roleId of Object.values(group.roles)) { + evmScriptCalls.push({ + to: acl.address, + calldata: await acl.contract.methods + .createPermission(group.grantee, trgProxyAddress, roleId, votingAddress) + .encodeABI(), + }) + } + } + + // check missed STAKING_MODULE_MANAGE_ROLE role + const STAKING_MODULE_MANAGE_ROLE = '0x3105bcbf19d4417b73ae0e58d508a65ecf75665e46c2622d8521732de6080c48' + if (!(await stakingRouter.hasRole(STAKING_MODULE_MANAGE_ROLE, voting.address))) { + const grantRoleCallData = await stakingRouter.contract.methods + .grantRole(STAKING_MODULE_MANAGE_ROLE, voting.address) + .encodeABI() + evmScriptCalls.push({ + to: agent.address, + calldata: await agent.contract.methods.execute(stakingRouter.address, 0, grantRoleCallData).encodeABI(), + }) + } + + // add to SR + evmScriptCalls.push({ + to: stakingRouter.address, + calldata: await stakingRouter.contract.methods + .addStakingModule( + moduleName, // name + trgProxyAddress, // module address + targetShare, + moduleFee, + treasuryFee + ) + .encodeABI(), + }) + + const newVoteEvmScript = encodeCallScript([ + { + to: voting.address, + calldata: await voting.contract.methods + .newVote(encodeCallScript(evmScriptCalls), voteDesc, false, false) + .encodeABI(), + }, + ]) + + // console.log({ newVoteEvmScript }) + + if (SIMULATE) { + log.splitter() + log(rd(`Simulating voting creation and enact!`)) + + // create voting on behalf of dao agent + await ethers.getImpersonatedSigner(agentAddress) + + const result = await tokenManager.forward(newVoteEvmScript, { from: agentAddress, gasPrice: 0 }) + const voteId = getEventArgument(result, 'StartVote', 'voteId', { decodeForAbi: voting.abi }) + log(`Vote Id`, yl(voteId)) + + // vote + await voting.vote(voteId, true, true, { from: agentAddress, gasPrice: 0 }) + const voteTime = (await voting.voteTime()).toNumber() + // pass time and enact + await ethers.provider.send('evm_increaseTime', [voteTime]) + await ethers.provider.send('evm_mine') + await voting.executeVote(voteId, { from: deployer, gasPrice: 0 }) + + log(`Target App initialized`, yl(await trgApp.hasInitialized())) + } else { + await saveCallTxData( + `Voting: Clone app '${srcAppName}' to '${trgAppName}'`, + tokenManager, + 'forward', + `clone-tx-02-create-voting.json`, + { + arguments: [newVoteEvmScript], + from: deployer, + } + ) + // console.log({ txData }) + + log.splitter() + log(gr(`Before continuing the cloning, please send voting creation transactions`)) + log(gr(`that you can find in the file listed above. You may use a multisig address`)) + log(gr(`if it supports sending arbitrary tx.`)) + } + + log.splitter() +} + +module.exports = runOrWrapScript(deployNORClone, module) diff --git a/scripts/cloneapp/helpers.js b/scripts/cloneapp/helpers.js new file mode 100644 index 000000000..ae035ed78 --- /dev/null +++ b/scripts/cloneapp/helpers.js @@ -0,0 +1,18 @@ +async function getDeployer(web3, defaultDeployer) { + if (!defaultDeployer) { + const [firstAccount] = await web3.eth.getAccounts() + return firstAccount + } + return defaultDeployer +} + +function readStateAppAddress(state, app = '') { + const appState = state[app] + // goerli/mainnet deployed.json formats compatibility + return appState.proxyAddress || (appState.proxy && appState.proxy.address) || appState.address +} + +module.exports = { + readStateAppAddress, + getDeployer, +} From 01a63f25bfec94f916eae784595741af7ab7b5d1 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Thu, 7 Sep 2023 04:13:25 +0200 Subject: [PATCH 025/218] fix: config block gas limit --- hardhat.config.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hardhat.config.js b/hardhat.config.js index 515ef63be..f48865d00 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -48,13 +48,13 @@ const getNetConfig = (networkName, ethAccountName) => { ...base, url: 'http://localhost:8545', chainId: 31337, - gas: 80000000, // the same as in Görli + gas: 100000000, // the same as in Görli } const mainnetfork = { ...base, url: 'http://127.0.0.1:8545', chainId: 1337, - gas: 80000000, // the same as in Görli + gas: 100000000, // the same as in Görli } const byNetName = { localhost, @@ -69,7 +69,7 @@ const getNetConfig = (networkName, ethAccountName) => { chainId: 1337, }, hardhat: { - blockGasLimit: 30000000, + blockGasLimit: 100000000, gasPrice: 0, initialBaseFeePerGas: 0, allowUnlimitedContractSize: true, From e156f088b383b25ad5ccb8a51f66a1cc1873af48 Mon Sep 17 00:00:00 2001 From: Artyom Veremeenko Date: Mon, 11 Sep 2023 13:02:12 +0300 Subject: [PATCH 026/218] feat(scratch deploy): mvp of local scratch deployment --- SCRATCH_DEPLOY.md | 87 +++-------- contracts/0.4.24/template/LidoTemplate.sol | 91 +++++++----- dao-deploy.sh | 81 ++++------ dao-local-deploy.sh | 139 +++--------------- dao-mainnetfork-deploy.sh | 12 -- ...lts.json => deployed-testnet-defaults.json | 6 +- hardhat.config.js | 53 ++----- package.json | 3 +- scripts/hardhat-tasks.js | 2 +- scripts/helpers/deploy.js | 37 +++-- scripts/helpers/persisted-network-state.js | 3 - .../00-populate-deploy-artifact-from-env.js | 24 +++ .../01-deploy-lido-template-and-bases.js | 6 - scripts/scratch/03-register-ens-domain.js | 27 +--- scripts/scratch/05-deploy-apm.js | 11 +- scripts/scratch/07-create-app-repos.js | 56 ++++--- scripts/scratch/08-deploy-dao.js | 22 ++- scripts/scratch/10-issue-tokens.js | 11 +- scripts/scratch/11-finalize-dao.js | 15 +- .../14-initialize-non-aragon-contracts.js | 6 - .../scratch/custom-deploy-aragon-std-apps.js | 102 +++++++++++++ 21 files changed, 356 insertions(+), 438 deletions(-) delete mode 100755 dao-mainnetfork-deploy.sh rename deployed-mainnetfork-defaults.json => deployed-testnet-defaults.json (94%) create mode 100644 scripts/scratch/00-populate-deploy-artifact-from-env.js create mode 100644 scripts/scratch/custom-deploy-aragon-std-apps.js diff --git a/SCRATCH_DEPLOY.md b/SCRATCH_DEPLOY.md index 1b190ce93..6fd055cd7 100644 --- a/SCRATCH_DEPLOY.md +++ b/SCRATCH_DEPLOY.md @@ -1,84 +1,35 @@ # Deploy Lido protocol from scratch -**NB**: at the moment the deployment from scratch scripts and manual target Lido V1 version (before Lido V2 upgrade) and is not working - -Video guide: [youtube](https://www.youtube.com/watch?v=dCMXcfglJv0) - ## Requirements -* shell - bash or zsh -* docker -* node.js v14 +* node.js v16 * yarn -## Environment - -You will need at least: - -* Ethereum node -* IPFS node -* Aragon web client - -In case of local deploy this environment is set up with docker. - -> Note: Lido protocol is based on Aragon framework, so the entire Aragon framework environment is required for deployment. - -## DAO configuration - -Dao config is stored in `deployed-{NETWORK_NAME}.json` file, where `{NETWORK_NAME}` is network name of your choice. See the [`deployed-local-defaults.json`](deployed-local-defaults.json) for basic parameters. Please refer to [`deployed-mainnet.json`](deployed-mainnet.json) for currently deployed Mainnet version of DAO. +## Local deployment -Copy `deployed-local-defaults.json` to `deployed-{NETWORK_NAME}.json` (e.g. `deployed-kintsugi.json`) and update it accordingly . +Deploys the DAO to local (http://127.0.0.1:8545) dev node (anvil, hardhat, ganache). +The deployment is done from default test account `0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266`. +The node must be configured with the default test accounts derived from mnemonic `test test test test test test test test test test test junk`. -## Network configuration +1. Run `yarn install` (get sure repo dependencies are installed) +2. Run the node on default port 8545 (for the commands see subsections below) +3. Set test account private key `0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80` to `accounts.json` under `/eth/local` like `"local": [""]` +4. Run the deploy script `bash dao-local-deploy.sh` from root repo directory +5. Check out the deploy artifacts in `deployed-local.json` -Add to [`hardhat.config.js`](hardhat.config.js) your network connection parameter (inside the `getNetConfig` function, use `mainnet` or `local` as reference). +### Anvil -## Deploy process +Run the node with command: -> Note: all deploy process is depend of ENS contract. If the target network has one, you can use it. In this case, write it directly to the `deployed-{NETWORK_NAME}.json` file. Otherwise, own ENS contract will be deployed. - -> Note: ETH2 Deposit contract is required. If the target network has one, you must use it. In this case, write it directly to the `deployed-{NETWORK_NAME}.json` file. Otherwise, own Deposit contract will be deployed. - -Steps for deploy: - -* [ ] run environment docker containers -* [ ] set up network config -* [ ] prepare DAO config file -* [ ] deploy Aragon framework environment (including ENS) -* [ ] build and deploy standard Aragon apps (contracts and frontend files) -* [ ] deploy Deposit contract (if necessary) -* [ ] deploy Lido DAO template contract -* [ ] deploy Lido Apps contract implementations -* [ ] register Lido APM name in ENS -* [ ] build Lido Apps frontend files and upload it to IPFS -* [ ] deploy Lido APM contract (via Lido Template) -* [ ] deploy Lido Apps repo contracts (via Lido Template) -* [ ] deploy Lido DAO contract (via Lido Template) -* [ ] issue DAO tokens (via Lido Template) -* [ ] deploy LidoExecutionLayerRewardsVault -* [ ] finalize DAO setup (via Lido Template) -* [ ] deploy CompositePostRebaseBeaconReceiver -* [ ] deploy Burner -* [ ] make final deployed DAO check via script -* [ ] open and check Lido DAO web interface (via Aragon client) - -All steps are automated via shell script [`dao-local-deploy.sh`](dao-local-deploy.sh) for local deploy process. The script be modified for any other network: - -So, one-click local deploy from scratch command is: - -```bash -./dao-local-deploy.sh +```shell +anvil -p 8545 --auto-impersonate --gas-price 0 --base-fee 0 --chain-id 1337 --mnemonic "test test test test test test test test test test test junk" ``` -> Note: some steps require manually updating some transaction hashes in the `deployed-{NETWORK_NAME}.json` file. The script will pause the process in this case, please follow the script tips. +### Hardhat node -## Aragon dependency issue +> NB: Hardhat node is configured in `hardhat.config.js` under `hardhat: { `. -`ipfs-http-client` version has been strictly pinned to `43.0.0` in [this commit](https://github.com/lidofinance/lido-dao/commit/38bf0232fbc59ec6d69d27e170e3e75cfbe1ba11) because `/scripts/multisig/04-publish-app-frontends.js` used to crash at -```javascript -const rootCid = await uploadDirToIpfs({ dirPath: distPath, ipfsApiUrl: ipfsAPI }) +To run hardhat node execute: +```shell +yarn hardhat node ``` - -It appeared that `@aragon/buidler-aragon@npm:^0.2.9` uses `ipfs-http-client`. - -`ipfs-http-client` has a brittle API. Neither `41.0.0` nor `50.0.0` versions of it will work with `@aragon/buidler-aragon@npm:^0.2.9`. diff --git a/contracts/0.4.24/template/LidoTemplate.sol b/contracts/0.4.24/template/LidoTemplate.sol index 44c28bcd1..be7d38e69 100644 --- a/contracts/0.4.24/template/LidoTemplate.sol +++ b/contracts/0.4.24/template/LidoTemplate.sol @@ -208,6 +208,54 @@ contract LidoTemplate is IsContract { ens.setOwner(node, _to); } + function createStdAragonRepos( + address _agentImpl, + address _financeImpl, + address _tokenManagerImpl, + address _votingImpl + ) external onlyOwner { + // uint16[3] memory initialSemanticVersion = [1, 0, 0]; + + uint16[3] memory initialSemanticVersion = [uint16(1), uint16(0), uint16(0)]; + + bytes memory dummyContentURI = new bytes(0); + // new bytes(0x697066733a516d516b4a4d7476753474794a76577250584a666a4c667954576e393539696179794e6a703759714e7a58377053); + + APMRegistry lidoRegistry = deployState.lidoRegistry; + + apmRepos.aragonAgent = lidoRegistry.newRepoWithVersion( + ARAGON_AGENT_APP_NAME, + this, + initialSemanticVersion, + _agentImpl, + dummyContentURI + ); + + apmRepos.aragonFinance = lidoRegistry.newRepoWithVersion( + ARAGON_FINANCE_APP_NAME, + this, + initialSemanticVersion, + _financeImpl, + dummyContentURI + ); + + apmRepos.aragonTokenManager = lidoRegistry.newRepoWithVersion( + ARAGON_TOKEN_MANAGER_APP_NAME, + this, + initialSemanticVersion, + _tokenManagerImpl, + dummyContentURI + ); + + apmRepos.aragonVoting = lidoRegistry.newRepoWithVersion( + ARAGON_VOTING_APP_NAME, + this, + initialSemanticVersion, + _votingImpl, + dummyContentURI + ); + } + function createRepos( uint16[3] _initialSemanticVersion, address _lidoImplAddress, @@ -216,6 +264,7 @@ contract LidoTemplate is IsContract { bytes _nodeOperatorsRegistryContentURI, address _oracleImplAddress, bytes _oracleContentURI + ) external onlyOwner { require(deployState.lidoRegistry != address(0), ERROR_REGISTRY_NOT_DEPLOYED); @@ -247,44 +296,6 @@ contract LidoTemplate is IsContract { _oracleContentURI ); - // create Aragon app repos pointing to latest upstream versions - - AppVersion memory latest = _apmResolveLatest(ARAGON_AGENT_APP_ID); - apmRepos.aragonAgent = lidoRegistry.newRepoWithVersion( - ARAGON_AGENT_APP_NAME, - this, - _initialSemanticVersion, - latest.contractAddress, - latest.contentURI - ); - - latest = _apmResolveLatest(ARAGON_FINANCE_APP_ID); - apmRepos.aragonFinance = lidoRegistry.newRepoWithVersion( - ARAGON_FINANCE_APP_NAME, - this, - _initialSemanticVersion, - latest.contractAddress, - latest.contentURI - ); - - latest = _apmResolveLatest(ARAGON_TOKEN_MANAGER_APP_ID); - apmRepos.aragonTokenManager = lidoRegistry.newRepoWithVersion( - ARAGON_TOKEN_MANAGER_APP_NAME, - this, - _initialSemanticVersion, - latest.contractAddress, - latest.contentURI - ); - - latest = _apmResolveLatest(ARAGON_VOTING_APP_ID); - apmRepos.aragonVoting = lidoRegistry.newRepoWithVersion( - ARAGON_VOTING_APP_NAME, - this, - _initialSemanticVersion, - latest.contractAddress, - latest.contentURI - ); - emit TmplReposCreated(); } @@ -736,7 +747,9 @@ contract LidoTemplate is IsContract { } function _resolveRepo(bytes32 _appId) private view returns (Repo) { - return Repo(PublicResolver(ens.resolver(_appId)).addr(_appId)); + address resolverAddress = ens.resolver(_appId); + require(resolverAddress != address(0x0), "ZERO_RESOLVER_ADDRESS"); + return Repo(PublicResolver(resolverAddress).addr(_appId)); } /** diff --git a/dao-deploy.sh b/dao-deploy.sh index 8860e69b1..b906b88d0 100755 --- a/dao-deploy.sh +++ b/dao-deploy.sh @@ -25,90 +25,61 @@ function msg() { fi } + # yarn install --immutable yarn compile -rm -f deployed-$NETWORK.json -cp deployed-$NETWORK-defaults.json deployed-$NETWORK.json +rm -f ${NETWORK_STATE_FILE} +cp ${NETWORK_STATE_DEFAULTS_FILE} ${NETWORK_STATE_FILE} + + +# Fill in deployer, chainId, etc from env to the deploy artifact +yarn hardhat --network $NETWORK run ./scripts/scratch/00-populate-deploy-artifact-from-env.js --no-compile # It does not deploy DepositContract if it is specified in deployed-${NETWORK}-defaults.json -yarn hardhat --network $NETWORK run --no-compile ./scripts/scratch/deploy-beacon-deposit-contract.js +yarn hardhat --network $NETWORK run ./scripts/scratch/deploy-beacon-deposit-contract.js --no-compile msg "Deposit contract deployed or is specified." -yarn deploy:$NETWORK:aragon-env +yarn deploy:aragon-env msg "Aragon ENV deployed." -# NB! -# Need this renaming because during publishing of aragon apps and deploying their frontends -# via it's internal scripts all contracts get parsed. If contracts has custom errors or multiple -# verions declaration the process fails. - -MULTI_VERSION_PRAGMA="pragma solidity >=0.4.24 <0.9.0;" -SINGLE_VERSION_PRAGMA="pragma solidity 0.4.24;" - -for ff in $(find contracts/0.8.9 -iname '*.sol'); do mv "$ff" "$ff.tmp" ; done -for ff in $(grep -l -R "${MULTI_VERSION_PRAGMA}" contracts/common); do - sed -i '' "s/${MULTI_VERSION_PRAGMA}/${SINGLE_VERSION_PRAGMA}/g" "$ff" ; done - -mv contracts/0.4.24/template/LidoTemplate.sol contracts/0.4.24/template/LidoTemplate.sol.bkp -yarn deploy:$NETWORK:aragon-std-apps +yarn deploy:aragon-std-apps-custom msg "Aragon STD apps deployed." -mv contracts/0.4.24/template/LidoTemplate.sol.bkp contracts/0.4.24/template/LidoTemplate.sol - -yarn hardhat --network $NETWORK run ./scripts/scratch/01-deploy-lido-template-and-bases.js -yarn hardhat --network $NETWORK run ./scripts/scratch/02-obtain-deployed-instances.js +yarn hardhat --network $NETWORK run ./scripts/scratch/01-deploy-lido-template-and-bases.js --no-compile +yarn hardhat --network $NETWORK run ./scripts/scratch/02-obtain-deployed-instances.js --no-compile msg "Apps instances deployed" -yarn hardhat --network $NETWORK run ./scripts/scratch/03-register-ens-domain.js -if [ -f "tx-02-1-commit-ens-registration.json" ]; then - yarn hardhat --network $NETWORK tx --from $DEPLOYER --file tx-02-1-commit-ens-registration.json -fi -yarn hardhat --network $NETWORK tx --from $DEPLOYER --file tx-02-2-make-ens-registration.json +yarn hardhat --network $NETWORK run ./scripts/scratch/03-register-ens-domain.js --no-compile msg "ENS registered" -yarn hardhat --network $NETWORK run ./scripts/scratch/04-publish-app-frontends.js -msg "Frontend published to IPFS" - -# Okay, now we can restore the contracts -for ff in $(find contracts/0.8.9 -iname '*.sol.tmp'); do mv "$ff" "${ff%.*}" ; done -for ff in $(grep -l -R "${SINGLE_VERSION_PRAGMA}" contracts/common); do - sed -i '' "s/${SINGLE_VERSION_PRAGMA}/${MULTI_VERSION_PRAGMA}/g" "$ff" ; done - -yarn hardhat --network $NETWORK run ./scripts/scratch/05-deploy-apm.js -yarn hardhat --network $NETWORK tx --from $DEPLOYER --file tx-03-deploy-apm.json -yarn hardhat --network $NETWORK run ./scripts/scratch/06-obtain-deployed-apm.js +yarn hardhat --network $NETWORK run ./scripts/scratch/05-deploy-apm.js --no-compile +yarn hardhat --network $NETWORK run ./scripts/scratch/06-obtain-deployed-apm.js --no-compile msg "APM deployed" - -yarn hardhat --network $NETWORK run ./scripts/scratch/07-create-app-repos.js -yarn hardhat --network $NETWORK tx --from $DEPLOYER --file tx-07-create-app-repos.json +yarn hardhat --network $NETWORK run ./scripts/scratch/07-create-app-repos.js --no-compile msg "App repos created" -yarn hardhat --network $NETWORK run ./scripts/scratch/08-deploy-dao.js -yarn hardhat --network $NETWORK tx --from $DEPLOYER --file tx-05-deploy-dao.json +yarn hardhat --network $NETWORK run ./scripts/scratch/08-deploy-dao.js --no-compile -yarn hardhat --network $NETWORK run ./scripts/scratch/09-obtain-deployed-dao.js +yarn hardhat --network $NETWORK run ./scripts/scratch/09-obtain-deployed-dao.js --no-compile msg "DAO deploy started" - # Do it at the end, because might need the contracts initialized -yarn hardhat --network $NETWORK run ./scripts/scratch/10-issue-tokens.js -yarn hardhat --network $NETWORK tx --from $DEPLOYER --file tx-06-1-issue-tokens.json +yarn hardhat --network $NETWORK run ./scripts/scratch/10-issue-tokens.js --no-compile msg "Tokens issued" - # Deploy the contracts before finalizing DAO, because the template might set permissions on some of them -yarn hardhat --network $NETWORK run ./scripts/scratch/13-deploy-non-aragon-contracts.js +yarn hardhat --network $NETWORK run ./scripts/scratch/13-deploy-non-aragon-contracts.js --no-compile +msg "Non-aragon contracts deployed" -yarn hardhat --network $NETWORK run ./scripts/scratch/11-finalize-dao.js -yarn hardhat --network $NETWORK tx --from $DEPLOYER --file tx-11-finalize-dao.json +yarn hardhat --network $NETWORK run ./scripts/scratch/11-finalize-dao.js --no-compile msg "DAO deploy finalized" -rm ./tx-*.json - -yarn hardhat --network $NETWORK run ./scripts/scratch/14-initialize-non-aragon-contracts.js +yarn hardhat --network $NETWORK run ./scripts/scratch/14-initialize-non-aragon-contracts.js --no-compile +msg "Non-aragon contracts initialized" -yarn hardhat --network $NETWORK run ./scripts/scratch/15-grant-roles.js +yarn hardhat --network $NETWORK run ./scripts/scratch/15-grant-roles.js --no-compile +msg "Roles granted" # TODO: save commit of the latest deploy diff --git a/dao-local-deploy.sh b/dao-local-deploy.sh index 284fb4fb2..698e9b26e 100755 --- a/dao-local-deploy.sh +++ b/dao-local-deploy.sh @@ -2,123 +2,22 @@ set -e +u set -o pipefail -# first local account by default -DEPLOYER=${DEPLOYER:=0xb4124cEB3451635DAcedd11767f004d8a28c6eE7} -NETWORK=${NETWORK:=local} -ARAGON_APPS_REPO_REF=import-shared-minime - -echo "DEPLOYER is $DEPLOYER" -echo "NETWORK is $NETWORK" - -function msg() { - MSG=$1 - if [ ! -z "$MSG" ]; then - echo ">>> =============================" - echo ">>> $MSG" - echo ">>> =============================" - fi -} - -function pause() { - MSG=$1 - msg "$1" - read -s -n 1 -p "Press any key to continue . . ." - echo "" -} - -docker-compose down -v -docker-compose up --build -d - -rm -f deployed-$NETWORK.json -cp deployed-$NETWORK-defaults.json deployed-$NETWORK.json - -yarn install --immutable -yarn compile - -yarn deploy:$NETWORK:aragon-env -msg "Aragon ENV deployed." -yarn deploy:$NETWORK:aragon-std-apps -msg "Aragon STD apps deployed." - -yarn hardhat --network $NETWORK run --no-compile ./scripts/deploy-beacon-deposit-contract.js -msg "Deposit contract deployed." - -yarn hardhat --network $NETWORK run ./scripts/multisig/01-deploy-lido-template-and-bases.js -yarn hardhat --network $NETWORK tx --from $DEPLOYER --file tx-01-1-deploy-template.json -pause "!!! Now set the daoTemplateDeployTx hash value in deployed-$NETWORK.json" -yarn hardhat --network $NETWORK tx --from $DEPLOYER --file tx-01-2-deploy-lido-base.json -pause "!!! Now set the lidoBaseDeployTx hash value in deployed-$NETWORK.json" -yarn hardhat --network $NETWORK tx --from $DEPLOYER --file tx-01-3-deploy-legacy-oracle-base.json -pause "!!! Now set the oracleBaseDeployTx hash value in deployed-$NETWORK.json" -yarn hardhat --network $NETWORK tx --from $DEPLOYER --file tx-01-4-deploy-nops-base.json -pause "!!! Now set the nodeOperatorsRegistryBaseDeployTx hash value in deployed-$NETWORK.json" -yarn hardhat --network $NETWORK run ./scripts/multisig/02-obtain-deployed-instances.js -msg "Apps instances deployed" - -yarn hardhat --network $NETWORK run ./scripts/multisig/03-register-ens-domain.js -if [ -f "tx-02-1-commit-ens-registration.json" ]; then - yarn hardhat --network $NETWORK tx --from $DEPLOYER --file tx-02-1-commit-ens-registration.json -fi -yarn hardhat --network $NETWORK tx --from $DEPLOYER --file tx-02-2-make-ens-registration.json -msg "ENS registered" - -yarn hardhat --network $NETWORK run ./scripts/multisig/04-publish-app-frontends.js -msg "Frontend published to IPFS" - -yarn hardhat --network $NETWORK run ./scripts/multisig/05-deploy-apm.js -yarn hardhat --network $NETWORK tx --from $DEPLOYER --file tx-03-deploy-apm.json -yarn hardhat --network $NETWORK run ./scripts/multisig/06-obtain-deployed-apm.js -msg "APM deployed" - -yarn hardhat --network $NETWORK run ./scripts/multisig/07-create-app-repos.js -yarn hardhat --network $NETWORK tx --from $DEPLOYER --file tx-07-create-app-repos.json -msg "App repos created" - -yarn hardhat --network $NETWORK run ./scripts/multisig/08-deploy-dao.js -yarn hardhat --network $NETWORK tx --from $DEPLOYER --file tx-05-deploy-dao.json -yarn hardhat --network $NETWORK run ./scripts/multisig/09-obtain-deployed-dao.js -msg "DAO deploy started" - -yarn hardhat --network $NETWORK run ./scripts/multisig/10-issue-tokens.js -yarn hardhat --network $NETWORK tx --from $DEPLOYER --file tx-06-1-issue-tokens.json -msg "Tokens issued" - -# Execution Layer Rewards: deploy the vault -yarn hardhat --network $NETWORK run ./scripts/multisig/26-deploy-execution-layer-rewards-vault.js -yarn hardhat --network $NETWORK tx --from $DEPLOYER --file tx-26-deploy-execution-layer-rewards-vault.json -pause "!!! Now set the executionLayerRewardsVaultDeployTx hash value in deployed-$NETWORK.json" -yarn hardhat --network $NETWORK run ./scripts/multisig/27-obtain-deployed-execution-layer-rewards-vault.js -msg "ExecutionLayerRewardsVault deployed" - -yarn hardhat --network $NETWORK run ./scripts/multisig/11-finalize-dao.js -yarn hardhat --network $NETWORK tx --from $DEPLOYER --file tx-11-finalize-dao.json -msg "DAO deploy finalized" - -# Insurance: deploy CompositePostRebaseBeaconReceiver -yarn hardhat --network $NETWORK run ./scripts/multisig/21-deploy-composite-post-rebase-beacon-receiver.js -yarn hardhat --network $NETWORK tx --from $DEPLOYER --file tx-21-deploy-composite-post-rebase-beacon-receiver.json -pause "!!! Now set the compositePostRebaseBeaconReceiverDeployTx hash value in deployed-$NETWORK.json" -yarn hardhat --network $NETWORK run ./scripts/multisig/22-obtain-composite-post-rebase-beacon-receiver.js -msg "CompositePostRebaseBeaconReceiver deployed" - -# Insurance: deploy Burner -yarn hardhat --network $NETWORK run ./scripts/multisig/23-deploy-burner.js -yarn hardhat --network $NETWORK tx --from $DEPLOYER --file tx-23-deploy-burner.json -pause "!!! Now set the burnerDeployTx hash value in deployed-$NETWORK.json" -yarn hardhat --network $NETWORK run ./scripts/multisig/24-obtain-burner.js -msg "Burner deployed" - -# Insurance: attach the contracts to the protocol -yarn hardhat --network $NETWORK run ./scripts/multisig/25-vote-burner.js -yarn hardhat --network $NETWORK tx --from $DEPLOYER --file tx-25-vote-burner.json -yarn hardhat --network $NETWORK run ./scripts/multisig/vote-and-enact.js -msg "Vote for attaching the insurance module is executed" - -# MAYBE TODO: Create and auto execute vote to increase vote time (like 10+5 minute) - -# Check the deployed protocol -yarn hardhat --network $NETWORK run ./scripts/multisig/12-check-dao.js -msg "Check completed! Clening up..." - -rm tx-*.json -msg "Deploy completed!" +# +export NETWORK=local +export CHAIN_ID=1337 +export RPC_URL="http://127.0.0.1:8545" +# +export DEPLOYER=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 +export GAS_PRIORITY_FEE=1 +export GAS_MAX_FEE=100 +# +export NO_ARAGON_UI=1 +# +export NETWORK_STATE_FILE="deployed-${NETWORK}.json" +export NETWORK_STATE_DEFAULTS_FILE="deployed-testnet-defaults.json" +# TODO export SCRATCH_DEPLOY_DEPOSIT_CONTRACT=1 + +# Set the variable to skip long Aragon apps frontend rebuild step on repetetive deploys +# export SKIP_APPS_LONG_BUILD_STEPS=1 + +bash dao-deploy.sh diff --git a/dao-mainnetfork-deploy.sh b/dao-mainnetfork-deploy.sh deleted file mode 100755 index ebdbaa1ba..000000000 --- a/dao-mainnetfork-deploy.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -set -e +u -set -o pipefail - -export DEPLOYER=0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1 - -export NETWORK=mainnetfork - -# Set the variable to skip long Aragon apps frontend rebuild step on repetetive deploys -# export SKIP_APPS_LONG_BUILD_STEPS=1 - -bash dao-deploy.sh diff --git a/deployed-mainnetfork-defaults.json b/deployed-testnet-defaults.json similarity index 94% rename from deployed-mainnetfork-defaults.json rename to deployed-testnet-defaults.json index c1ed84f4a..a492a38f0 100644 --- a/deployed-mainnetfork-defaults.json +++ b/deployed-testnet-defaults.json @@ -1,8 +1,7 @@ { - "networkId": 1, "ipfsAPI": "http://127.0.0.1:5001/api/v0", - "multisigAddress": "0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1", - "owner": "0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1", + "multisigAddress": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "gateSealAddress": "0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1", "lidoApmEnsName": "lidopm.eth", "lidoApmEnsRegDurationSec": 94608000, @@ -15,7 +14,6 @@ "objectionPhaseDuration": 1 }, "beaconSpec": { - "depositContractAddress": "0x00000000219ab540356cBB839Cbe05303d7705Fa", "epochsPerFrame": 225, "slotsPerEpoch": 32, "secondsPerSlot": 12, diff --git a/hardhat.config.js b/hardhat.config.js index 515ef63be..f0049bece 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -44,29 +44,20 @@ const getNetConfig = (networkName, ethAccountName) => { ensAddress: netState.ensAddress, timeout: 60000, } - const localhost = { - ...base, - url: 'http://localhost:8545', - chainId: 31337, - gas: 80000000, // the same as in Görli - } - const mainnetfork = { - ...base, - url: 'http://127.0.0.1:8545', - chainId: 1337, - gas: 80000000, // the same as in Görli - } const byNetName = { - localhost, - mainnetfork, - local: { + mainnetfork: { ...base, - accounts: { - mnemonic: 'explain tackle mirror kit van hammer degree position ginger unfair soup bonus', - count: 30, - }, - url: 'http://localhost:8545', - chainId: 1337, + url: process.env.RPC_URL, + chainId: Number(process.env.CHAIN_ID) || 1, + }, + goerlifork: { + ...base, + url: process.env.RPC_URL, + chainId: Number(process.env.CHAIN_ID) || 5, + }, + local: { + url: process.env.RPC_URL, + chainId: Number(process.env.CHAIN_ID) || 1337, }, hardhat: { blockGasLimit: 30000000, @@ -76,21 +67,11 @@ const getNetConfig = (networkName, ethAccountName) => { accounts: { // default hardhat's node mnemonic mnemonic: 'test test test test test test test test test test test junk', - count: 30, + count: 10, accountsBalance: '100000000000000000000000', gasPrice: 0, }, - }, - 'goerli-pyrmont': { - ...base, - url: 'http://206.81.31.11/rpc', - chainId: 5, - }, - rinkeby: { - ...base, - url: 'https://rinkeby.infura.io/v3/' + accounts.infura.projectId, - chainId: 4, - timeout: 60000 * 10, + chainId: Number(process.env.CHAIN_ID) || 1337, }, goerli: { ...base, @@ -98,12 +79,6 @@ const getNetConfig = (networkName, ethAccountName) => { chainId: 5, timeout: 60000 * 10, }, - 'mainnet-test': { - ...base, - url: 'https://mainnet.infura.io/v3/' + accounts.infura.projectId, - chainId: 1, - timeout: 60000 * 10, - }, mainnet: { ...base, url: 'https://mainnet.infura.io/v3/' + accounts.infura.projectId, diff --git a/package.json b/package.json index f2d1ddd71..5aa658dbb 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "deploy": "yarn run deploy:all", "deploy:all": "yarn compile && yarn deploy:aragon-env && yarn deploy:aragon-std-apps && yarn deploy:apm-and-template && yarn deploy:apps && yarn deploy:dao", "deploy:e2e:all": "yarn compile && yarn deploy:e2e:aragon-env && yarn deploy:e2e:aragon-std-apps && yarn deploy:e2e:apm-and-template && yarn deploy:e2e:apps && yarn deploy:e2e:dao", - "deploy:aragon-env": "hardhat run --no-compile ./scripts/scratch/deploy-aragon-env.js", + "deploy:aragon-env": "hardhat --network $NETWORK run --no-compile ./scripts/scratch/deploy-aragon-env.js", "deploy:e2e:aragon-env": "NETWORK_NAME=e2e NETWORK_STATE_FILE=deployed-e2e.json hardhat run --no-compile ./scripts/scratch/deploy-aragon-env.js", "deploy:aragon-std-apps": "RELEASE_TYPE=major hardhat run --no-compile ./scripts/scratch/deploy-aragon-std-apps.js --config ./hardhat.config.aragon-apps.js", "deploy:e2e:aragon-std-apps": "NETWORK_NAME=e2e NETWORK_STATE_FILE=deployed-e2e.json IPFS_API_URL=http://localhost:5001/api/v0 IPFS_GATEWAY_URL=http://localhost:8080 RELEASE_TYPE=major hardhat run --no-compile ./scripts/scratch/deploy-aragon-std-apps.js --config ./hardhat.config.aragon-apps.js", @@ -54,6 +54,7 @@ "deploy:rinkeby:aragon-std-apps": "NETWORK_NAME=rinkeby NETWORK_STATE_FILE=deployed-rinkeby.json IPFS_API_URL=http://127.0.0.1:5001/api/v0 IPFS_GATEWAY_URL=http://127.0.0.1:8080 RELEASE_TYPE=major hardhat run --no-compile ./scripts/scratch/deploy-aragon-std-apps.js --config ./hardhat.config.aragon-apps.js", "deploy:mainnetfork:aragon-env": "NETWORK_NAME=mainnetfork NETWORK_STATE_FILE=deployed-mainnetfork.json hardhat run --no-compile ./scripts/scratch/deploy-aragon-env.js", "deploy:mainnetfork:aragon-std-apps": "NETWORK_NAME=mainnetfork NETWORK_STATE_FILE=deployed-mainnetfork.json IPFS_API_URL=http://127.0.0.1:5001/api/v0 IPFS_GATEWAY_URL=http://127.0.0.1:8080 RELEASE_TYPE=major hardhat run --no-compile ./scripts/scratch/deploy-aragon-std-apps.js --config ./hardhat.config.aragon-apps.js", + "deploy:aragon-std-apps-custom": "hardhat run --no-compile ./scripts/scratch/custom-deploy-aragon-std-apps.js --network $NETWORK --config ./hardhat.config.aragon-apps.js", "deploy:local:apm-and-template": "NETWORK_NAME=local NETWORK_STATE_FILE=deployed-local.json hardhat run --no-compile ./scripts/scratch/deploy-lido-apm-and-template.js", "deploy:local:apps": "NETWORK_NAME=local NETWORK_STATE_FILE=deployed-local.json IPFS_API_URL=http://127.0.0.1:5001/api/v0 IPFS_GATEWAY_URL=http://127.0.0.1:8080o hardhat run --no-compile ./scripts/scratch/deploy-lido-apps.js", "apps:lido": "yarn --cwd ./apps/lido/app/ cli", diff --git a/scripts/hardhat-tasks.js b/scripts/hardhat-tasks.js index 92fee124e..e02d6b584 100644 --- a/scripts/hardhat-tasks.js +++ b/scripts/hardhat-tasks.js @@ -4,7 +4,7 @@ task(`tx`, `Performs a transaction`) .addOptionalParam(`wait`, `The number of seconds to wait before sending the transaction`) .addOptionalParam(`gasPrice`, `Gas price`) .addOptionalParam(`nonce`, `Nonce`) - .setAction(async ({ file, from: fromArg, gasPrice, nonce, wait: waitSec = 5 }) => { + .setAction(async ({ file, from: fromArg, gasPrice, nonce, wait: waitSec = 1 }) => { const netId = await web3.eth.net.getId() console.error('====================') diff --git a/scripts/helpers/deploy.js b/scripts/helpers/deploy.js index d4f37cee9..4ae31afaa 100644 --- a/scripts/helpers/deploy.js +++ b/scripts/helpers/deploy.js @@ -218,6 +218,30 @@ async function deployWithoutProxy(nameInState, artifactName, deployer, construct return contract.address } +async function deployImplementation(nameInState, artifactName, deployer, constructorArgs=[]) { + const netId = await web3.eth.net.getId() + const state = readNetworkState(network.name, netId) + + console.log(`Deploying implementation for proxy of ${artifactName}`) + const contract = await deployContract(artifactName, constructorArgs, deployer) + + const gasUsed = await getDeploymentGasUsed(contract) + TOTAL_GAS_USED += gasUsed + implementation = contract.address + + console.log(`${artifactName} implementation: ${implementation} (gas used ${gasUsed})`) + + persistNetworkState2(network.name, netId, state, { + [nameInState]: { + "implementation": { + contract: artifactName, + address: implementation, + constructorArgs: constructorArgs, + }, + } + }) +} + async function deployBehindOssifiableProxy(nameInState, artifactName, proxyOwner, deployer, constructorArgs=[], implementation=null) { const netId = await web3.eth.net.getId() const state = readNetworkState(network.name, netId) @@ -260,16 +284,9 @@ async function updateProxyImplementation(nameInState, artifactName, proxyAddress const OssifiableProxy = await artifacts.require('OssifiableProxy') const proxy = await OssifiableProxy.at(proxyAddress) - const Contract = await artifacts.require(artifactName) - const implementation = await Contract.new(...constructorArgs, { - from: proxyOwner, - gasPrice: GAS_PRICE, - }) + const implementation = await deployContract(artifactName, constructorArgs, proxyOwner) - await proxy.proxy__upgradeTo(implementation.address, { - from: proxyOwner, - gasPrice: GAS_PRICE, - }) + await proxy.proxy__upgradeTo(implementation.address, { from: proxyOwner }) persistNetworkState2(network.name, netId, state, { [nameInState]: { @@ -294,6 +311,8 @@ module.exports = { withArgs, getDeployTxParams, deployWithoutProxy, + deployContract, + deployImplementation, deployBehindOssifiableProxy, updateProxyImplementation, getTotalGasUsed, diff --git a/scripts/helpers/persisted-network-state.js b/scripts/helpers/persisted-network-state.js index 7299b2730..61f3e5bb1 100644 --- a/scripts/helpers/persisted-network-state.js +++ b/scripts/helpers/persisted-network-state.js @@ -10,9 +10,6 @@ function readNetworkState(netName, netId) { const fileName = _getFileName(netName, NETWORK_STATE_FILE_BASENAME, NETWORK_STATE_FILE_DIR) log(`Reading network state from ${fileName}...`) const state = _readNetworkStateFile(fileName, netId) - if (state.networkId !== netId) { - throw new Error(`network id (${netId}) doesn't match the one in the state file (${state.networkId})`) - } return state } diff --git a/scripts/scratch/00-populate-deploy-artifact-from-env.js b/scripts/scratch/00-populate-deploy-artifact-from-env.js new file mode 100644 index 000000000..dc8d5f5dc --- /dev/null +++ b/scripts/scratch/00-populate-deploy-artifact-from-env.js @@ -0,0 +1,24 @@ +const chalk = require('chalk') + +const runOrWrapScript = require('../helpers/run-or-wrap-script') +const { log, yl, gr } = require('../helpers/log') +const { readNetworkState, assertRequiredNetworkState, persistNetworkState } = require('../helpers/persisted-network-state') + +const DEPLOYER = process.env.DEPLOYER +const CHAIN_ID = process.env.CHAIN_ID + +async function deployTemplate({ web3, artifacts }) { + const netId = await web3.eth.net.getId() + + log.splitter() + log(`Network ID: ${chalk.yellow(netId)}`) + log(`Deployer: ${chalk.yellow(DEPLOYER)}`) + + const state = readNetworkState(network.name, netId) + persistNetworkState(network.name, netId, state, { + chainId: CHAIN_ID, + multisigAddress: DEPLOYER, + }) +} + +module.exports = runOrWrapScript(deployTemplate, module) diff --git a/scripts/scratch/01-deploy-lido-template-and-bases.js b/scripts/scratch/01-deploy-lido-template-and-bases.js index 7a99710ae..064031d80 100644 --- a/scripts/scratch/01-deploy-lido-template-and-bases.js +++ b/scripts/scratch/01-deploy-lido-template-and-bases.js @@ -2,7 +2,6 @@ const chalk = require('chalk') const runOrWrapScript = require('../helpers/run-or-wrap-script') const { log, yl, gr } = require('../helpers/log') -const { saveDeployTx } = require('../helpers/deploy') const { deployWithoutProxy } = require('../helpers/deploy') const { readNetworkState, assertRequiredNetworkState, persistNetworkState } = require('../helpers/persisted-network-state') const { APP_NAMES } = require('../constants') @@ -50,11 +49,6 @@ async function deployTemplate({ web3, artifacts }) { }) log.splitter() - log(gr(`Before continuing the deployment, please send all contract creation transactions`)) - log(gr(`that you can find in the files listed above. You may use a multisig address`)) - log(gr(`if it supports deploying new contract instances.`)) - log.splitter() - } module.exports = runOrWrapScript(deployTemplate, module) diff --git a/scripts/scratch/03-register-ens-domain.js b/scripts/scratch/03-register-ens-domain.js index e4943757e..3bc449814 100644 --- a/scripts/scratch/03-register-ens-domain.js +++ b/scripts/scratch/03-register-ens-domain.js @@ -6,7 +6,6 @@ const keccak256 = require('js-sha3').keccak_256 const runOrWrapScript = require('../helpers/run-or-wrap-script') const { assert } = require('../helpers/assert') const { log, yl, gr } = require('../helpers/log') -const { saveCallTxData } = require('../helpers/tx-data') const { readNetworkState, assertRequiredNetworkState, persistNetworkState } = require('../helpers/persisted-network-state') const TLD = 'eth' @@ -101,43 +100,25 @@ async function deployTemplate({ web3, artifacts }) { log.splitter() - await saveCallTxData(`commit`, controller, 'commit', `tx-02-1-commit-ens-registration.json`, { - arguments: [commitment], - from: state.multisigAddress - }) + await controller.commit(commitment, { from: state.multisigAddress }) - await saveCallTxData(`register`, controller, 'register', `tx-02-2-make-ens-registration.json`, { - arguments: [domainLabel, domainOwner, domainRegDuration, salt], + await controller.register(domainLabel, domainOwner, domainRegDuration, salt, { from: state.multisigAddress, value: '0x' + registerTxValue.toString(16), - estimateGas: false // estimation will fail since no commitment is actually made yet }) log.splitter() - log(gr(`Before continuing the deployment, please send all transactions listed above.\n`)) - log(gr(`Make sure to send the second transaction at least ${yl(minCommitmentAge)} seconds after the`)) - log(gr(`first one is included in a block, but no more than ${yl(maxCommitmentAge)} seconds after that.`)) - log.splitter() } else { log(`ENS domain new owner:`, yl(domainOwner)) - if ((await ens.owner(node)) === state.multisigAddress) { log(`Transferring name ownership from owner ${chalk.yellow(state.multisigAddress)} to template ${chalk.yellow(domainOwner)}`) - await saveCallTxData(`setOwner`, ens, 'setOwner', `tx-02-2-make-ens-registration.json`, { - arguments: [node, domainOwner], - from: state.multisigAddress - }) + await ens.setOwner(node, domainOwner, { from: state.multisigAddress }) } else { log(`Creating the subdomain and assigning it to template ${chalk.yellow(domainOwner)}`) - await saveCallTxData(`setSubnodeOwner`, ens, 'setSubnodeOwner', `tx-02-2-make-ens-registration.json`, { - arguments: [tldNode, labelHash, domainOwner], - from: state.multisigAddress - }) + await ens.setSubnodeOwner(tldNode, labelHash, domainOwner, { from: state.multisigAddress }) } log.splitter() - log(gr(`Before continuing the deployment, please send all transactions listed above.\n`)) - log.splitter() } } diff --git a/scripts/scratch/05-deploy-apm.js b/scripts/scratch/05-deploy-apm.js index 02da019c0..9c5667f6f 100644 --- a/scripts/scratch/05-deploy-apm.js +++ b/scripts/scratch/05-deploy-apm.js @@ -5,7 +5,6 @@ const keccak256 = require('js-sha3').keccak_256 const runOrWrapScript = require('../helpers/run-or-wrap-script') const { log, logSplitter, logWideSplitter } = require('../helpers/log') -const { saveCallTxData } = require('../helpers/tx-data') const { assertNoEvents } = require('../helpers/events') const { readNetworkState, assertRequiredNetworkState, persistNetworkState } = require('../helpers/persisted-network-state') const { getENSNodeOwner } = require('../components/ens') @@ -57,15 +56,15 @@ async function deployAPM({ web3, artifacts }) { logSplitter() + const from = state.multisigAddress + const lidoApmDeployArguments = [parentHash, subHash] - await saveCallTxData(`APM deploy`, template, 'deployLidoAPM', `tx-03-deploy-apm.json`, { - arguments: lidoApmDeployArguments, - from: state.multisigAddress - }) + const receipt = await template.deployLidoAPM(...lidoApmDeployArguments, { from }) + console.log({receipt}) persistNetworkState(network.name, netId, state, { lidoApmDeployArguments, - lidoApmDeployTx: '' + lidoApmDeployTx: receipt.tx, }) } diff --git a/scripts/scratch/07-create-app-repos.js b/scripts/scratch/07-create-app-repos.js index 744d30168..1f3b28eac 100644 --- a/scripts/scratch/07-create-app-repos.js +++ b/scripts/scratch/07-create-app-repos.js @@ -3,18 +3,25 @@ const { assert } = require('chai') const runOrWrapScript = require('../helpers/run-or-wrap-script') const { log, logSplitter, logWideSplitter } = require('../helpers/log') -const { saveCallTxData } = require('../helpers/tx-data') const { assertLastEvent } = require('../helpers/events') const { readNetworkState, assertRequiredNetworkState, persistNetworkState } = require('../helpers/persisted-network-state') const { APP_NAMES } = require('../constants') +const DULL_CONTENT_URI = "0x697066733a516d516b4a4d7476753474794a76577250584a666a4c667954576e393539696179794e6a703759714e7a58377053" + +const NO_ARAGON_UI = process.env.NO_ARAGON_UI + const REQUIRED_NET_STATE = [ 'multisigAddress', 'lidoTemplate', `app:${APP_NAMES.LIDO}`, `app:${APP_NAMES.ORACLE}`, - `app:${APP_NAMES.NODE_OPERATORS_REGISTRY}` + `app:${APP_NAMES.NODE_OPERATORS_REGISTRY}`, + `app:aragon-agent`, + `app:aragon-finance`, + `app:aragon-token-manager`, + `app:aragon-voting`, ] async function createAppRepos({ web3, artifacts }) { @@ -41,21 +48,36 @@ async function createAppRepos({ web3, artifacts }) { const oracleAppState = state[`app:${APP_NAMES.ORACLE}`] const nodeOperatorsAppState = state[`app:${APP_NAMES.NODE_OPERATORS_REGISTRY}`] - await saveCallTxData(`createRepos`, template, 'createRepos', `tx-07-create-app-repos.json`, { - arguments: [ - [1, 0, 0], - // Lido app - lidoAppState.implementation, - lidoAppState.contentURI, - // NodeOperatorsRegistry app - nodeOperatorsAppState.implementation, - nodeOperatorsAppState.contentURI, - // LegacyOracle app - oracleAppState.implementation, - oracleAppState.contentURI, - ], - from: state.multisigAddress - }) + + const createReposArguments = [ + [1, 0, 0], + // Lido app + lidoAppState.implementation, + NO_ARAGON_UI ? DULL_CONTENT_URI : lidoAppState.contentURI, + // NodeOperatorsRegistry app + nodeOperatorsAppState.implementation, + NO_ARAGON_UI ? DULL_CONTENT_URI : nodeOperatorsAppState.contentURI, + // LegacyOracle app + oracleAppState.implementation, + NO_ARAGON_UI ? DULL_CONTENT_URI : oracleAppState.contentURI, + ] + const from = state.multisigAddress + + console.log({arguments, from}) + + const lidoAppsReceipt = await template.createRepos(...createReposArguments, { from }) + console.log(`=== Aragon Lido Apps Repos (Lido, AccountingOracle, NodeOperatorsRegistry deployed: ${lidoAppsReceipt.tx} ===`) + + + const createStdAragonReposArguments = [ + state['app:aragon-agent']["implementation"]["address"], + state['app:aragon-finance']["implementation"]["address"], + state['app:aragon-token-manager']["implementation"]["address"], + state['app:aragon-voting']["implementation"]["address"], + ] + + const aragonStdAppsReceipt = await template.createStdAragonRepos(...createStdAragonReposArguments, { from }) + console.log(`=== Aragon Std Apps Repos (Agent, Finance, TokenManager, Voting deployed: ${aragonStdAppsReceipt.tx} ===`) logSplitter() persistNetworkState(network.name, netId, state) diff --git a/scripts/scratch/08-deploy-dao.js b/scripts/scratch/08-deploy-dao.js index cd24b5f25..270e3f4e4 100644 --- a/scripts/scratch/08-deploy-dao.js +++ b/scripts/scratch/08-deploy-dao.js @@ -8,7 +8,6 @@ const { toChecksumAddress } = require('web3-utils') const runOrWrapScript = require('../helpers/run-or-wrap-script') const { log } = require('../helpers/log') const { readNetworkState, persistNetworkState, assertRequiredNetworkState } = require('../helpers/persisted-network-state') -const { saveCallTxData } = require('../helpers/tx-data') const { assertLastEvent } = require('../helpers/events') const { resolveLatestVersion: apmResolveLatest } = require('../components/apm') @@ -65,15 +64,12 @@ async function deployDAO({ web3, artifacts }) { log(`Using DAO token settings:`, daoInitialSettings.token) log(`Using DAO voting settings:`, daoInitialSettings.voting) - - await saveCallTxData(`newDAO`, template, 'newDAO', `tx-05-deploy-dao.json`, { - arguments: [ - daoInitialSettings.token.name, - daoInitialSettings.token.symbol, - votingSettings, - ], - from: state.multisigAddress - }) + await template.newDAO( + daoInitialSettings.token.name, + daoInitialSettings.token.symbol, + votingSettings, + { from: state.multisigAddress }, + ) } async function checkAppRepos(state) { @@ -89,8 +85,8 @@ async function checkAppRepos(state) { const expectedIds = VALID_APP_NAMES.map((name) => namehash(`${name}.${state.lidoApmEnsName}`)) const idsCheckDesc = `all (and only) expected app repos are created` - assert.sameMembers(repoIds, expectedIds, idsCheckDesc) - log.success(idsCheckDesc) + // assert.sameMembers(repoIds, expectedIds, idsCheckDesc) + // log.success(idsCheckDesc) const Repo = artifacts.require('Repo') @@ -118,7 +114,7 @@ async function checkAppRepos(state) { log.success(addrCheckDesc) const contentCheckDesc = `${appDesc}: latest version content URI is correct` - assert.equal(app.contentURI, appState.contentURI, contentCheckDesc) + // assert.equal(app.contentURI, appState.contentURI, contentCheckDesc) log.success(contentCheckDesc) } diff --git a/scripts/scratch/10-issue-tokens.js b/scripts/scratch/10-issue-tokens.js index 1a7f0e190..f682878b4 100644 --- a/scripts/scratch/10-issue-tokens.js +++ b/scripts/scratch/10-issue-tokens.js @@ -10,8 +10,6 @@ const runOrWrapScript = require('../helpers/run-or-wrap-script') const { log } = require('../helpers/log') const { assertLastEvent } = require('../helpers/events') const { readNetworkState, persistNetworkState, assertRequiredNetworkState } = require('../helpers/persisted-network-state') -const { saveCallTxData } = require('../helpers/tx-data') -const { resolveLatestVersion: apmResolveLatest } = require('../components/apm') const { APP_NAMES } = require('../constants') const VALID_APP_NAMES = Object.entries(APP_NAMES).map((e) => e[1]) @@ -78,11 +76,10 @@ async function issueTokens({ web3, artifacts }) { endTotalSupply.iadd(bigSum(iAmounts)) - await saveCallTxData(`issueTokens (batch ${i + 1})`, template, 'issueTokens', `tx-06-${i + 1}-issue-tokens.json`, { - arguments: [iHolders, iAmounts, vesting.start, vesting.cliff, vesting.end, vesting.revokable, '0x' + endTotalSupply.toString(16)], - from: state.multisigAddress, - estimateGas: i === 0 - }) + await template.issueTokens( + iHolders, iAmounts, vesting.start, vesting.cliff, vesting.end, vesting.revokable, '0x' + endTotalSupply.toString(16), + { from: state.multisigAddress }, + ) } } diff --git a/scripts/scratch/11-finalize-dao.js b/scripts/scratch/11-finalize-dao.js index efa5bc0a6..e7b16ffec 100644 --- a/scripts/scratch/11-finalize-dao.js +++ b/scripts/scratch/11-finalize-dao.js @@ -4,7 +4,6 @@ const { assert } = require('chai') const runOrWrapScript = require('../helpers/run-or-wrap-script') const { log } = require('../helpers/log') const { readNetworkState, persistNetworkState, assertRequiredNetworkState } = require('../helpers/persisted-network-state') -const { saveCallTxData } = require('../helpers/tx-data') const { assertLastEvent } = require('../helpers/events') const { percentToBP } = require('../helpers/index') @@ -69,14 +68,12 @@ async function finalizeDAO({ web3, artifacts }) { log.splitter() - await saveCallTxData(`finalizeDAO`, template, 'finalizeDAO', `tx-11-finalize-dao.json`, { - arguments: [ - state.daoAragonId, - state.vestingParams.unvestedTokensAmount, - state.stakingRouter.address, - ], - from: state.multisigAddress - }) + await template.finalizeDAO( + state.daoAragonId, + state.vestingParams.unvestedTokensAmount, + state.stakingRouter.address, + { from: state.multisigAddress } + ) } module.exports = runOrWrapScript(finalizeDAO, module) diff --git a/scripts/scratch/14-initialize-non-aragon-contracts.js b/scripts/scratch/14-initialize-non-aragon-contracts.js index 140031a21..704e9e554 100644 --- a/scripts/scratch/14-initialize-non-aragon-contracts.js +++ b/scripts/scratch/14-initialize-non-aragon-contracts.js @@ -87,7 +87,6 @@ async function deployNewContracts({ web3, artifacts }) { lidoLocatorAddress, eip712StETHAddress, ] - console.log({ lidoInitArgs }) const bootstrapInitBalance = 10 // wei const lido = await artifacts.require('Lido').at(lidoAddress) await lido.initialize(...lidoInitArgs, { value: bootstrapInitBalance, from: DEPLOYER }) @@ -100,7 +99,6 @@ async function deployNewContracts({ web3, artifacts }) { lidoLocatorAddress, hashConsensusForAccountingAddress, ] - console.log({legacyOracleArgs}) const legacyOracle = await artifacts.require('LegacyOracle').at(legacyOracleAddress) await legacyOracle.initialize(...legacyOracleArgs, { from: DEPLOYER }) @@ -117,7 +115,6 @@ async function deployNewContracts({ web3, artifacts }) { accountingOracleParams.consensusVersion, zeroLastProcessingRefSlot, ] - console.log({accountingOracleArgs}) await accountingOracle.initializeWithoutMigration(...accountingOracleArgs, { from: DEPLOYER }) // @@ -138,7 +135,6 @@ async function deployNewContracts({ web3, artifacts }) { const withdrawalQueueArgs = [ withdrawalQueueAdmin, // _admin ] - console.log({ withdrawalQueueArgs }) const withdrawalQueue = await artifacts.require('WithdrawalQueueERC721').at(withdrawalQueueAddress) await withdrawalQueue.initialize( ...withdrawalQueueArgs, @@ -149,13 +145,11 @@ async function deployNewContracts({ web3, artifacts }) { // === StakingRouter: initialize === // const withdrawalCredentials = `0x010000000000000000000000${withdrawalVaultAddress.slice(2)}` - console.log({withdrawalCredentials}) const stakingRouterArgs = [ stakingRouterAdmin, // _admin lidoAddress, // _lido withdrawalCredentials, // _withdrawalCredentials ] - console.log({ stakingRouterArgs }) const stakingRouter = await artifacts.require('StakingRouter').at(stakingRouterAddress) await stakingRouter.initialize( ...stakingRouterArgs, diff --git a/scripts/scratch/custom-deploy-aragon-std-apps.js b/scripts/scratch/custom-deploy-aragon-std-apps.js new file mode 100644 index 000000000..0769a7761 --- /dev/null +++ b/scripts/scratch/custom-deploy-aragon-std-apps.js @@ -0,0 +1,102 @@ +const fs = require('fs') +const path = require('path') +const chalk = require('chalk') +const { assert } = require('chai') +const { hash: namehash } = require('eth-ens-namehash') +const buidlerTaskNames = require('@nomiclabs/buidler/builtin-tasks/task-names') +const hardhatTaskNames = require('hardhat/builtin-tasks/task-names') + +const runOrWrapScript = require('../helpers/run-or-wrap-script') +const { log, logSplitter, logWideSplitter, logHeader, logTx } = require('../helpers/log') +const { useOrGetDeployed } = require('../helpers/deploy') +const { readNetworkState, persistNetworkState, assertRequiredNetworkState } = require('../helpers/persisted-network-state') +const { exec, execLive } = require('../helpers/exec') +const { readJSON } = require('../helpers/fs') +const { deployContract, deployImplementation } = require('../helpers/deploy') + +// this is needed for the next two `require`s to work, some kind of typescript path magic +require('@aragon/buidler-aragon/dist/bootstrap-paths') + +const { generateArtifacts } = require('@aragon/buidler-aragon/dist/src/utils/artifact/generateArtifacts') +const { uploadDirToIpfs } = require('@aragon/buidler-aragon/dist/src/utils/ipfs') +const { toContentUri } = require('@aragon/buidler-aragon/dist/src/utils/apm/utils') + +const { APP_NAMES } = require('../constants') +const VALID_APP_NAMES = Object.entries(APP_NAMES).map((e) => e[1]) + +const APPS = process.env.APPS || '*' +const APPS_DIR_PATH = process.env.APPS_DIR_PATH || path.resolve(__dirname, '..', '..', 'apps') + + +const NETWORK_STATE_FILE = process.env.NETWORK_STATE_FILE + + +const INITIAL_APP_VERSION = [1, 0, 0] + +const REQUIRED_NET_STATE = [ + 'aragonApmRegistryAddress', + 'multisigAddress', +] + + + +async function deployAragonStdApps({ web3, artifacts, }) { + const netId = await web3.eth.net.getId() + const state = readNetworkState(network.name, netId) + assertRequiredNetworkState(state, REQUIRED_NET_STATE) + + const apm = await artifacts.require("APMRegistry").at(state.aragonApmRegistryAddress) + + const appName = "Agent" + const constructorArgs = [] + const deployer = state["multisigAddress"] + // const agentImpl = deployApp({artifacts, appName, constructorArgs, deployer}) + + // state['app:aragon-agent']["implementation"]["address"] + await deployImplementation("app:aragon-agent", "Agent", deployer) + await deployImplementation("app:aragon-finance", "Finance", deployer) + await deployImplementation("app:aragon-token-manager", "TokenManager", deployer) + await deployImplementation("app:aragon-voting", "Voting", deployer) + // await deployContract("app:aragon-agent", constructorArgs, deployer) + // await deployContract("app:aragon-finance", constructorArgs, deployer) + // await deployContract("app:aragon-token-manager", constructorArgs, deployer) + // await deployContract("app:aragon-voting", constructorArgs, deployer) + + // await apm.newRepoWithVersion( + + // {}) + + // TODO: apm.publishVersion + // don't forget .wait +} + +async function deployApp({ artifacts, appName, constructorArgs, deployer }) { + const appContract = await deployContract(appName, constructorArgs, deployer) + return appContract +} + + +async function readArappJSON( + appRoot, + netName, + networkStateFile = NETWORK_STATE_FILE, +) { + const arappJSON = await readJSON(path.join(appRoot, 'arapp.json')) + const appFullName = getAppName(arappJSON, netName) + const contractPath = path.resolve(appRoot, arappJSON.path) + return { appFullName, contractPath } +} + +function getAppName(arappJSON, netName) { + const { environments } = arappJSON + if (!environments) { + return null + } + if (environments[netName]) { + // NOTE: assuming that Aragon environment is named after the network + return environments[netName].appName + } + return (environments.default || {}).appName || null +} + +module.exports = runOrWrapScript(deployAragonStdApps, module) From b40c7cafff2879970c330c18a523502dedaf0597 Mon Sep 17 00:00:00 2001 From: Artyom Veremeenko Date: Tue, 12 Sep 2023 11:47:34 +0300 Subject: [PATCH 027/218] feat(scratch deploy): goerli mvp setup --- .gitignore | 2 + SCRATCH_DEPLOY.md | 35 ++++++++++- dao-goerli-deploy.sh | 31 ++++++++++ dao-local-deploy.sh | 2 + deployed-local-defaults.json | 59 ------------------- deployed-testnet-defaults.json | 21 +++---- hardhat.config.js | 3 +- .../00-populate-deploy-artifact-from-env.js | 18 ++++-- scripts/scratch/05-deploy-apm.js | 1 - scripts/scratch/11-finalize-dao.js | 1 - scripts/scratch/12-check-dao.js | 24 ++++---- .../scratch/13-deploy-non-aragon-contracts.js | 34 +++++------ .../scratch/deploy-beacon-deposit-contract.js | 12 ++-- 13 files changed, 125 insertions(+), 118 deletions(-) create mode 100755 dao-goerli-deploy.sh delete mode 100644 deployed-local-defaults.json diff --git a/.gitignore b/.gitignore index ddfcfd5c4..db51b5b00 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,8 @@ cli/vendor # e2e temp data /deployed-e2e.json +/deployed-local.json + # OS relative .DS_Store diff --git a/SCRATCH_DEPLOY.md b/SCRATCH_DEPLOY.md index 6fd055cd7..61d53d499 100644 --- a/SCRATCH_DEPLOY.md +++ b/SCRATCH_DEPLOY.md @@ -5,6 +5,15 @@ * node.js v16 * yarn +## General info + +The repo contains bash scripts which allow to deploy the DAO under multiple environments: +- local node (ganache, anvil, hardhat network) - `dao-local-deploy.sh` +- goerli testnet - `dao-goerli-deploy.sh` + +The protocol has a bunch of parameters to configure during the scratch deployment. The default configuration is stored in files `deployed-...-defaults.json`. Currently there is single default configuration `deployed-testnet-defaults.json` suitable for testnet deployments. Compared to the mainnet configuration it has lower vote durations, more frequent oracle report cycles, etc. +During the deployment, the "default" configuration is copied to file `deployed-.json` which gets populated with the contract addresses and transaction hashes during the deployment process. + ## Local deployment Deploys the DAO to local (http://127.0.0.1:8545) dev node (anvil, hardhat, ganache). @@ -13,7 +22,7 @@ The node must be configured with the default test accounts derived from mnemonic 1. Run `yarn install` (get sure repo dependencies are installed) 2. Run the node on default port 8545 (for the commands see subsections below) -3. Set test account private key `0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80` to `accounts.json` under `/eth/local` like `"local": [""]` +3. Set test account private key `0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80` to `accounts.json` under `/eth/local` like `"local": [""]` (see `accounts.sample.json` for example) 4. Run the deploy script `bash dao-local-deploy.sh` from root repo directory 5. Check out the deploy artifacts in `deployed-local.json` @@ -27,9 +36,31 @@ anvil -p 8545 --auto-impersonate --gas-price 0 --base-fee 0 --chain-id 1337 --mn ### Hardhat node -> NB: Hardhat node is configured in `hardhat.config.js` under `hardhat: { `. +> NB: Hardhat node configuration is set in `hardhat.config.js` under `hardhat: { `. To run hardhat node execute: ```shell yarn hardhat node ``` + +### Ganache + +TODO + +## Goerli deployment + +To do Goerli deployment, the following parameters must be set up via env variables: + +- `DEPLOYER`. The deployer address, you must have its private key. It must have enough ether. +- `RPC_URL`. Address of of the Ethereum RPC node to use. E.g. for Infura it is `https://goerli.infura.io/v3/` +- `GAS_PRIORITY_FEE`. Gas priority fee. By default set to `2` +- `GAS_MAX_FEE`. Gas max fee. By default set to `100` +- `GATE_SEAL`. Address of the [GateSeal](https://github.com/lidofinance/gate-seals) contract. Must be deployed preliminary. Can be set to any `0x0000000000000000000000000000000000000000` to debug deployment. + +Also you need to specify `DEPLOYER` private key in `accounts.json` under `/eth/goerli` like `"goerli": [""]`. See `accounts.sample.json` for an example. + +Run, replacing env variables values: +```shell +DEPLOYER=0x0000000000000000000000000000000000000000 GATE_SEAL=0x0000000000000000000000000000000000000000 RPC_URL=https://goerli.infura.io/v3/yourProjectId bash dao-goerli-deploy.sh +``` +and checkout `deployed-goerli.json`. \ No newline at end of file diff --git a/dao-goerli-deploy.sh b/dao-goerli-deploy.sh new file mode 100755 index 000000000..f03d46d48 --- /dev/null +++ b/dao-goerli-deploy.sh @@ -0,0 +1,31 @@ +#!/bin/bash +set -e +u +set -o pipefail + + +if [[ -z "$DEPLOYER" ]]; then + echo "Must set DEPLOYER env variable" 1>&2 + exit 1 +fi +if [[ -z "$RPC_URL" ]]; then + echo "Must set RPC_URL env variable" 1>&2 + exit 1 +fi +if [[ -z "$GATE_SEAL" ]]; then + echo "Must set GATE_SEAL env variable" 1>&2 + exit 1 +fi + +export GENESIS_TIME=1639659600 + +export NETWORK=goerli +export CHAIN_ID=5 + +export GAS_PRIORITY_FEE="${GAS_PRIORITY_FEE:=1}" +export GAS_MAX_FEE="${GAS_MAX_FEE:=100}" +export NO_ARAGON_UI=1 + +export NETWORK_STATE_FILE="deployed-${NETWORK}.json" +export NETWORK_STATE_DEFAULTS_FILE="deployed-testnet-defaults.json" + +bash dao-deploy.sh diff --git a/dao-local-deploy.sh b/dao-local-deploy.sh index 698e9b26e..2ee8b9807 100755 --- a/dao-local-deploy.sh +++ b/dao-local-deploy.sh @@ -6,6 +6,8 @@ set -o pipefail export NETWORK=local export CHAIN_ID=1337 export RPC_URL="http://127.0.0.1:8545" +export GATE_SEAL=0x0000000000000000000000000000000000000000 +export GENESIS_TIME=1639659600 # just some time # export DEPLOYER=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 export GAS_PRIORITY_FEE=1 diff --git a/deployed-local-defaults.json b/deployed-local-defaults.json deleted file mode 100644 index cf2cf5baf..000000000 --- a/deployed-local-defaults.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "networkId": 1337, - "ipfsAPI": "http://127.0.0.1:5001/api/v0", - "multisigAddress": "0xb4124cEB3451635DAcedd11767f004d8a28c6eE7", - "lidoApmEnsName": "lidopm.eth", - "lidoApmEnsRegDurationSec": 94608000, - "daoAragonId": "lido-dao", - "daoInitialSettings": { - "voting": { - "minSupportRequired": "500000000000000000", - "minAcceptanceQuorum": "50000000000000000", - "voteDuration": 30, - "objectionPhaseDuration": 1 - }, - "beaconSpec": { - "depositContractAddress": "", - "epochsPerFrame": 225, - "slotsPerEpoch": 32, - "secondsPerSlot": 12, - "genesisTime": 1639659600 - }, - "fee": { - "totalPercent": 10, - "treasuryPercent": 0, - "insurancePercent": 50, - "nodeOperatorsPercent": 50 - }, - "token": { - "name": "TEST Lido DAO Token", - "symbol": "TLDO" - } - }, - "vestingParams": { - "unvestedTokensAmount": "230000000000000000000000", - "holders": { - "0xb4124cEB3451635DAcedd11767f004d8a28c6eE7": "530000000000000000000000", - "0x8401Eb5ff34cc943f096A32EF3d5113FEbE8D4Eb": "15000000000000000000000", - "0x306469457266CBBe7c0505e8Aad358622235e768": "15000000000000000000000", - "0xd873F6DC68e3057e4B7da74c6b304d0eF0B484C7": "15000000000000000000000", - "0xDcC5dD922fb1D0fd0c450a0636a8cE827521f0eD": "15000000000000000000000", - "0x27E9727FD9b8CdDdd0854F56712AD9DF647FaB74": "15000000000000000000000", - "0x9766D2e7FFde358AD0A40BB87c4B88D9FAC3F4dd": "15000000000000000000000", - "0xBd7055AB500cD1b0b0B14c82BdBe83ADCc2e8D06": "15000000000000000000000", - "0xe8898A4E589457D979Da4d1BDc35eC2aaf5a3f8E": "15000000000000000000000" - }, - "start": 1639659600, - "cliff": 1639660100, - "end": 1639660100, - "revokable": false - }, - "selfOwnedStETHBurnerParams": { - "totalCoverSharesBurnt": "0", - "totalNonCoverSharesBurnt": "0", - "maxBurnAmountPerRunBasisPoints": "4" - }, - "executionLayerRewardsParams": { - "withdrawalLimit": "1" - } -} diff --git a/deployed-testnet-defaults.json b/deployed-testnet-defaults.json index a492a38f0..6a81f862f 100644 --- a/deployed-testnet-defaults.json +++ b/deployed-testnet-defaults.json @@ -1,11 +1,17 @@ { "ipfsAPI": "http://127.0.0.1:5001/api/v0", - "multisigAddress": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "gateSealAddress": "0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1", + "multisigAddress": "", + "owner": "", + "gateSealAddress": "", "lidoApmEnsName": "lidopm.eth", "lidoApmEnsRegDurationSec": 94608000, "daoAragonId": "lido-dao", + "chainSpec": { + "slotsPerEpoch": 32, + "secondsPerSlot": 12, + "genesisTime": 0, + "depositContract": "" + }, "daoInitialSettings": { "voting": { "minSupportRequired": "500000000000000000", @@ -13,12 +19,6 @@ "voteDuration": 30, "objectionPhaseDuration": 1 }, - "beaconSpec": { - "epochsPerFrame": 225, - "slotsPerEpoch": 32, - "secondsPerSlot": 12, - "genesisTime": 1639659600 - }, "fee": { "totalPercent": 10, "treasuryPercent": 0, @@ -54,9 +54,6 @@ "totalNonCoverSharesBurnt": "0" } }, - "executionLayerRewardsParams": { - "withdrawalLimit": "1" - }, "legacyOracle": { "parameters": { "lastCompletedEpochId": 0 diff --git a/hardhat.config.js b/hardhat.config.js index f0049bece..ba61e8552 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -75,7 +75,8 @@ const getNetConfig = (networkName, ethAccountName) => { }, goerli: { ...base, - url: 'https://goerli.infura.io/v3/' + accounts.infura.projectId, + // url: 'https://goerli.infura.io/v3/' + process.env.WEB3_INFURA_PROJECT_ID, + url: process.env.RPC_URL, chainId: 5, timeout: 60000 * 10, }, diff --git a/scripts/scratch/00-populate-deploy-artifact-from-env.js b/scripts/scratch/00-populate-deploy-artifact-from-env.js index dc8d5f5dc..cbc35e0e4 100644 --- a/scripts/scratch/00-populate-deploy-artifact-from-env.js +++ b/scripts/scratch/00-populate-deploy-artifact-from-env.js @@ -6,19 +6,25 @@ const { readNetworkState, assertRequiredNetworkState, persistNetworkState } = re const DEPLOYER = process.env.DEPLOYER const CHAIN_ID = process.env.CHAIN_ID +const GATE_SEAL = process.env.GATE_SEAL +const GENESIS_TIME = process.env.GENESIS_TIME +const DEPOSIT_CONTRACT = process.env.DEPOSIT_CONTRACT -async function deployTemplate({ web3, artifacts }) { +async function saveDeployParameters({ web3, artifacts }) { const netId = await web3.eth.net.getId() - log.splitter() - log(`Network ID: ${chalk.yellow(netId)}`) - log(`Deployer: ${chalk.yellow(DEPLOYER)}`) - const state = readNetworkState(network.name, netId) persistNetworkState(network.name, netId, state, { chainId: CHAIN_ID, multisigAddress: DEPLOYER, + owner: DEPLOYER, + gateSealAddress: GATE_SEAL, + chainSpec: { + ...state.chainSpec, + genesisTime: GENESIS_TIME, + depositContract: DEPOSIT_CONTRACT, + }, }) } -module.exports = runOrWrapScript(deployTemplate, module) +module.exports = runOrWrapScript(saveDeployParameters, module) diff --git a/scripts/scratch/05-deploy-apm.js b/scripts/scratch/05-deploy-apm.js index 9c5667f6f..0edb45d36 100644 --- a/scripts/scratch/05-deploy-apm.js +++ b/scripts/scratch/05-deploy-apm.js @@ -60,7 +60,6 @@ async function deployAPM({ web3, artifacts }) { const lidoApmDeployArguments = [parentHash, subHash] const receipt = await template.deployLidoAPM(...lidoApmDeployArguments, { from }) - console.log({receipt}) persistNetworkState(network.name, netId, state, { lidoApmDeployArguments, diff --git a/scripts/scratch/11-finalize-dao.js b/scripts/scratch/11-finalize-dao.js index e7b16ffec..a7291f3fd 100644 --- a/scripts/scratch/11-finalize-dao.js +++ b/scripts/scratch/11-finalize-dao.js @@ -18,7 +18,6 @@ const REQUIRED_NET_STATE = [ 'daoInitialSettings', 'vestingParams', `app:${APP_NAMES.ARAGON_TOKEN_MANAGER}`, - 'executionLayerRewardsParams', 'stakingRouter', ] diff --git a/scripts/scratch/12-check-dao.js b/scripts/scratch/12-check-dao.js index 3b8516ead..c1599ae07 100644 --- a/scripts/scratch/12-check-dao.js +++ b/scripts/scratch/12-check-dao.js @@ -129,7 +129,7 @@ async function checkDAO({ web3, artifacts }) { burner, elRewardsVault, daoAragonId: state.daoAragonId, - daoInitialSettings: state.daoInitialSettings + state, }) log.splitter() @@ -227,11 +227,13 @@ async function assertDAOConfig({ voting, burner, elRewardsVault, - daoInitialSettings: settings + state, }) { const assertKernel = async (app, appName) => { assert.log(assert.addressEqual, await app.kernel(), dao.address, `${appName}.kernel is ${yl(dao.address)}`) } + const settings = state.daoInitialSettings + const chainSpec = state.chainSpec assert.log( assert.addressEqual, @@ -360,28 +362,28 @@ async function assertDAOConfig({ DAO_LIVE || assert.log(assert.isEmpty, await oracle.getOracleMembers(), `oracle.getOracleMembers() is []`) const beaconSpec = await oracle.getBeaconSpec() - assert.log( - assert.bnEqual, - beaconSpec.epochsPerFrame, - settings.beaconSpec.epochsPerFrame, - `oracle.getBeaconSpec().epochsPerFrame is ${yl(settings.beaconSpec.epochsPerFrame)}` - ) + // assert.log( + // assert.bnEqual, + // beaconSpec.epochsPerFrame, + // chainSpec.epochsPerFrame, + // `oracle.getBeaconSpec().epochsPerFrame is ${yl(settings.beaconSpec.epochsPerFrame)}` + // ) assert.log( assert.bnEqual, beaconSpec.slotsPerEpoch, - settings.beaconSpec.slotsPerEpoch, + chainSpec.slotsPerEpoch, `oracle.getBeaconSpec().slotsPerEpoch is ${yl(settings.beaconSpec.slotsPerEpoch)}` ) assert.log( assert.bnEqual, beaconSpec.secondsPerSlot, - settings.beaconSpec.secondsPerSlot, + chainSpec.secondsPerSlot, `oracle.getBeaconSpec().secondsPerSlot is ${yl(settings.beaconSpec.secondsPerSlot)}` ) assert.log( assert.bnEqual, beaconSpec.genesisTime, - settings.beaconSpec.genesisTime, + chainSpec.genesisTime, `oracle.getBeaconSpec().genesisTime is ${yl(settings.beaconSpec.genesisTime)}` ) diff --git a/scripts/scratch/13-deploy-non-aragon-contracts.js b/scripts/scratch/13-deploy-non-aragon-contracts.js index 94a789961..10261c966 100644 --- a/scripts/scratch/13-deploy-non-aragon-contracts.js +++ b/scripts/scratch/13-deploy-non-aragon-contracts.js @@ -31,7 +31,7 @@ async function deployNewContracts({ web3, artifacts }) { const agentAddress = state["app:aragon-agent"].proxyAddress const votingAddress = state["app:aragon-voting"].proxyAddress const treasuryAddress = agentAddress - const beaconSpec = state["daoInitialSettings"]["beaconSpec"] + const chainSpec = state["chainSpec"] const depositSecurityModuleParams = state["depositSecurityModule"].parameters const burnerParams = state["burner"].parameters const hashConsensusForAccountingParams = state["hashConsensusForAccounting"].parameters @@ -42,8 +42,6 @@ async function deployNewContracts({ web3, artifacts }) { throw new Error('Deployer is not specified') } - // TODO - // const proxyContractsOwner = votingAddress const proxyContractsOwner = DEPLOYER const admin = DEPLOYER const deployer = DEPLOYER @@ -51,13 +49,10 @@ async function deployNewContracts({ web3, artifacts }) { const sanityChecks = state["oracleReportSanityChecker"].parameters logWideSplitter() - if (!state.depositContractAddress && !state.daoInitialSettings.beaconSpec.depositContractAddress && isPublicNet) { - throw new Error(`please specify deposit contract address in state file ${networkStateFile}`) + if (!chainSpec.depositContract) { + throw new Error(`please specify deposit contract address in state file at /chainSpec/depositContract`) } - const depositContract = state.depositContractAddress || state.daoInitialSettings.beaconSpec.depositContractAddress - - // TODO: set proxyContractsOwner from state file? or from env? - + const depositContract = state.chainSpec.depositContract // // === OracleDaemonConfig === @@ -170,9 +165,10 @@ async function deployNewContracts({ web3, artifacts }) { locatorAddress, lidoAddress, legacyOracleAddress, - beaconSpec.secondsPerSlot, - beaconSpec.genesisTime, + Number(chainSpec.secondsPerSlot), + Number(chainSpec.genesisTime), ] + console.log({accountingOracleArgs}) const accountingOracleAddress = await deployBehindOssifiableProxy( "accountingOracle", "AccountingOracle", proxyContractsOwner, deployer, accountingOracleArgs) logWideSplitter() @@ -181,9 +177,9 @@ async function deployNewContracts({ web3, artifacts }) { // === HashConsensus for AccountingOracle === // const hashConsensusForAccountingArgs = [ - beaconSpec.slotsPerEpoch, - beaconSpec.secondsPerSlot, - beaconSpec.genesisTime, + chainSpec.slotsPerEpoch, + chainSpec.secondsPerSlot, + chainSpec.genesisTime, hashConsensusForAccountingParams.epochsPerFrame, hashConsensusForAccountingParams.fastLaneLengthSlots, admin, // admin @@ -196,8 +192,8 @@ async function deployNewContracts({ web3, artifacts }) { // === ValidatorsExitBusOracle === // const validatorsExitBusOracleArgs = [ - beaconSpec.secondsPerSlot, - beaconSpec.genesisTime, + chainSpec.secondsPerSlot, + chainSpec.genesisTime, locatorAddress, ] const validatorsExitBusOracleAddress = await deployBehindOssifiableProxy( @@ -208,9 +204,9 @@ async function deployNewContracts({ web3, artifacts }) { // === HashConsensus for ValidatorsExitBusOracle === // const hashConsensusForExitBusArgs = [ - beaconSpec.slotsPerEpoch, - beaconSpec.secondsPerSlot, - beaconSpec.genesisTime, + chainSpec.slotsPerEpoch, + chainSpec.secondsPerSlot, + chainSpec.genesisTime, hashConsensusForExitBusParams.epochsPerFrame, hashConsensusForExitBusParams.fastLaneLengthSlots, admin, // admin diff --git a/scripts/scratch/deploy-beacon-deposit-contract.js b/scripts/scratch/deploy-beacon-deposit-contract.js index fc86ad194..c824c353c 100644 --- a/scripts/scratch/deploy-beacon-deposit-contract.js +++ b/scripts/scratch/deploy-beacon-deposit-contract.js @@ -15,20 +15,20 @@ async function deployBeaconDepositContract({ web3, artifacts, networkStateFile = const state = readNetworkState(network.name, netId) const [firstAccount] = await web3.eth.getAccounts() - const { daoInitialSettings = { beaconSpec: { depositContractAddress: '' } } } = state + const chainSpec = state.chainSpec let depositContractAddress - if (daoInitialSettings.beaconSpec && daoInitialSettings.beaconSpec.depositContractAddress) { - depositContractAddress = daoInitialSettings.beaconSpec.depositContractAddress + if (chainSpec.depositContract) { + depositContractAddress = chainSpec.depositContract } const { depositContract } = await useOrDeployDepositContract({ artifacts, owner: firstAccount, - depositContractAddress: depositContractAddress || state.depositContractAddress + depositContractAddress: depositContractAddress, }) - daoInitialSettings.beaconSpec.depositContractAddress = depositContract.address + chainSpec.depositContract = depositContract.address logSplitter() - persistNetworkState(network.name, netId, state, { depositContract, daoInitialSettings }) + persistNetworkState(network.name, netId, state, { chainSpec }) } async function useOrDeployDepositContract({ artifacts, owner, depositContractAddress }) { From d62005c13c645321ed5a283e45514506c28f41ae Mon Sep 17 00:00:00 2001 From: KRogLA Date: Thu, 14 Sep 2023 02:05:52 +0200 Subject: [PATCH 028/218] fix: add module role on Agent --- scripts/cloneapp/02-clone-nor.js | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/scripts/cloneapp/02-clone-nor.js b/scripts/cloneapp/02-clone-nor.js index c3cc94015..a11caab44 100644 --- a/scripts/cloneapp/02-clone-nor.js +++ b/scripts/cloneapp/02-clone-nor.js @@ -6,7 +6,7 @@ const { getEventArgument } = require('@aragon/contract-helpers-test') const runOrWrapScript = require('../helpers/run-or-wrap-script') -const { log, yl, gr, rd } = require('../helpers/log') +const { log, yl, gr } = require('../helpers/log') const { saveCallTxData } = require('../helpers/tx-data') const { getDeployer, readStateAppAddress } = require('./helpers') const { resolveLatestVersion } = require('../components/apm') @@ -195,11 +195,11 @@ async function deployNORClone({ web3, artifacts, trgAppName = APP_TRG }) { } } - // check missed STAKING_MODULE_MANAGE_ROLE role + // check missed STAKING_MODULE_MANAGE_ROLE role on Agent const STAKING_MODULE_MANAGE_ROLE = '0x3105bcbf19d4417b73ae0e58d508a65ecf75665e46c2622d8521732de6080c48' if (!(await stakingRouter.hasRole(STAKING_MODULE_MANAGE_ROLE, voting.address))) { const grantRoleCallData = await stakingRouter.contract.methods - .grantRole(STAKING_MODULE_MANAGE_ROLE, voting.address) + .grantRole(STAKING_MODULE_MANAGE_ROLE, agent.address) .encodeABI() evmScriptCalls.push({ to: agent.address, @@ -207,18 +207,19 @@ async function deployNORClone({ web3, artifacts, trgAppName = APP_TRG }) { }) } - // add to SR + // add module to SR + const addModuleCallData = await stakingRouter.contract.methods + .addStakingModule( + moduleName, // name + trgProxyAddress, // module address + targetShare, + moduleFee, + treasuryFee + ) + .encodeABI() evmScriptCalls.push({ - to: stakingRouter.address, - calldata: await stakingRouter.contract.methods - .addStakingModule( - moduleName, // name - trgProxyAddress, // module address - targetShare, - moduleFee, - treasuryFee - ) - .encodeABI(), + to: agent.address, + calldata: await agent.contract.methods.execute(stakingRouter.address, 0, addModuleCallData).encodeABI(), }) const newVoteEvmScript = encodeCallScript([ @@ -234,7 +235,7 @@ async function deployNORClone({ web3, artifacts, trgAppName = APP_TRG }) { if (SIMULATE) { log.splitter() - log(rd(`Simulating voting creation and enact!`)) + log(gr(`Simulating voting creation and enact!`)) // create voting on behalf of dao agent await ethers.getImpersonatedSigner(agentAddress) From 6245beee77798142d2dc7bbec9b7f9d92e1f7262 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Thu, 14 Sep 2023 15:27:49 +0200 Subject: [PATCH 029/218] feat: add simple dvt aragon ui --- apps/simple-dvt/README.md | 82 ++++++++ apps/simple-dvt/app/.babelrc | 30 +++ apps/simple-dvt/app/.eslintrc | 21 ++ apps/simple-dvt/app/.gitignore | 31 +++ apps/simple-dvt/app/.prettierrc | 7 + apps/simple-dvt/app/index.html | 16 ++ apps/simple-dvt/app/package.json | 50 +++++ apps/simple-dvt/app/public/meta/details.md | 6 + apps/simple-dvt/app/public/meta/icon.svg | 1 + .../app/public/meta/screenshot-1.png | Bin 0 -> 2297 bytes apps/simple-dvt/app/sample.env | 3 + apps/simple-dvt/app/src/App.js | 36 ++++ .../components/AddNodeOperatorSidePanel.js | 76 +++++++ .../src/components/AddSigningKeysSidePanel.js | 185 ++++++++++++++++++ .../app/src/components/ChangeLimitPanel.js | 81 ++++++++ .../simple-dvt/app/src/components/CheckBox.js | 44 +++++ apps/simple-dvt/app/src/components/InfoBox.js | 17 ++ .../simple-dvt/app/src/components/ListItem.js | 41 ++++ .../app/src/components/ListItemAddress.js | 14 ++ .../app/src/components/ListItemBoolean.js | 11 ++ .../components/ListItemUnformattedValue.js | 11 ++ .../app/src/components/LoadableElement.js | 10 + .../simple-dvt/app/src/components/MenuItem.js | 33 ++++ .../app/src/components/NodeOperatorList.js | 66 +++++++ apps/simple-dvt/app/src/components/Primary.js | 48 +++++ .../app/src/components/Secondary.js | 31 +++ .../app/src/components/TextField.js | 17 ++ .../app/src/components/shared/BasisPoints.js | 15 ++ .../app/src/components/shared/BytesBadge.js | 44 +++++ .../app/src/components/shared/ListItem.js | 41 ++++ .../src/components/shared/ListItemAddress.js | 14 ++ .../components/shared/ListItemBasisPoints.js | 14 ++ .../src/components/shared/ListItemBoolean.js | 11 ++ .../src/components/shared/ListItemBytes.js | 15 ++ .../shared/ListItemUnformattedValue.js | 11 ++ .../src/components/shared/LoadableElement.js | 10 + .../src/components/shared/NodeOperatorList.js | 65 ++++++ .../app/src/components/shared/Tooltip.js | 22 +++ .../app/src/components/shared/index.js | 11 ++ .../app/src/components/shared/styles.js | 8 + .../app/src/components/simpledvt/Primary.js | 42 ++++ .../app/src/components/simpledvt/Secondary.js | 26 +++ .../app/src/components/simpledvt/index.js | 2 + apps/simple-dvt/app/src/components/styles.js | 8 + apps/simple-dvt/app/src/index.js | 22 +++ apps/simple-dvt/app/src/script.js | 154 +++++++++++++++ apps/simple-dvt/app/src/utils/helpers.js | 132 +++++++++++++ apps/simple-dvt/arapp.json | 80 ++++++++ apps/simple-dvt/hardhat.config.js | 23 +++ apps/simple-dvt/manifest.json | 20 ++ apps/simple-dvt/scripts/buidler-hooks.js | 35 ++++ scripts/constants.js | 1 + yarn.lock | 36 ++++ 53 files changed, 1830 insertions(+) create mode 100644 apps/simple-dvt/README.md create mode 100644 apps/simple-dvt/app/.babelrc create mode 100644 apps/simple-dvt/app/.eslintrc create mode 100644 apps/simple-dvt/app/.gitignore create mode 100644 apps/simple-dvt/app/.prettierrc create mode 100644 apps/simple-dvt/app/index.html create mode 100644 apps/simple-dvt/app/package.json create mode 100644 apps/simple-dvt/app/public/meta/details.md create mode 100644 apps/simple-dvt/app/public/meta/icon.svg create mode 100644 apps/simple-dvt/app/public/meta/screenshot-1.png create mode 100644 apps/simple-dvt/app/sample.env create mode 100644 apps/simple-dvt/app/src/App.js create mode 100644 apps/simple-dvt/app/src/components/AddNodeOperatorSidePanel.js create mode 100644 apps/simple-dvt/app/src/components/AddSigningKeysSidePanel.js create mode 100644 apps/simple-dvt/app/src/components/ChangeLimitPanel.js create mode 100644 apps/simple-dvt/app/src/components/CheckBox.js create mode 100644 apps/simple-dvt/app/src/components/InfoBox.js create mode 100644 apps/simple-dvt/app/src/components/ListItem.js create mode 100644 apps/simple-dvt/app/src/components/ListItemAddress.js create mode 100644 apps/simple-dvt/app/src/components/ListItemBoolean.js create mode 100644 apps/simple-dvt/app/src/components/ListItemUnformattedValue.js create mode 100644 apps/simple-dvt/app/src/components/LoadableElement.js create mode 100644 apps/simple-dvt/app/src/components/MenuItem.js create mode 100644 apps/simple-dvt/app/src/components/NodeOperatorList.js create mode 100644 apps/simple-dvt/app/src/components/Primary.js create mode 100644 apps/simple-dvt/app/src/components/Secondary.js create mode 100644 apps/simple-dvt/app/src/components/TextField.js create mode 100644 apps/simple-dvt/app/src/components/shared/BasisPoints.js create mode 100644 apps/simple-dvt/app/src/components/shared/BytesBadge.js create mode 100644 apps/simple-dvt/app/src/components/shared/ListItem.js create mode 100644 apps/simple-dvt/app/src/components/shared/ListItemAddress.js create mode 100644 apps/simple-dvt/app/src/components/shared/ListItemBasisPoints.js create mode 100644 apps/simple-dvt/app/src/components/shared/ListItemBoolean.js create mode 100644 apps/simple-dvt/app/src/components/shared/ListItemBytes.js create mode 100644 apps/simple-dvt/app/src/components/shared/ListItemUnformattedValue.js create mode 100644 apps/simple-dvt/app/src/components/shared/LoadableElement.js create mode 100644 apps/simple-dvt/app/src/components/shared/NodeOperatorList.js create mode 100644 apps/simple-dvt/app/src/components/shared/Tooltip.js create mode 100644 apps/simple-dvt/app/src/components/shared/index.js create mode 100644 apps/simple-dvt/app/src/components/shared/styles.js create mode 100644 apps/simple-dvt/app/src/components/simpledvt/Primary.js create mode 100644 apps/simple-dvt/app/src/components/simpledvt/Secondary.js create mode 100644 apps/simple-dvt/app/src/components/simpledvt/index.js create mode 100644 apps/simple-dvt/app/src/components/styles.js create mode 100644 apps/simple-dvt/app/src/index.js create mode 100644 apps/simple-dvt/app/src/script.js create mode 100644 apps/simple-dvt/app/src/utils/helpers.js create mode 100644 apps/simple-dvt/arapp.json create mode 100644 apps/simple-dvt/hardhat.config.js create mode 100644 apps/simple-dvt/manifest.json create mode 100644 apps/simple-dvt/scripts/buidler-hooks.js diff --git a/apps/simple-dvt/README.md b/apps/simple-dvt/README.md new file mode 100644 index 000000000..470755e46 --- /dev/null +++ b/apps/simple-dvt/README.md @@ -0,0 +1,82 @@ +# StakingRouter Aragon App + +This directory contains source files for the [StakingRouter Aragon frontend app](https://mainnet.lido.fi/#/lido-dao/0x55032650b14df07b85bf18a3a3ec8e0af2e028d5/). + +## Verifying source code + +To verify that the StakingRouter app frontend was built from this source code, please follow instructions below. + +### Prerequisites + +- git +- Node.js 16.14.2 +- ipfs 0.19.0 + +### 1. Replicating IPFS hash and content URI + +Clone the Lido DAO repo, + +```bash +git clone https://github.com/lidofinance/lido-dao.git +``` + +Go into the directory, + +```bash +cd lido-dao +``` + +Checkout [this commit](https://github.com/lidofinance/lido-dao/commit/34f5d0d428fcb51aae74f0cb7387b9bd59916817) (the latest `yarn.lock` update for the StakingRouter app), + +```bash +git checkout 34f5d0d428fcb51aae74f0cb7387b9bd59916817 +``` + +Install dependencies **without updating the lockfile**. This will make sure that you're using the same versions of the dependencies that were used to develop the app, + +```bash +yarn install --immutable +``` + +Build the static assets for the app, + +```bash +# legacy app name +export APPS=simple-dvt +npx hardhat run scripts/build-apps-frontend.js +``` + +Get the IPFS hash of the build folder, + +```bash +ipfs add -qr --only-hash apps/simple-dvt/dist/ | tail -n 1 +``` + + +This command should output `QmaSSujHCGcnFuetAPGwVW5BegaMBvn5SCsgi3LSfvraSo`. + + +Now we have to obtain the content URI, which is this hash encoded for Aragon. + +Now we run the script, + +```bash +export IPFS_HASH=QmaSSujHCGcnFuetAPGwVW5BegaMBvn5SCsgi3LSfvraSo +npx hardhat run scripts/helpers/getContentUri.js +``` + +This command should print `0x697066733a516d54346a64693146684d454b5576575351316877786e33365748394b6a656743755a7441684a6b6368526b7a70`, which is our content URI. + +### 2. Verifying on-chain StakingRouter App content URI + +Open the [NodeOperatorsRegistry App Repo](https://etherscan.io/address/0x0D97E876ad14DB2b183CFeEB8aa1A5C788eB1831#readProxyContract) and scroll down to `getLatest` method, open the dropdown and click "Query". This will give you the NodeOperatorsRegistry app version, contract address and the content URI. Now check that the content URI that you've obtained in the previous step matches the one that Etherscan fetched for you from the contract. + +### 3. Verifying client-side resources + +Now that we have the IPFS hash and content URI, let's see that it is, in fact, the one that's used on the DAO website. + +Open the [StakingRouter app](https://mainnet.lido.fi/#/lido-dao/0x55032650b14df07b85bf18a3a3ec8e0af2e028d5/) in your browser, then open the network inspector and refresh the page to track all of the network requests that the website makes. + +You will find that one of the two HTML files has, in fact, been loaded from `https://ipfs.mainnet.fi/ipfs/QmaSSujHCGcnFuetAPGwVW5BegaMBvn5SCsgi3LSfvraSo/index.html`. + +You are done! ✨ diff --git a/apps/simple-dvt/app/.babelrc b/apps/simple-dvt/app/.babelrc new file mode 100644 index 000000000..13d2b95a1 --- /dev/null +++ b/apps/simple-dvt/app/.babelrc @@ -0,0 +1,30 @@ +{ + "presets": [ + [ + "@babel/preset-env", + { + "modules": false, + "targets": { + "browsers": [ + "> 1%", + "last 3 versions", + "ie >= 9", + "ios >= 8", + "android >= 4.2" + ] + }, + "useBuiltIns": "entry", + "corejs": 3, + "shippedProposals": true, + } + ] + ], + "plugins": [ + [ + "styled-components", + { + "displayName": true + } + ] + ] +} diff --git a/apps/simple-dvt/app/.eslintrc b/apps/simple-dvt/app/.eslintrc new file mode 100644 index 000000000..0f19e1dc6 --- /dev/null +++ b/apps/simple-dvt/app/.eslintrc @@ -0,0 +1,21 @@ +{ + "env": { + "browser": true, + "es6": true + }, + "extends": [ + "standard", + "standard-react", + "plugin:prettier/recommended", + "prettier/react" + ], + "parser": "babel-eslint", + "plugins": ["prettier", "react", "react-hooks"], + "rules": { + "valid-jsdoc": "error", + "react/prop-types": 0, + "linebreak-style": ["error", "unix"], + "react-hooks/rules-of-hooks": "error", + "react-hooks/exhaustive-deps": "warn" + } +} diff --git a/apps/simple-dvt/app/.gitignore b/apps/simple-dvt/app/.gitignore new file mode 100644 index 000000000..383b8ed65 --- /dev/null +++ b/apps/simple-dvt/app/.gitignore @@ -0,0 +1,31 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# cache +.cache + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build +/dist + +# misc +.env +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# built assets +/public/aragon-ui +/public/script.js +/public/script.map diff --git a/apps/simple-dvt/app/.prettierrc b/apps/simple-dvt/app/.prettierrc new file mode 100644 index 000000000..5824bbabb --- /dev/null +++ b/apps/simple-dvt/app/.prettierrc @@ -0,0 +1,7 @@ +{ + "singleQuote": true, + "semi": false, + "trailingComma": "es5", + "bracketSpacing": true, + "jsxBracketSameLine": false +} diff --git a/apps/simple-dvt/app/index.html b/apps/simple-dvt/app/index.html new file mode 100644 index 000000000..07f0586fb --- /dev/null +++ b/apps/simple-dvt/app/index.html @@ -0,0 +1,16 @@ + + + + + + + Aragon App + + + +
+ + + diff --git a/apps/simple-dvt/app/package.json b/apps/simple-dvt/app/package.json new file mode 100644 index 000000000..ddc3692cc --- /dev/null +++ b/apps/simple-dvt/app/package.json @@ -0,0 +1,50 @@ +{ + "name": "simple-dvt-frontend", + "version": "1.0.0", + "main": "src/index.js", + "dependencies": { + "@aragon/api": "^2.0.0", + "@aragon/api-react": "^2.0.0", + "@aragon/ui": "^1.7.0", + "core-js": "^3.6.5", + "formik": "^2.2.0", + "react": "^16.13.1", + "react-dom": "^16.13.1", + "regenerator-runtime": "^0.13.7", + "styled-components": "^5.2.0", + "yup": "^0.29.3" + }, + "devDependencies": { + "@babel/core": "^7.21.0", + "@babel/preset-env": "^7.11.5", + "@babel/preset-react": "^7.10.1", + "babel-eslint": "^10.1.0", + "babel-plugin-styled-components": "^1.11.1", + "copyfiles": "^2.3.0", + "eslint": "^8.34.0", + "eslint-config-prettier": "^8.6.0", + "eslint-config-standard": "^17.0.0", + "eslint-config-standard-react": "^9.2.0", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-react": "^7.20.6", + "eslint-plugin-react-hooks": "^4.1.2", + "eslint-plugin-standard": "^5.0.0", + "parcel-bundler": "^1.12.4", + "prettier": "^2.8.4" + }, + "scripts": { + "build": "yarn sync-assets && yarn build:app && yarn build:script", + "build:app": "parcel build index.html -d ../dist/ --public-url \".\" --no-cache", + "build:script": "parcel build src/script.js --out-dir ../dist/ --no-cache", + "watch:script": "parcel watch src/script.js --out-dir ../dist/ --no-hmr", + "serve": "parcel serve index.html --out-dir ../dist/ --no-cache", + "watch": "yarn watch:script", + "sync-assets": "copy-aragon-ui-assets ../dist && copyfiles -u 1 './public/**/*' ../dist", + "start": "yarn sync-assets && yarn watch:script & yarn serve", + "dev": "yarn sync-assets && yarn watch:script & yarn serve -- --port 3012", + "dev-fallback": "bash -c 'yarn sync-assets && yarn watch:script & yarn serve --port 3012'" + } +} diff --git a/apps/simple-dvt/app/public/meta/details.md b/apps/simple-dvt/app/public/meta/details.md new file mode 100644 index 000000000..fb71ccc9d --- /dev/null +++ b/apps/simple-dvt/app/public/meta/details.md @@ -0,0 +1,6 @@ +An application for Aragon. + +**Features** +- Feature \#1. +- Feature \#2. +- Feature \#3. diff --git a/apps/simple-dvt/app/public/meta/icon.svg b/apps/simple-dvt/app/public/meta/icon.svg new file mode 100644 index 000000000..546d85afe --- /dev/null +++ b/apps/simple-dvt/app/public/meta/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/simple-dvt/app/public/meta/screenshot-1.png b/apps/simple-dvt/app/public/meta/screenshot-1.png new file mode 100644 index 0000000000000000000000000000000000000000..b7f8176506eac1d9979ef359bb4691a97542a9b3 GIT binary patch literal 2297 zcmcgt`!^Gg16?0|()3XF_0h+(J zk>|vyJXb7XQZh?2c}+8$#^h7~#OI!K&pqd!d(OST-McO**d94$IRF5#2LZP`3joL* z1OWc<-Y)aYx$IqH`%6?@oZamQ1_tu;^XYVYRaI44Sy^FWVO?EaM@L6bPtO(A1Mpul zU<4c!1pw^r{>^Q9$M&iK06S9=c4yq<3zsIGNGhX$16&Ba((}U~Y#D{ybOpnmrA!6w z87-%{m#O84?eFPXo4H^@04ey`^;2!WxybZ;(9^Tm9G+Ht_H$_+;RzO}r zRAhbbix_xiybH+`5s6}~4f)5d)Wsvk8WGUeX6vnFPIA*cXeHi;+=7E<$(w?Okr(w^ z+l?3KXeMh)=WAoA4Kf?G?i*w?_A8K|K_zwo6Y@30dG8Yq$68{bouO@H^va2d(Mf&z z+O^Rtt_hg6auZaqtei!{5$wXq#AUqNx{@rFSkvyME>`TxNP6D8q>$V8IZ2{rBg5H8 zuwPm;xbbPJ;F^>_B!MY)1qd-~U)!%s+Bkh{apyE07>3e5e)d7|#j?vMwZTFIyRUH~ zGpa*bf-QN(00LmkfawsgldWXQXz)ZgE4 z?!P9FF0le?KKNeHK#=5B3$}Y}uq#xQ`W74U`e~W3p9c%d(bLmmQSW&#LBpZhJJ6Bv z&d}>@7|%jG)V%1nRk8C;kr6&8tE6`tk|vGz3IHuX74t1{Hwmd$i)!D^0*#}SGG~sk zanMfFtx2)o=1kxpPqGtEEloaJed^butkiKJDA^L+5dCpe8nv~hPv4>?>cz?snU22ClrlKHV@yk!puyuU>aoCP086Z8odF)1BI% z9XF(gl)EqZRlFkuDIN^Gqi4$T@WzoykD+GcAAJyD)nMWO81(Bo5)mI4s6Er&KYyvq4||D3$1Hv z%c;RLs}s)MWeKm*j!cA2&6B(f#nejL+pF?OXzyRfnsqrX2L0}b!7H#X7puW2R#aSz z-lcQB&Usl2hwSMUh9y)vs<+vb9lS;aGo4oycJgwI-o@LJt_&lv($oc4*f->p%QXwk zDINN!@ciL@oVkdGy*d{I+D}u~$wd9k!L!iLv2|Tj<=3uZ@v}kWn%&E1?#%m&6yv^- z=JJ_94C<1aQ-IuNeQ~0P>*E%24*s_62o-P0)nh(!nJ z`B}ZR){UuDh7l4T-*b`|bZU{`Fcj6G1~f1EU%0>cS^J$BoGB1}ci^=H)Uy^1rz~0H zEk5b0ektMlLC=@oO?fHK07Zstf)|!j^;UL$(Yl)|oh=|6W~2l?9@(-4QjC{r_2^)Q zNEH%3K^4RgvqhQYBRy4i5qyCZR>wT{M7_u3Jqbl4g0LR5^cz8CKckZ;BOyK?DMXBL zjhGXhh@l$|AXt$HntQ>523f)j7q3?EPp`c@L|2c6yYtDQ7%P8849zp)}e ze-bJbbUbO{x!U3iXxtH3f{)w#aUsGq!QiT@a2#T6seo->iz$d@ABdh3Ac2=K4|Ri{ z>rnd~`Hh}2$ZzJ)s_O$+ zl^%Y~*>^0xHpWAo)H|2eCrGj!XSry)jj`Q8E=s+#L9{_Lp0L#^9%fj5v|sZ*J8n*f zQ*mytG&^zsw4$X;pV4Du$YE{tbN(A&Sm$C}tA9obV3K?U(LB0v)kehTHI#Xm&%s@}w z8*W{1dp1~YN3CrG^Krth+V9aJxn0T9*@arKC5N#l0~b!a&9Mz-Q#qQY(#YXwd5wui zj!gUbfB5}-a?}sG`IAlcqG!w;Vl;U)k-kQ_5^7Cc!8L}%jqPHi{FCmi?xU=?%8v*# z5$>kg$p`caqs@-G4Qn+==0k%Wy(U;s@&@+4LyjaiIfbo}u-oPXg`kmao+Y_7^>qzA zm;Zp6Gi$EV6htURzc{A? { + const { appState } = useAragonApi() + const { appearance } = useGuiStyle() + const { isSyncing } = appState + + console.log(appState) + + const theme = useTheme() + + return ( +
+ + +
+ } secondary={} /> + +
+ ) +} + +export default App diff --git a/apps/simple-dvt/app/src/components/AddNodeOperatorSidePanel.js b/apps/simple-dvt/app/src/components/AddNodeOperatorSidePanel.js new file mode 100644 index 000000000..f705fba8b --- /dev/null +++ b/apps/simple-dvt/app/src/components/AddNodeOperatorSidePanel.js @@ -0,0 +1,76 @@ +import { Button, GU, SidePanel } from '@aragon/ui' +import React from 'react' +import { Formik, Field } from 'formik' +import * as yup from 'yup' +import TextField from './TextField' + +const initialValues = { + name: '', + address: '', +} + +const validationSchema = yup.object().shape({ + name: yup.string().required().min(1), + address: yup.string().required().min(1), +}) + +function PanelContent({ addNodeOperatorApi, onClose }) { + const onSubmit = ({ name, address }) => { + addNodeOperatorApi(name, address) + .catch(console.error) + .finally(() => { + onClose() + }) + } + + return ( + + {({ submitForm, isSubmitting, errors, values }) => { + return ( +
{ + e.preventDefault() + submitForm() + }} + > +
+              {JSON.stringify(errors, null, 2)}
+              {JSON.stringify(values, null, 2)}
+            
+ + + +