Finalize test migration: remove legacy dependencies and test helpers (#4797)

pull/4716/head
Hadrien Croubois 1 year ago committed by GitHub
parent abcf9dd8b7
commit a72c9561b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .github/ISSUE_TEMPLATE/bug_report.md
  2. 6
      .github/workflows/checks.yml
  3. 6
      .gitignore
  4. 2
      README.md
  5. 2
      contracts/proxy/README.adoc
  6. 2
      docs/modules/ROOT/pages/index.adoc
  7. 9
      docs/modules/ROOT/pages/utilities.adoc
  8. 2
      docs/modules/ROOT/pages/wizard.adoc
  9. 1
      hardhat.config.js
  10. 23
      hardhat/env-contract.js
  11. 17166
      package-lock.json
  12. 9
      package.json
  13. 2
      scripts/generate/templates/Checkpoints.js
  14. 20
      scripts/upgradeable/upgradeable.patch
  15. 62
      test/access/AccessControl.behavior.js
  16. 2
      test/access/AccessControl.test.js
  17. 18
      test/access/Ownable.test.js
  18. 22
      test/access/Ownable2Step.test.js
  19. 6
      test/access/extensions/AccessControlDefaultAdminRules.test.js
  20. 2
      test/access/extensions/AccessControlEnumerable.test.js
  21. 19
      test/access/manager/AccessManaged.test.js
  22. 10
      test/access/manager/AccessManager.behavior.js
  23. 11
      test/access/manager/AccessManager.predicate.js
  24. 191
      test/access/manager/AccessManager.test.js
  25. 1
      test/access/manager/AuthorityUtils.test.js
  26. 2
      test/finance/VestingWallet.behavior.js
  27. 10
      test/finance/VestingWallet.test.js
  28. 200
      test/governance/Governor.test.js
  29. 20
      test/governance/TimelockController.test.js
  30. 20
      test/governance/extensions/GovernorERC721.test.js
  31. 30
      test/governance/extensions/GovernorPreventLateQuorum.test.js
  32. 10
      test/governance/extensions/GovernorStorage.test.js
  33. 88
      test/governance/extensions/GovernorTimelockAccess.test.js
  34. 84
      test/governance/extensions/GovernorTimelockCompound.test.js
  35. 86
      test/governance/extensions/GovernorTimelockControl.test.js
  36. 20
      test/governance/extensions/GovernorVotesQuorumFraction.test.js
  37. 24
      test/governance/extensions/GovernorWithParams.test.js
  38. 4
      test/governance/utils/ERC6372.behavior.js
  39. 40
      test/governance/utils/Votes.behavior.js
  40. 12
      test/governance/utils/Votes.test.js
  41. 9
      test/helpers/access-manager.js
  42. 6
      test/helpers/chainid.js
  43. 5
      test/helpers/eip712.js
  44. 14
      test/helpers/enums.js
  45. 2
      test/helpers/governance.js
  46. 3
      test/helpers/math.js
  47. 22
      test/helpers/namespaced-storage.js
  48. 19
      test/helpers/storage.js
  49. 19
      test/helpers/time.js
  50. 2
      test/helpers/txpool.js
  51. 8
      test/metatx/ERC2771Context.test.js
  52. 6
      test/metatx/ERC2771Forwarder.test.js
  53. 34
      test/proxy/ERC1967/ERC1967Utils.test.js
  54. 6
      test/proxy/Proxy.behaviour.js
  55. 7
      test/proxy/beacon/BeaconProxy.test.js
  56. 14
      test/proxy/beacon/UpgradeableBeacon.test.js
  57. 13
      test/proxy/transparent/ProxyAdmin.test.js
  58. 34
      test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js
  59. 18
      test/proxy/utils/UUPSUpgradeable.test.js
  60. 6
      test/sanity.test.js
  61. 80
      test/token/ERC1155/ERC1155.behavior.js
  62. 14
      test/token/ERC1155/ERC1155.test.js
  63. 4
      test/token/ERC1155/extensions/ERC1155Burnable.test.js
  64. 2
      test/token/ERC1155/extensions/ERC1155Pausable.test.js
  65. 22
      test/token/ERC20/ERC20.behavior.js
  66. 22
      test/token/ERC20/ERC20.test.js
  67. 14
      test/token/ERC20/extensions/ERC20Burnable.test.js
  68. 36
      test/token/ERC20/extensions/ERC20FlashMint.test.js
  69. 6
      test/token/ERC20/extensions/ERC20Permit.test.js
  70. 50
      test/token/ERC20/extensions/ERC20Votes.test.js
  71. 38
      test/token/ERC20/extensions/ERC20Wrapper.test.js
  72. 150
      test/token/ERC20/extensions/ERC4626.test.js
  73. 24
      test/token/ERC20/utils/SafeERC20.test.js
  74. 70
      test/token/ERC721/ERC721.behavior.js
  75. 4
      test/token/ERC721/extensions/ERC721Burnable.test.js
  76. 22
      test/token/ERC721/extensions/ERC721Consecutive.test.js
  77. 2
      test/token/ERC721/extensions/ERC721Pausable.test.js
  78. 2
      test/token/ERC721/extensions/ERC721URIStorage.test.js
  79. 18
      test/token/ERC721/extensions/ERC721Votes.test.js
  80. 58
      test/token/ERC721/extensions/ERC721Wrapper.test.js
  81. 2
      test/token/ERC721/utils/ERC721Holder.test.js
  82. 14
      test/utils/Address.test.js
  83. 6
      test/utils/Context.behavior.js
  84. 4
      test/utils/Create2.test.js
  85. 8
      test/utils/Multicall.test.js
  86. 2
      test/utils/Nonces.test.js
  87. 4
      test/utils/Pausable.test.js
  88. 35
      test/utils/cryptography/ECDSA.test.js
  89. 3
      test/utils/cryptography/EIP712.test.js
  90. 2
      test/utils/introspection/ERC165.test.js
  91. 11
      test/utils/introspection/SupportsInterface.behavior.js
  92. 4
      test/utils/math/Math.test.js
  93. 2
      test/utils/math/SafeCast.test.js
  94. 2
      test/utils/math/SignedMath.test.js
  95. 2
      test/utils/structs/Checkpoints.test.js
  96. 14
      test/utils/types/Time.test.js

@ -10,7 +10,7 @@ about: Report a bug in OpenZeppelin Contracts
**💻 Environment**
<!-- Tell us what version of OpenZeppelin Contracts you're using, and how you're using it: Truffle, Remix, etc. -->
<!-- Tell us what version of OpenZeppelin Contracts you're using, and how you're using it: Hardhat, Remix, etc. -->
**📝 Details**

@ -34,8 +34,6 @@ jobs:
- uses: actions/checkout@v4
- name: Set up environment
uses: ./.github/actions/setup
- name: Compile contracts # TODO: Remove after migrating tests to ethers
run: npm run compile
- name: Run tests and generate gas report
run: npm run test
- name: Check linearisation of the inheritance graph
@ -64,8 +62,6 @@ jobs:
cp -rnT contracts lib/openzeppelin-contracts/contracts
- name: Transpile to upgradeable
run: bash scripts/upgradeable/transpile.sh
- name: Compile contracts # TODO: Remove after migrating tests to ethers
run: npm run compile
- name: Run tests
run: npm run test
- name: Check linearisation of the inheritance graph
@ -94,8 +90,6 @@ jobs:
- uses: actions/checkout@v4
- name: Set up environment
uses: ./.github/actions/setup
- name: Compile contracts # TODO: Remove after migrating tests to ethers
run: npm run compile
- name: Run coverage
run: npm run coverage
- uses: codecov/codecov-action@v3

6
.gitignore vendored

@ -29,15 +29,9 @@ npm-debug.log
# local env variables
.env
# truffle build directory
build/
# macOS
.DS_Store
# truffle
.node-xmlhttprequest-*
# IntelliJ IDE
.idea

@ -23,7 +23,7 @@
### Installation
#### Hardhat, Truffle (npm)
#### Hardhat (npm)
```
$ npm install @openzeppelin/contracts

@ -19,7 +19,7 @@ There are two alternative ways to add upgradeability to an ERC-1967 proxy. Their
- {TransparentUpgradeableProxy}: A proxy with a built-in immutable admin and upgrade interface.
- {UUPSUpgradeable}: An upgradeability mechanism to be included in the implementation contract.
CAUTION: Using upgradeable proxies correctly and securely is a difficult task that requires deep knowledge of the proxy pattern, Solidity, and the EVM. Unless you want a lot of low level control, we recommend using the xref:upgrades-plugins::index.adoc[OpenZeppelin Upgrades Plugins] for Truffle and Hardhat.
CAUTION: Using upgradeable proxies correctly and securely is a difficult task that requires deep knowledge of the proxy pattern, Solidity, and the EVM. Unless you want a lot of low level control, we recommend using the xref:upgrades-plugins::index.adoc[OpenZeppelin Upgrades Plugins] for Hardhat and Foundry.
A different family of proxies are beacon proxies. This pattern, popularized by Dharma, allows multiple proxies to be upgraded to a different implementation in a single transaction.

@ -13,7 +13,7 @@ IMPORTANT: OpenZeppelin Contracts uses semantic versioning to communicate backwa
[[install]]
=== Installation
==== Hardhat, Truffle (npm)
==== Hardhat (npm)
```console
$ npm install @openzeppelin/contracts

@ -186,16 +186,15 @@ contract Box is Multicall {
}
----
This is how to call the `multicall` function using Truffle, allowing `foo` and `bar` to be called in a single transaction:
This is how to call the `multicall` function using Ethers.js, allowing `foo` and `bar` to be called in a single transaction:
[source,javascript]
----
// scripts/foobar.js
const Box = artifacts.require('Box');
const instance = await Box.new();
const instance = await ethers.deployContract("Box");
await instance.multicall([
instance.contract.methods.foo().encodeABI(),
instance.contract.methods.bar().encodeABI()
instance.interface.encodeFunctionData("foo"),
instance.interface.encodeFunctionData("bar")
]);
----

@ -4,7 +4,7 @@
Not sure where to start? Use the interactive generator below to bootstrap your
contract and learn about the components offered in OpenZeppelin Contracts.
TIP: Place the resulting contract in your `contracts` directory in order to compile it with a tool like Hardhat or Truffle. Consider reading our guide on xref:learn::developing-smart-contracts.adoc[Developing Smart Contracts] for more guidance!
TIP: Place the resulting contract in your `contracts` or `src` directory in order to compile it with a tool like Hardhat or Foundry. Consider reading our guide on xref:learn::developing-smart-contracts.adoc[Developing Smart Contracts] for more guidance!
++++
<script async src="https://wizard.openzeppelin.com/build/embed.js"></script>

@ -55,7 +55,6 @@ const argv = require('yargs/yargs')()
},
}).argv;
require('@nomiclabs/hardhat-truffle5'); // deprecated
require('@nomicfoundation/hardhat-toolbox');
require('@nomicfoundation/hardhat-ethers');
require('hardhat-ignore-warnings');

@ -15,27 +15,4 @@ extendEnvironment(hre => {
const filteredSignersAsPromise = originalGetSigners().then(signers => signers.slice(1));
hre.ethers.getSigners = () => filteredSignersAsPromise;
}
// override hre.contract
const originalContract = hre.contract;
hre.contract = function (name, body) {
originalContract.call(this, name, accounts => {
let snapshot;
before(async function () {
// reset the state of the chain in between contract test suites
// TODO: this should be removed when migration to ethers is over
const { takeSnapshot } = require('@nomicfoundation/hardhat-network-helpers');
snapshot = await takeSnapshot();
});
after(async function () {
// reset the state of the chain in between contract test suites
// TODO: this should be removed when migration to ethers is over
await snapshot.restore();
});
body(accounts.slice(1));
});
};
});

17166
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -53,24 +53,18 @@
"@changesets/cli": "^2.26.0",
"@changesets/pre": "^2.0.0",
"@changesets/read": "^0.6.0",
"@nomicfoundation/hardhat-chai-matchers": "^2.0.2",
"@nomicfoundation/hardhat-chai-matchers": "^2.0.3",
"@nomicfoundation/hardhat-ethers": "^3.0.4",
"@nomicfoundation/hardhat-foundry": "^1.1.1",
"@nomicfoundation/hardhat-network-helpers": "^1.0.3",
"@nomicfoundation/hardhat-toolbox": "^4.0.0",
"@nomiclabs/hardhat-truffle5": "^2.0.5",
"@nomiclabs/hardhat-web3": "^2.0.0",
"@openzeppelin/docs-utils": "^0.1.5",
"@openzeppelin/merkle-tree": "^1.0.5",
"@openzeppelin/test-helpers": "^0.5.13",
"@openzeppelin/upgrade-safe-transpiler": "^0.3.32",
"@openzeppelin/upgrades-core": "^1.20.6",
"chai": "^4.2.0",
"eslint": "^8.30.0",
"eslint-config-prettier": "^9.0.0",
"eth-sig-util": "^3.0.0",
"ethereumjs-util": "^7.0.7",
"ethereumjs-wallet": "^1.0.1",
"ethers": "^6.7.1",
"glob": "^10.3.5",
"graphlib": "^2.1.8",
@ -91,7 +85,6 @@
"solidity-coverage": "^0.8.5",
"solidity-docgen": "^0.6.0-beta.29",
"undici": "^5.22.1",
"web3": "^1.3.0",
"yargs": "^17.0.0"
}
}

@ -1,5 +1,5 @@
const format = require('../format-lines');
const { OPTS } = require('./Checkpoints.opts.js');
const { OPTS } = require('./Checkpoints.opts');
// TEMPLATE
const header = `\

@ -1,6 +1,6 @@
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index 2797a0889..000000000
index 35ad097ff..000000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,21 +0,0 @@
@ -16,7 +16,7 @@ index 2797a0889..000000000
-
-**💻 Environment**
-
-<!-- Tell us what version of OpenZeppelin Contracts you're using, and how you're using it: Truffle, Remix, etc. -->
-<!-- Tell us what version of OpenZeppelin Contracts you're using, and how you're using it: Hardhat, Remix, etc. -->
-
-**📝 Details**
-
@ -59,7 +59,7 @@ index ff596b0c3..000000000
-<!-- Make sure that you have reviewed the OpenZeppelin Contracts Contributor Guidelines. -->
-<!-- https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CONTRIBUTING.md -->
diff --git a/README.md b/README.md
index 9ca41573f..57d6e3b5b 100644
index 35083bc6e..05cf4fc27 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,9 @@
@ -73,7 +73,7 @@ index 9ca41573f..57d6e3b5b 100644
### Installation
@@ -26,7 +29,7 @@
#### Hardhat, Truffle (npm)
#### Hardhat (npm)
```
-$ npm install @openzeppelin/contracts
@ -110,7 +110,7 @@ index 9ca41573f..57d6e3b5b 100644
}
```
diff --git a/contracts/package.json b/contracts/package.json
index be3e741e3..877e942c2 100644
index 6ab89138a..ece834a44 100644
--- a/contracts/package.json
+++ b/contracts/package.json
@@ -1,5 +1,5 @@
@ -118,7 +118,7 @@ index be3e741e3..877e942c2 100644
- "name": "@openzeppelin/contracts",
+ "name": "@openzeppelin/contracts-upgradeable",
"description": "Secure Smart Contract library for Solidity",
"version": "5.0.0",
"version": "5.0.1",
"files": [
@@ -13,7 +13,7 @@
},
@ -140,7 +140,7 @@ index be3e741e3..877e942c2 100644
+ }
}
diff --git a/contracts/utils/cryptography/EIP712.sol b/contracts/utils/cryptography/EIP712.sol
index 8e548cdd8..a60ee74fd 100644
index 77c4c8990..602467f40 100644
--- a/contracts/utils/cryptography/EIP712.sol
+++ b/contracts/utils/cryptography/EIP712.sol
@@ -4,7 +4,6 @@
@ -307,7 +307,7 @@ index 8e548cdd8..a60ee74fd 100644
}
}
diff --git a/package.json b/package.json
index c2c3a2675..3301b213d 100644
index ec2c44ced..46eedc98f 100644
--- a/package.json
+++ b/package.json
@@ -32,7 +32,7 @@
@ -328,10 +328,10 @@ index 304d1386a..a1cd63bee 100644
+@openzeppelin/contracts-upgradeable/=contracts/
+@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
diff --git a/test/utils/cryptography/EIP712.test.js b/test/utils/cryptography/EIP712.test.js
index 75ca00b12..265e6c909 100644
index 166038b36..268e0d29d 100644
--- a/test/utils/cryptography/EIP712.test.js
+++ b/test/utils/cryptography/EIP712.test.js
@@ -40,27 +40,6 @@ describe('EIP712', function () {
@@ -47,27 +47,6 @@ describe('EIP712', function () {
const rebuildDomain = await getDomain(this.eip712);
expect(rebuildDomain).to.be.deep.equal(this.domain);
});

@ -1,7 +1,7 @@
const { ethers } = require('hardhat');
const { expect } = require('chai');
const { bigint: time } = require('../helpers/time');
const time = require('../helpers/time');
const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior');
@ -38,7 +38,7 @@ function shouldBehaveLikeAccessControl() {
it('non-admin cannot grant role to other accounts', async function () {
await expect(this.mock.connect(this.other).grantRole(ROLE, this.authorized))
.to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount')
.withArgs(this.other.address, DEFAULT_ADMIN_ROLE);
.withArgs(this.other, DEFAULT_ADMIN_ROLE);
});
it('accounts can be granted a role multiple times', async function () {
@ -68,7 +68,7 @@ function shouldBehaveLikeAccessControl() {
it('admin can revoke role', async function () {
await expect(this.mock.connect(this.defaultAdmin).revokeRole(ROLE, this.authorized))
.to.emit(this.mock, 'RoleRevoked')
.withArgs(ROLE, this.authorized.address, this.defaultAdmin.address);
.withArgs(ROLE, this.authorized, this.defaultAdmin);
expect(await this.mock.hasRole(ROLE, this.authorized)).to.equal(false);
});
@ -76,7 +76,7 @@ function shouldBehaveLikeAccessControl() {
it('non-admin cannot revoke role', async function () {
await expect(this.mock.connect(this.other).revokeRole(ROLE, this.authorized))
.to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount')
.withArgs(this.other.address, DEFAULT_ADMIN_ROLE);
.withArgs(this.other, DEFAULT_ADMIN_ROLE);
});
it('a role can be revoked multiple times', async function () {
@ -106,7 +106,7 @@ function shouldBehaveLikeAccessControl() {
it('bearer can renounce role', async function () {
await expect(this.mock.connect(this.authorized).renounceRole(ROLE, this.authorized))
.to.emit(this.mock, 'RoleRevoked')
.withArgs(ROLE, this.authorized.address, this.authorized.address);
.withArgs(ROLE, this.authorized, this.authorized);
expect(await this.mock.hasRole(ROLE, this.authorized)).to.equal(false);
});
@ -145,26 +145,26 @@ function shouldBehaveLikeAccessControl() {
it('the new admin can grant roles', async function () {
await expect(this.mock.connect(this.otherAdmin).grantRole(ROLE, this.authorized))
.to.emit(this.mock, 'RoleGranted')
.withArgs(ROLE, this.authorized.address, this.otherAdmin.address);
.withArgs(ROLE, this.authorized, this.otherAdmin);
});
it('the new admin can revoke roles', async function () {
await this.mock.connect(this.otherAdmin).grantRole(ROLE, this.authorized);
await expect(this.mock.connect(this.otherAdmin).revokeRole(ROLE, this.authorized))
.to.emit(this.mock, 'RoleRevoked')
.withArgs(ROLE, this.authorized.address, this.otherAdmin.address);
.withArgs(ROLE, this.authorized, this.otherAdmin);
});
it("a role's previous admins no longer grant roles", async function () {
await expect(this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.authorized))
.to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount')
.withArgs(this.defaultAdmin.address, OTHER_ROLE);
.withArgs(this.defaultAdmin, OTHER_ROLE);
});
it("a role's previous admins no longer revoke roles", async function () {
await expect(this.mock.connect(this.defaultAdmin).revokeRole(ROLE, this.authorized))
.to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount')
.withArgs(this.defaultAdmin.address, OTHER_ROLE);
.withArgs(this.defaultAdmin, OTHER_ROLE);
});
});
@ -180,13 +180,13 @@ function shouldBehaveLikeAccessControl() {
it("revert if sender doesn't have role #1", async function () {
await expect(this.mock.connect(this.other).$_checkRole(ROLE))
.to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount')
.withArgs(this.other.address, ROLE);
.withArgs(this.other, ROLE);
});
it("revert if sender doesn't have role #2", async function () {
await expect(this.mock.connect(this.authorized).$_checkRole(OTHER_ROLE))
.to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount')
.withArgs(this.authorized.address, OTHER_ROLE);
.withArgs(this.authorized, OTHER_ROLE);
});
});
@ -271,7 +271,7 @@ function shouldBehaveLikeAccessControlDefaultAdminRules() {
describe(`${getter}()`, function () {
it('has a default set to the initial default admin', async function () {
const value = await this.mock[getter]();
expect(value).to.equal(this.defaultAdmin.address);
expect(value).to.equal(this.defaultAdmin);
expect(await this.mock.hasRole(DEFAULT_ADMIN_ROLE, value)).to.be.true;
});
@ -284,7 +284,7 @@ function shouldBehaveLikeAccessControlDefaultAdminRules() {
await this.mock.connect(this.newDefaultAdmin).acceptDefaultAdminTransfer();
const value = await this.mock[getter]();
expect(value).to.equal(this.newDefaultAdmin.address);
expect(value).to.equal(this.newDefaultAdmin);
});
});
}
@ -312,7 +312,7 @@ function shouldBehaveLikeAccessControlDefaultAdminRules() {
await time.increaseTo.timestamp(firstSchedule + fromSchedule);
const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin();
expect(newAdmin).to.equal(this.newDefaultAdmin.address);
expect(newAdmin).to.equal(this.newDefaultAdmin);
expect(schedule).to.equal(firstSchedule);
});
}
@ -429,7 +429,7 @@ function shouldBehaveLikeAccessControlDefaultAdminRules() {
it('reverts if called by non default admin accounts', async function () {
await expect(this.mock.connect(this.other).beginDefaultAdminTransfer(this.newDefaultAdmin))
.to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount')
.withArgs(this.other.address, DEFAULT_ADMIN_ROLE);
.withArgs(this.other, DEFAULT_ADMIN_ROLE);
});
describe('when there is no pending delay nor pending admin transfer', function () {
@ -440,10 +440,10 @@ function shouldBehaveLikeAccessControlDefaultAdminRules() {
await time.increaseTo.timestamp(nextBlockTimestamp, false); // set timestamp but don't mine the block yet
await expect(this.mock.connect(this.defaultAdmin).beginDefaultAdminTransfer(this.newDefaultAdmin))
.to.emit(this.mock, 'DefaultAdminTransferScheduled')
.withArgs(this.newDefaultAdmin.address, acceptSchedule);
.withArgs(this.newDefaultAdmin, acceptSchedule);
const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin();
expect(newAdmin).to.equal(this.newDefaultAdmin.address);
expect(newAdmin).to.equal(this.newDefaultAdmin);
expect(schedule).to.equal(acceptSchedule);
});
});
@ -470,7 +470,7 @@ function shouldBehaveLikeAccessControlDefaultAdminRules() {
);
const newSchedule = (await time.clock.timestamp()) + this.delay;
const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin();
expect(newAdmin).to.equal(this.other.address);
expect(newAdmin).to.equal(this.other);
expect(schedule).to.equal(newSchedule);
});
}
@ -513,11 +513,11 @@ function shouldBehaveLikeAccessControlDefaultAdminRules() {
const expectedAcceptSchedule = nextBlockTimestamp + expectedDelay;
await expect(this.mock.connect(this.defaultAdmin).beginDefaultAdminTransfer(this.newDefaultAdmin))
.to.emit(this.mock, 'DefaultAdminTransferScheduled')
.withArgs(this.newDefaultAdmin.address, expectedAcceptSchedule);
.withArgs(this.newDefaultAdmin, expectedAcceptSchedule);
// Check that the schedule corresponds with the new delay
const { newAdmin, schedule: transferSchedule } = await this.mock.pendingDefaultAdmin();
expect(newAdmin).to.equal(this.newDefaultAdmin.address);
expect(newAdmin).to.equal(this.newDefaultAdmin);
expect(transferSchedule).to.equal(expectedAcceptSchedule);
});
}
@ -534,7 +534,7 @@ function shouldBehaveLikeAccessControlDefaultAdminRules() {
await time.increaseTo.timestamp(this.acceptSchedule + 1n, false);
await expect(this.mock.connect(this.other).acceptDefaultAdminTransfer())
.to.be.revertedWithCustomError(this.mock, 'AccessControlInvalidDefaultAdmin')
.withArgs(this.other.address);
.withArgs(this.other);
});
describe('when caller is pending default admin and delay has passed', function () {
@ -546,14 +546,14 @@ function shouldBehaveLikeAccessControlDefaultAdminRules() {
// Emit events
await expect(this.mock.connect(this.newDefaultAdmin).acceptDefaultAdminTransfer())
.to.emit(this.mock, 'RoleRevoked')
.withArgs(DEFAULT_ADMIN_ROLE, this.defaultAdmin.address, this.newDefaultAdmin.address)
.withArgs(DEFAULT_ADMIN_ROLE, this.defaultAdmin, this.newDefaultAdmin)
.to.emit(this.mock, 'RoleGranted')
.withArgs(DEFAULT_ADMIN_ROLE, this.newDefaultAdmin.address, this.newDefaultAdmin.address);
.withArgs(DEFAULT_ADMIN_ROLE, this.newDefaultAdmin, this.newDefaultAdmin);
// Storage changes
expect(await this.mock.hasRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin)).to.be.false;
expect(await this.mock.hasRole(DEFAULT_ADMIN_ROLE, this.newDefaultAdmin)).to.be.true;
expect(await this.mock.owner()).to.equal(this.newDefaultAdmin.address);
expect(await this.mock.owner()).to.equal(this.newDefaultAdmin);
// Resets pending default admin and schedule
const { newAdmin, schedule } = await this.mock.pendingDefaultAdmin();
@ -581,7 +581,7 @@ function shouldBehaveLikeAccessControlDefaultAdminRules() {
it('reverts if called by non default admin accounts', async function () {
await expect(this.mock.connect(this.other).cancelDefaultAdminTransfer())
.to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount')
.withArgs(this.other.address, DEFAULT_ADMIN_ROLE);
.withArgs(this.other, DEFAULT_ADMIN_ROLE);
});
describe('when there is a pending default admin transfer', function () {
@ -619,7 +619,7 @@ function shouldBehaveLikeAccessControlDefaultAdminRules() {
// Previous pending default admin should not be able to accept after cancellation.
await expect(this.mock.connect(this.newDefaultAdmin).acceptDefaultAdminTransfer())
.to.be.revertedWithCustomError(this.mock, 'AccessControlInvalidDefaultAdmin')
.withArgs(this.newDefaultAdmin.address);
.withArgs(this.newDefaultAdmin);
});
});
@ -666,14 +666,14 @@ function shouldBehaveLikeAccessControlDefaultAdminRules() {
await this.mock.connect(this.other).renounceRole(DEFAULT_ADMIN_ROLE, this.other);
expect(await this.mock.hasRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin)).to.be.true;
expect(await this.mock.defaultAdmin()).to.be.equal(this.defaultAdmin.address);
expect(await this.mock.defaultAdmin()).to.be.equal(this.defaultAdmin);
});
it('renounces role', async function () {
await time.increaseBy.timestamp(this.delay + 1n, false);
await expect(this.mock.connect(this.defaultAdmin).renounceRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin))
.to.emit(this.mock, 'RoleRevoked')
.withArgs(DEFAULT_ADMIN_ROLE, this.defaultAdmin.address, this.defaultAdmin.address);
.withArgs(DEFAULT_ADMIN_ROLE, this.defaultAdmin, this.defaultAdmin);
expect(await this.mock.hasRole(DEFAULT_ADMIN_ROLE, this.defaultAdmin)).to.be.false;
expect(await this.mock.defaultAdmin()).to.be.equal(ethers.ZeroAddress);
@ -690,7 +690,7 @@ function shouldBehaveLikeAccessControlDefaultAdminRules() {
await expect(this.mock.connect(this.defaultAdmin).$_grantRole(DEFAULT_ADMIN_ROLE, this.other))
.to.emit(this.mock, 'RoleGranted')
.withArgs(DEFAULT_ADMIN_ROLE, this.other.address, this.defaultAdmin.address);
.withArgs(DEFAULT_ADMIN_ROLE, this.other, this.defaultAdmin);
});
describe('schedule not passed', function () {
@ -712,7 +712,7 @@ function shouldBehaveLikeAccessControlDefaultAdminRules() {
it('reverts if called by non default admin accounts', async function () {
await expect(this.mock.connect(this.other).changeDefaultAdminDelay(time.duration.hours(4)))
.to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount')
.withArgs(this.other.address, DEFAULT_ADMIN_ROLE);
.withArgs(this.other, DEFAULT_ADMIN_ROLE);
});
for (const [delayDifference, delayChangeType] of [
@ -810,7 +810,7 @@ function shouldBehaveLikeAccessControlDefaultAdminRules() {
it('reverts if called by non default admin accounts', async function () {
await expect(this.mock.connect(this.other).rollbackDefaultAdminDelay())
.to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount')
.withArgs(this.other.address, DEFAULT_ADMIN_ROLE);
.withArgs(this.other, DEFAULT_ADMIN_ROLE);
});
describe('when there is a pending delay', function () {

@ -1,7 +1,7 @@
const { ethers } = require('hardhat');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { DEFAULT_ADMIN_ROLE, shouldBehaveLikeAccessControl } = require('./AccessControl.behavior.js');
const { DEFAULT_ADMIN_ROLE, shouldBehaveLikeAccessControl } = require('./AccessControl.behavior');
async function fixture() {
const [defaultAdmin, ...accounts] = await ethers.getSigners();

@ -16,7 +16,7 @@ describe('Ownable', function () {
it('emits ownership transfer events during construction', async function () {
await expect(this.ownable.deploymentTransaction())
.to.emit(this.ownable, 'OwnershipTransferred')
.withArgs(ethers.ZeroAddress, this.owner.address);
.withArgs(ethers.ZeroAddress, this.owner);
});
it('rejects zero address for initialOwner', async function () {
@ -26,22 +26,22 @@ describe('Ownable', function () {
});
it('has an owner', async function () {
expect(await this.ownable.owner()).to.equal(this.owner.address);
expect(await this.ownable.owner()).to.equal(this.owner);
});
describe('transfer ownership', function () {
it('changes owner after transfer', async function () {
await expect(this.ownable.connect(this.owner).transferOwnership(this.other))
.to.emit(this.ownable, 'OwnershipTransferred')
.withArgs(this.owner.address, this.other.address);
.withArgs(this.owner, this.other);
expect(await this.ownable.owner()).to.equal(this.other.address);
expect(await this.ownable.owner()).to.equal(this.other);
});
it('prevents non-owners from transferring', async function () {
await expect(this.ownable.connect(this.other).transferOwnership(this.other))
.to.be.revertedWithCustomError(this.ownable, 'OwnableUnauthorizedAccount')
.withArgs(this.other.address);
.withArgs(this.other);
});
it('guards ownership against stuck state', async function () {
@ -55,7 +55,7 @@ describe('Ownable', function () {
it('loses ownership after renouncement', async function () {
await expect(this.ownable.connect(this.owner).renounceOwnership())
.to.emit(this.ownable, 'OwnershipTransferred')
.withArgs(this.owner.address, ethers.ZeroAddress);
.withArgs(this.owner, ethers.ZeroAddress);
expect(await this.ownable.owner()).to.equal(ethers.ZeroAddress);
});
@ -63,7 +63,7 @@ describe('Ownable', function () {
it('prevents non-owners from renouncement', async function () {
await expect(this.ownable.connect(this.other).renounceOwnership())
.to.be.revertedWithCustomError(this.ownable, 'OwnableUnauthorizedAccount')
.withArgs(this.other.address);
.withArgs(this.other);
});
it('allows to recover access using the internal _transferOwnership', async function () {
@ -71,9 +71,9 @@ describe('Ownable', function () {
await expect(this.ownable.$_transferOwnership(this.other))
.to.emit(this.ownable, 'OwnershipTransferred')
.withArgs(ethers.ZeroAddress, this.other.address);
.withArgs(ethers.ZeroAddress, this.other);
expect(await this.ownable.owner()).to.equal(this.other.address);
expect(await this.ownable.owner()).to.equal(this.other);
});
});
});

@ -22,10 +22,10 @@ describe('Ownable2Step', function () {
it('starting a transfer does not change owner', async function () {
await expect(this.ownable2Step.connect(this.owner).transferOwnership(this.accountA))
.to.emit(this.ownable2Step, 'OwnershipTransferStarted')
.withArgs(this.owner.address, this.accountA.address);
.withArgs(this.owner, this.accountA);
expect(await this.ownable2Step.owner()).to.equal(this.owner.address);
expect(await this.ownable2Step.pendingOwner()).to.equal(this.accountA.address);
expect(await this.ownable2Step.owner()).to.equal(this.owner);
expect(await this.ownable2Step.pendingOwner()).to.equal(this.accountA);
});
it('changes owner after transfer', async function () {
@ -33,9 +33,9 @@ describe('Ownable2Step', function () {
await expect(this.ownable2Step.connect(this.accountA).acceptOwnership())
.to.emit(this.ownable2Step, 'OwnershipTransferred')
.withArgs(this.owner.address, this.accountA.address);
.withArgs(this.owner, this.accountA);
expect(await this.ownable2Step.owner()).to.equal(this.accountA.address);
expect(await this.ownable2Step.owner()).to.equal(this.accountA);
expect(await this.ownable2Step.pendingOwner()).to.equal(ethers.ZeroAddress);
});
@ -44,7 +44,7 @@ describe('Ownable2Step', function () {
await expect(this.ownable2Step.connect(this.accountB).acceptOwnership())
.to.be.revertedWithCustomError(this.ownable2Step, 'OwnableUnauthorizedAccount')
.withArgs(this.accountB.address);
.withArgs(this.accountB);
});
});
@ -52,7 +52,7 @@ describe('Ownable2Step', function () {
it('changes owner after renouncing ownership', async function () {
await expect(this.ownable2Step.connect(this.owner).renounceOwnership())
.to.emit(this.ownable2Step, 'OwnershipTransferred')
.withArgs(this.owner.address, ethers.ZeroAddress);
.withArgs(this.owner, ethers.ZeroAddress);
// If renounceOwnership is removed from parent an alternative is needed ...
// without it is difficult to cleanly renounce with the two step process
@ -62,14 +62,14 @@ describe('Ownable2Step', function () {
it('pending owner resets after renouncing ownership', async function () {
await this.ownable2Step.connect(this.owner).transferOwnership(this.accountA);
expect(await this.ownable2Step.pendingOwner()).to.equal(this.accountA.address);
expect(await this.ownable2Step.pendingOwner()).to.equal(this.accountA);
await this.ownable2Step.connect(this.owner).renounceOwnership();
expect(await this.ownable2Step.pendingOwner()).to.equal(ethers.ZeroAddress);
await expect(this.ownable2Step.connect(this.accountA).acceptOwnership())
.to.be.revertedWithCustomError(this.ownable2Step, 'OwnableUnauthorizedAccount')
.withArgs(this.accountA.address);
.withArgs(this.accountA);
});
it('allows to recover access using the internal _transferOwnership', async function () {
@ -77,9 +77,9 @@ describe('Ownable2Step', function () {
await expect(this.ownable2Step.$_transferOwnership(this.accountA))
.to.emit(this.ownable2Step, 'OwnershipTransferred')
.withArgs(ethers.ZeroAddress, this.accountA.address);
.withArgs(ethers.ZeroAddress, this.accountA);
expect(await this.ownable2Step.owner()).to.equal(this.accountA.address);
expect(await this.ownable2Step.owner()).to.equal(this.accountA);
});
});
});

@ -1,11 +1,13 @@
const { ethers } = require('hardhat');
const { expect } = require('chai');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { bigint: time } = require('../../helpers/time');
const time = require('../../helpers/time');
const {
shouldBehaveLikeAccessControl,
shouldBehaveLikeAccessControlDefaultAdminRules,
} = require('../AccessControl.behavior.js');
} = require('../AccessControl.behavior');
async function fixture() {
const delay = time.duration.hours(10);

@ -5,7 +5,7 @@ const {
DEFAULT_ADMIN_ROLE,
shouldBehaveLikeAccessControl,
shouldBehaveLikeAccessControlEnumerable,
} = require('../AccessControl.behavior.js');
} = require('../AccessControl.behavior');
async function fixture() {
const [defaultAdmin, ...accounts] = await ethers.getSigners();

@ -1,8 +1,9 @@
const { ethers } = require('hardhat');
const { expect } = require('chai');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { impersonate } = require('../../helpers/account');
const { bigint: time } = require('../../helpers/time');
const time = require('../../helpers/time');
async function fixture() {
const [admin, roleMember, other] = await ethers.getSigners();
@ -35,7 +36,7 @@ describe('AccessManaged', function () {
it('sets authority and emits AuthorityUpdated event during construction', async function () {
await expect(this.managed.deploymentTransaction())
.to.emit(this.managed, 'AuthorityUpdated')
.withArgs(this.authority.target);
.withArgs(this.authority);
});
describe('restricted modifier', function () {
@ -53,7 +54,7 @@ describe('AccessManaged', function () {
it('reverts when role is not granted', async function () {
await expect(this.managed.connect(this.other)[this.selector]())
.to.be.revertedWithCustomError(this.managed, 'AccessManagedUnauthorized')
.withArgs(this.other.address);
.withArgs(this.other);
});
it('panics in short calldata', async function () {
@ -103,21 +104,21 @@ describe('AccessManaged', function () {
it('reverts if the caller is not the authority', async function () {
await expect(this.managed.connect(this.other).setAuthority(this.other))
.to.be.revertedWithCustomError(this.managed, 'AccessManagedUnauthorized')
.withArgs(this.other.address);
.withArgs(this.other);
});
it('reverts if the new authority is not a valid authority', async function () {
await expect(this.managed.connect(this.authorityAsSigner).setAuthority(this.other))
.to.be.revertedWithCustomError(this.managed, 'AccessManagedInvalidAuthority')
.withArgs(this.other.address);
.withArgs(this.other);
});
it('sets authority and emits AuthorityUpdated event', async function () {
await expect(this.managed.connect(this.authorityAsSigner).setAuthority(this.anotherAuthority))
.to.emit(this.managed, 'AuthorityUpdated')
.withArgs(this.anotherAuthority.target);
.withArgs(this.anotherAuthority);
expect(await this.managed.authority()).to.equal(this.anotherAuthority.target);
expect(await this.managed.authority()).to.equal(this.anotherAuthority);
});
});
@ -136,7 +137,7 @@ describe('AccessManaged', function () {
await expect(this.managed.connect(this.other).fnRestricted())
.to.emit(this.authorityObserveIsConsuming, 'ConsumeScheduledOpCalled')
.withArgs(
this.other.address,
this.other,
this.managed.interface.encodeFunctionData(fnRestricted, []),
isConsumingScheduledOp.selector,
);

@ -1,3 +1,5 @@
const { expect } = require('chai');
const {
LIKE_COMMON_IS_EXECUTING,
LIKE_COMMON_GET_ACCESS,
@ -39,7 +41,7 @@ function shouldBehaveLikeDelayedAdminOperation() {
await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata }))
.to.be.revertedWithCustomError(this.target, 'AccessManagerUnauthorizedAccount')
.withArgs(
this.caller.address,
this.caller,
this.roles.ADMIN.id, // Although PUBLIC is required, target function role doesn't apply to admin ops
);
});
@ -83,7 +85,7 @@ function shouldBehaveLikeNotDelayedAdminOperation() {
await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata }))
.to.be.revertedWithCustomError(this.target, 'AccessManagerUnauthorizedAccount')
.withArgs(
this.caller.address,
this.caller,
this.roles.ADMIN.id, // Although PUBLIC_ROLE is required, admin ops are not subject to target function roles
);
});
@ -123,7 +125,7 @@ function shouldBehaveLikeRoleAdminOperation(roleAdmin) {
it('reverts as AccessManagerUnauthorizedAccount', async function () {
await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata }))
.to.be.revertedWithCustomError(this.target, 'AccessManagerUnauthorizedAccount')
.withArgs(this.caller.address, roleAdmin);
.withArgs(this.caller, roleAdmin);
});
},
specificRoleIsRequired: getAccessPath,
@ -142,7 +144,7 @@ function shouldBehaveLikeAManagedRestrictedOperation() {
it('reverts as AccessManagedUnauthorized', async function () {
await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata }))
.to.be.revertedWithCustomError(this.target, 'AccessManagedUnauthorized')
.withArgs(this.caller.address);
.withArgs(this.caller);
});
}

@ -1,9 +1,10 @@
const { ethers } = require('hardhat');
const { expect } = require('chai');
const { setStorageAt } = require('@nomicfoundation/hardhat-network-helpers');
const { EXECUTION_ID_STORAGE_SLOT, EXPIRATION, prepareOperation } = require('../../helpers/access-manager');
const { impersonate } = require('../../helpers/account');
const { bigint: time } = require('../../helpers/time');
const time = require('../../helpers/time');
// ============ COMMON PREDICATES ============
@ -17,7 +18,7 @@ const LIKE_COMMON_IS_EXECUTING = {
it('reverts as AccessManagerUnauthorizedAccount', async function () {
await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata }))
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedAccount')
.withArgs(this.caller.address, this.role.id);
.withArgs(this.caller, this.role.id);
});
},
};
@ -30,7 +31,7 @@ const LIKE_COMMON_GET_ACCESS = {
it('reverts as AccessManagerUnauthorizedAccount', async function () {
await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata }))
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedAccount')
.withArgs(this.caller.address, this.role.id);
.withArgs(this.caller, this.role.id);
});
},
afterGrantDelay: undefined, // Diverges if there's an operation delay or not
@ -40,7 +41,7 @@ const LIKE_COMMON_GET_ACCESS = {
it('reverts as AccessManagerUnauthorizedAccount', async function () {
await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata }))
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedAccount')
.withArgs(this.caller.address, this.role.id);
.withArgs(this.caller, this.role.id);
});
},
afterGrantDelay() {
@ -71,7 +72,7 @@ const LIKE_COMMON_GET_ACCESS = {
it('reverts as AccessManagerUnauthorizedAccount', async function () {
await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata }))
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedAccount')
.withArgs(this.caller.address, this.role.id);
.withArgs(this.caller, this.role.id);
});
},
};

@ -1,11 +1,11 @@
const { ethers } = require('hardhat');
const { expect } = require('chai');
const { loadFixture, getStorageAt } = require('@nomicfoundation/hardhat-network-helpers');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { impersonate } = require('../../helpers/account');
const { MAX_UINT48 } = require('../../helpers/constants');
const { bigint: time } = require('../../helpers/time');
const { selector } = require('../../helpers/methods');
const time = require('../../helpers/time');
const {
buildBaseRoles,
@ -17,12 +17,14 @@ const {
prepareOperation,
hashOperation,
} = require('../../helpers/access-manager');
const {
shouldBehaveLikeDelayedAdminOperation,
shouldBehaveLikeNotDelayedAdminOperation,
shouldBehaveLikeRoleAdminOperation,
shouldBehaveLikeAManagedRestrictedOperation,
} = require('./AccessManager.behavior');
const {
LIKE_COMMON_SCHEDULABLE,
testAsClosable,
@ -33,8 +35,6 @@ const {
testAsGetAccess,
} = require('./AccessManager.predicate');
const { address: someAddress } = ethers.Wallet.createRandom();
async function fixture() {
const [admin, roleAdmin, roleGuardian, member, user, other] = await ethers.getSigners();
@ -72,11 +72,8 @@ async function fixture() {
}
return {
// TODO: Check if all signers are actually used
admin,
roleAdmin,
roleGuardian,
member,
user,
other,
roles,
@ -99,9 +96,7 @@ async function fixture() {
// The predicates can be identified by the `testAs*` prefix while the behaviors
// are prefixed with `shouldBehave*`. The common assertions for predicates are
// defined as constants.
contract('AccessManager', function () {
// const [admin, manager, guardian, member, user, other] = accounts;
describe('AccessManager', function () {
beforeEach(async function () {
Object.assign(this, await loadFixture(fixture));
});
@ -144,7 +139,7 @@ contract('AccessManager', function () {
closed() {
it('should return false and no delay', async function () {
const { immediate, delay } = await this.manager.canCall(
someAddress,
this.other,
this.target,
this.calldata.substring(0, 10),
);
@ -763,11 +758,7 @@ contract('AccessManager', function () {
describe('#hashOperation', function () {
it('returns an operationId', async function () {
const calldata = '0x123543';
const address = someAddress;
const args = [this.user.address, address, calldata];
const args = [this.user, this.other, '0x123543'];
expect(await this.manager.hashOperation(...args)).to.equal(hashOperation(...args));
});
});
@ -980,7 +971,7 @@ contract('AccessManager', function () {
describe('#setTargetAdminDelay', function () {
describe('restrictions', function () {
beforeEach('set method and args', function () {
const args = [someAddress, time.duration.days(3)];
const args = [this.other.address, time.duration.days(3)];
const method = this.manager.interface.getFunction('setTargetAdminDelay(address,uint32)');
this.calldata = this.manager.interface.encodeFunctionData(method, args);
});
@ -991,50 +982,48 @@ contract('AccessManager', function () {
describe('when increasing the delay', function () {
const oldDelay = time.duration.days(10);
const newDelay = time.duration.days(11);
const target = someAddress;
beforeEach('sets old delay', async function () {
await this.manager.$_setTargetAdminDelay(target, oldDelay);
await this.manager.$_setTargetAdminDelay(this.other, oldDelay);
await time.increaseBy.timestamp(MINSETBACK);
expect(await this.manager.getTargetAdminDelay(target)).to.equal(oldDelay);
expect(await this.manager.getTargetAdminDelay(this.other)).to.equal(oldDelay);
});
it('increases the delay after minsetback', async function () {
const txResponse = await this.manager.connect(this.admin).setTargetAdminDelay(target, newDelay);
const txResponse = await this.manager.connect(this.admin).setTargetAdminDelay(this.other, newDelay);
const setTargetAdminDelayAt = await time.clockFromReceipt.timestamp(txResponse);
expect(txResponse)
.to.emit(this.manager, 'TargetAdminDelayUpdated')
.withArgs(target, newDelay, setTargetAdminDelayAt + MINSETBACK);
.withArgs(this.other, newDelay, setTargetAdminDelayAt + MINSETBACK);
expect(await this.manager.getTargetAdminDelay(target)).to.equal(oldDelay);
expect(await this.manager.getTargetAdminDelay(this.other)).to.equal(oldDelay);
await time.increaseBy.timestamp(MINSETBACK);
expect(await this.manager.getTargetAdminDelay(target)).to.equal(newDelay);
expect(await this.manager.getTargetAdminDelay(this.other)).to.equal(newDelay);
});
});
describe('when reducing the delay', function () {
const oldDelay = time.duration.days(10);
const target = someAddress;
beforeEach('sets old delay', async function () {
await this.manager.$_setTargetAdminDelay(target, oldDelay);
await this.manager.$_setTargetAdminDelay(this.other, oldDelay);
await time.increaseBy.timestamp(MINSETBACK);
expect(await this.manager.getTargetAdminDelay(target)).to.equal(oldDelay);
expect(await this.manager.getTargetAdminDelay(this.other)).to.equal(oldDelay);
});
describe('when the delay difference is shorter than minimum setback', function () {
const newDelay = oldDelay - 1n;
it('increases the delay after minsetback', async function () {
const txResponse = await this.manager.connect(this.admin).setTargetAdminDelay(target, newDelay);
const txResponse = await this.manager.connect(this.admin).setTargetAdminDelay(this.other, newDelay);
const setTargetAdminDelayAt = await time.clockFromReceipt.timestamp(txResponse);
expect(txResponse)
.to.emit(this.manager, 'TargetAdminDelayUpdated')
.withArgs(target, newDelay, setTargetAdminDelayAt + MINSETBACK);
.withArgs(this.other, newDelay, setTargetAdminDelayAt + MINSETBACK);
expect(await this.manager.getTargetAdminDelay(target)).to.equal(oldDelay);
expect(await this.manager.getTargetAdminDelay(this.other)).to.equal(oldDelay);
await time.increaseBy.timestamp(MINSETBACK);
expect(await this.manager.getTargetAdminDelay(target)).to.equal(newDelay);
expect(await this.manager.getTargetAdminDelay(this.other)).to.equal(newDelay);
});
});
@ -1048,16 +1037,16 @@ contract('AccessManager', function () {
it('increases the delay after delay difference', async function () {
const setback = oldDelay - newDelay;
const txResponse = await this.manager.connect(this.admin).setTargetAdminDelay(target, newDelay);
const txResponse = await this.manager.connect(this.admin).setTargetAdminDelay(this.other, newDelay);
const setTargetAdminDelayAt = await time.clockFromReceipt.timestamp(txResponse);
expect(txResponse)
.to.emit(this.manager, 'TargetAdminDelayUpdated')
.withArgs(target, newDelay, setTargetAdminDelayAt + setback);
.withArgs(this.other, newDelay, setTargetAdminDelayAt + setback);
expect(await this.manager.getTargetAdminDelay(target)).to.equal(oldDelay);
expect(await this.manager.getTargetAdminDelay(this.other)).to.equal(oldDelay);
await time.increaseBy.timestamp(setback);
expect(await this.manager.getTargetAdminDelay(target)).to.equal(newDelay);
expect(await this.manager.getTargetAdminDelay(this.other)).to.equal(newDelay);
});
});
});
@ -1083,20 +1072,20 @@ contract('AccessManager', function () {
});
it('changes the authority', async function () {
expect(await this.newManagedTarget.authority()).to.be.equal(this.manager.target);
expect(await this.newManagedTarget.authority()).to.be.equal(this.manager);
await expect(this.manager.connect(this.admin).updateAuthority(this.newManagedTarget, this.newAuthority))
.to.emit(this.newManagedTarget, 'AuthorityUpdated') // Managed contract is responsible of notifying the change through an event
.withArgs(this.newAuthority.target);
.withArgs(this.newAuthority);
expect(await this.newManagedTarget.authority()).to.be.equal(this.newAuthority.target);
expect(await this.newManagedTarget.authority()).to.be.equal(this.newAuthority);
});
});
describe('#setTargetClosed', function () {
describe('restrictions', function () {
beforeEach('set method and args', function () {
const args = [someAddress, true];
const args = [this.other.address, true];
const method = this.manager.interface.getFunction('setTargetClosed(address,bool)');
this.calldata = this.manager.interface.encodeFunctionData(method, args);
});
@ -1107,26 +1096,26 @@ contract('AccessManager', function () {
it('closes and opens a target', async function () {
await expect(this.manager.connect(this.admin).setTargetClosed(this.target, true))
.to.emit(this.manager, 'TargetClosed')
.withArgs(this.target.target, true);
.withArgs(this.target, true);
expect(await this.manager.isTargetClosed(this.target)).to.be.true;
await expect(this.manager.connect(this.admin).setTargetClosed(this.target, false))
.to.emit(this.manager, 'TargetClosed')
.withArgs(this.target.target, false);
.withArgs(this.target, false);
expect(await this.manager.isTargetClosed(this.target)).to.be.false;
});
it('reverts if closing the manager', async function () {
await expect(this.manager.connect(this.admin).setTargetClosed(this.manager, true))
.to.be.revertedWithCustomError(this.manager, 'AccessManagerLockedAccount')
.withArgs(this.manager.target);
.withArgs(this.manager);
});
});
describe('#setTargetFunctionRole', function () {
describe('restrictions', function () {
beforeEach('set method and args', function () {
const args = [someAddress, ['0x12345678'], 443342];
const args = [this.other.address, ['0x12345678'], 443342];
const method = this.manager.interface.getFunction('setTargetFunctionRole(address,bytes4[],uint64)');
this.calldata = this.manager.interface.encodeFunctionData(method, args);
});
@ -1148,7 +1137,7 @@ contract('AccessManager', function () {
for (const sig of sigs) {
expect(allowRole)
.to.emit(this.manager, 'TargetFunctionRoleUpdated')
.withArgs(this.target.target, sig, this.roles.SOME.id);
.withArgs(this.target, sig, this.roles.SOME.id);
expect(await this.manager.getTargetFunctionRole(this.target, sig)).to.equal(this.roles.SOME.id);
}
@ -1156,7 +1145,7 @@ contract('AccessManager', function () {
this.manager.connect(this.admin).setTargetFunctionRole(this.target, [sigs[1]], this.roles.SOME_ADMIN.id),
)
.to.emit(this.manager, 'TargetFunctionRoleUpdated')
.withArgs(this.target.target, sigs[1], this.roles.SOME_ADMIN.id);
.withArgs(this.target, sigs[1], this.roles.SOME_ADMIN.id);
for (const sig of sigs) {
expect(await this.manager.getTargetFunctionRole(this.target, sig)).to.equal(
@ -1182,7 +1171,7 @@ contract('AccessManager', function () {
describe('#grantRole', function () {
describe('restrictions', function () {
beforeEach('set method and args', function () {
const args = [ANOTHER_ROLE, someAddress, 0];
const args = [ANOTHER_ROLE, this.other.address, 0];
const method = this.manager.interface.getFunction('grantRole(uint64,address,uint32)');
this.calldata = this.manager.interface.encodeFunctionData(method, args);
});
@ -1291,7 +1280,7 @@ contract('AccessManager', function () {
const grantedAt = await time.clockFromReceipt.timestamp(txResponse);
expect(txResponse)
.to.emit(this.manager, 'RoleGranted')
.withArgs(ANOTHER_ROLE, this.user.address, executionDelay, grantedAt, true);
.withArgs(ANOTHER_ROLE, this.user, executionDelay, grantedAt, true);
// Access is correctly stored
const access = await this.manager.getAccess(ANOTHER_ROLE, this.user);
@ -1348,7 +1337,7 @@ contract('AccessManager', function () {
expect(txResponse)
.to.emit(this.manager, 'RoleGranted')
.withArgs(ANOTHER_ROLE, this.user.address, timestamp, this.newExecutionDelay, false);
.withArgs(ANOTHER_ROLE, this.user, timestamp, this.newExecutionDelay, false);
// Access is correctly stored
const access = await this.manager.getAccess(ANOTHER_ROLE, this.user);
@ -1384,13 +1373,7 @@ contract('AccessManager', function () {
it('emits event', function () {
expect(this.txResponse)
.to.emit(this.manager, 'RoleGranted')
.withArgs(
ANOTHER_ROLE,
this.user.address,
this.grantTimestamp + this.delay,
this.newExecutionDelay,
false,
);
.withArgs(ANOTHER_ROLE, this.user, this.grantTimestamp + this.delay, this.newExecutionDelay, false);
});
testAsDelay('execution delay effect', {
@ -1465,7 +1448,7 @@ contract('AccessManager', function () {
expect(txResponse)
.to.emit(this.manager, 'RoleGranted')
.withArgs(ANOTHER_ROLE, this.user.address, timestamp, this.newExecutionDelay, false);
.withArgs(ANOTHER_ROLE, this.user, timestamp, this.newExecutionDelay, false);
// Access is correctly stored
const access = await this.manager.getAccess(ANOTHER_ROLE, this.user);
@ -1501,13 +1484,7 @@ contract('AccessManager', function () {
it('emits event', function () {
expect(this.txResponse)
.to.emit(this.manager, 'RoleGranted')
.withArgs(
ANOTHER_ROLE,
this.user.address,
this.grantTimestamp + this.delay,
this.newExecutionDelay,
false,
);
.withArgs(ANOTHER_ROLE, this.user, this.grantTimestamp + this.delay, this.newExecutionDelay, false);
});
testAsDelay('execution delay effect', {
@ -1557,7 +1534,7 @@ contract('AccessManager', function () {
describe('#revokeRole', function () {
describe('restrictions', function () {
beforeEach('set method and args', async function () {
const args = [ANOTHER_ROLE, someAddress];
const args = [ANOTHER_ROLE, this.other.address];
const method = this.manager.interface.getFunction('revokeRole(uint64,address)');
this.calldata = this.manager.interface.encodeFunctionData(method, args);
@ -1588,7 +1565,7 @@ contract('AccessManager', function () {
await expect(this.manager.connect(this.admin).revokeRole(ANOTHER_ROLE, this.user))
.to.emit(this.manager, 'RoleRevoked')
.withArgs(ANOTHER_ROLE, this.user.address);
.withArgs(ANOTHER_ROLE, this.user);
expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([
false,
@ -1613,7 +1590,7 @@ contract('AccessManager', function () {
await expect(this.manager.connect(this.admin).revokeRole(ANOTHER_ROLE, this.user))
.to.emit(this.manager, 'RoleRevoked')
.withArgs(ANOTHER_ROLE, this.user.address);
.withArgs(ANOTHER_ROLE, this.user);
expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([
false,
@ -1670,7 +1647,7 @@ contract('AccessManager', function () {
]);
await expect(this.manager.connect(this.caller).renounceRole(this.role.id, this.caller))
.to.emit(this.manager, 'RoleRevoked')
.withArgs(this.role.id, this.caller.address);
.withArgs(this.role.id, this.caller);
expect(await this.manager.hasRole(this.role.id, this.caller).then(formatAccess)).to.be.deep.equal([
false,
'0',
@ -1685,7 +1662,7 @@ contract('AccessManager', function () {
it('reverts if renouncing with bad caller confirmation', async function () {
await expect(
this.manager.connect(this.caller).renounceRole(this.role.id, someAddress),
this.manager.connect(this.caller).renounceRole(this.role.id, this.other),
).to.be.revertedWithCustomError(this.manager, 'AccessManagerBadConfirmation');
});
});
@ -1719,7 +1696,7 @@ contract('AccessManager', function () {
}),
)
.to.emit(this.target, 'CalledRestricted')
.withArgs(this.user.address);
.withArgs(this.user);
});
});
@ -1742,7 +1719,7 @@ contract('AccessManager', function () {
}),
)
.to.emit(this.target, 'CalledUnrestricted')
.withArgs(this.user.address);
.withArgs(this.user);
});
});
});
@ -1772,7 +1749,7 @@ contract('AccessManager', function () {
});
await expect(schedule())
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall')
.withArgs(this.caller.address, this.target.target, this.calldata.substring(0, 10));
.withArgs(this.caller, this.target, this.calldata.substring(0, 10));
});
},
open: {
@ -1790,7 +1767,7 @@ contract('AccessManager', function () {
});
await expect(schedule())
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall')
.withArgs(this.caller.address, this.target.target, this.calldata.substring(0, 10));
.withArgs(this.caller, this.target, this.calldata.substring(0, 10));
});
},
},
@ -1800,7 +1777,7 @@ contract('AccessManager', function () {
// prepareOperation is not used here because it alters the next block timestamp
await expect(this.manager.connect(this.caller).schedule(this.target, this.calldata, MAX_UINT48))
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall')
.withArgs(this.caller.address, this.target.target, this.calldata.substring(0, 10));
.withArgs(this.caller, this.target, this.calldata.substring(0, 10));
});
},
specificRoleIsRequired: {
@ -1812,7 +1789,7 @@ contract('AccessManager', function () {
// prepareOperation is not used here because it alters the next block timestamp
await expect(this.manager.connect(this.caller).schedule(this.target, this.calldata, MAX_UINT48))
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall')
.withArgs(this.caller.address, this.target.target, this.calldata.substring(0, 10));
.withArgs(this.caller, this.target, this.calldata.substring(0, 10));
});
},
afterGrantDelay() {
@ -1828,7 +1805,7 @@ contract('AccessManager', function () {
// prepareOperation is not used here because it alters the next block timestamp
await expect(this.manager.connect(this.caller).schedule(this.target, this.calldata, MAX_UINT48))
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall')
.withArgs(this.caller.address, this.target.target, this.calldata.substring(0, 10));
.withArgs(this.caller, this.target, this.calldata.substring(0, 10));
});
},
afterGrantDelay() {
@ -1836,7 +1813,7 @@ contract('AccessManager', function () {
// prepareOperation is not used here because it alters the next block timestamp
await expect(this.manager.connect(this.caller).schedule(this.target, this.calldata, MAX_UINT48))
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall')
.withArgs(this.caller.address, this.target.target, this.calldata.substring(0, 10));
.withArgs(this.caller, this.target, this.calldata.substring(0, 10));
});
},
},
@ -1859,7 +1836,7 @@ contract('AccessManager', function () {
// prepareOperation is not used here because it alters the next block timestamp
await expect(this.manager.connect(this.caller).schedule(this.target, this.calldata, MAX_UINT48))
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall')
.withArgs(this.caller.address, this.target.target, this.calldata.substring(0, 10));
.withArgs(this.caller, this.target, this.calldata.substring(0, 10));
});
},
},
@ -1874,7 +1851,7 @@ contract('AccessManager', function () {
});
await expect(schedule())
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall')
.withArgs(this.caller.address, this.target.target, this.calldata.substring(0, 10));
.withArgs(this.caller, this.target, this.calldata.substring(0, 10));
});
},
},
@ -1896,7 +1873,7 @@ contract('AccessManager', function () {
expect(await this.manager.getSchedule(operationId)).to.equal(scheduledAt + this.delay);
expect(txResponse)
.to.emit(this.manager, 'OperationScheduled')
.withArgs(operationId, '1', scheduledAt + this.delay, this.target.target, this.calldata);
.withArgs(operationId, '1', scheduledAt + this.delay, this.target, this.calldata);
});
it('schedules an operation at the minimum execution date if no specified execution date (when == 0)', async function () {
@ -1911,7 +1888,7 @@ contract('AccessManager', function () {
expect(await this.manager.getSchedule(operationId)).to.equal(scheduledAt + executionDelay);
expect(txResponse)
.to.emit(this.manager, 'OperationScheduled')
.withArgs(operationId, '1', scheduledAt + executionDelay, this.target.target, this.calldata);
.withArgs(operationId, '1', scheduledAt + executionDelay, this.target, this.calldata);
});
it('increases the nonce of an operation scheduled more than once', async function () {
@ -1928,14 +1905,7 @@ contract('AccessManager', function () {
});
await expect(op1.schedule())
.to.emit(this.manager, 'OperationScheduled')
.withArgs(
op1.operationId,
1n,
op1.scheduledAt + this.delay,
this.caller.address,
this.target.target,
this.calldata,
);
.withArgs(op1.operationId, 1n, op1.scheduledAt + this.delay, this.caller, this.target, this.calldata);
expect(expectedOperationId).to.equal(op1.operationId);
// Consume
@ -1954,14 +1924,7 @@ contract('AccessManager', function () {
});
await expect(op2.schedule())
.to.emit(this.manager, 'OperationScheduled')
.withArgs(
op2.operationId,
2n,
op2.scheduledAt + this.delay,
this.caller.address,
this.target.target,
this.calldata,
);
.withArgs(op2.operationId, 2n, op2.scheduledAt + this.delay, this.caller, this.target, this.calldata);
expect(expectedOperationId).to.equal(op2.operationId);
// Check final nonce
@ -1981,7 +1944,7 @@ contract('AccessManager', function () {
await expect(schedule())
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall')
.withArgs(this.caller.address, this.target.target, this.calldata.substring(0, 10));
.withArgs(this.caller, this.target, this.calldata.substring(0, 10));
});
it('reverts if an operation is already schedule', async function () {
@ -2040,7 +2003,7 @@ contract('AccessManager', function () {
await expect(schedule())
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall')
.withArgs(this.caller.address, this.manager.target, calldata);
.withArgs(this.caller, this.manager, calldata);
});
});
@ -2062,7 +2025,7 @@ contract('AccessManager', function () {
it('reverts as AccessManagerUnauthorizedCall', async function () {
await expect(this.manager.connect(this.caller).execute(this.target, this.calldata))
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall')
.withArgs(this.caller.address, this.target.target, this.calldata.substring(0, 10));
.withArgs(this.caller, this.target, this.calldata.substring(0, 10));
});
},
open: {
@ -2076,7 +2039,7 @@ contract('AccessManager', function () {
it('reverts as AccessManagerUnauthorizedCall', async function () {
await expect(this.manager.connect(this.caller).execute(this.target, this.calldata))
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall')
.withArgs(this.caller.address, this.target.target, this.calldata.substring(0, 10));
.withArgs(this.caller, this.target, this.calldata.substring(0, 10));
});
},
},
@ -2094,7 +2057,7 @@ contract('AccessManager', function () {
it('reverts as AccessManagerUnauthorizedCall', async function () {
await expect(this.manager.connect(this.caller).execute(this.target, this.calldata))
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall')
.withArgs(this.caller.address, this.target.target, this.calldata.substring(0, 10));
.withArgs(this.caller, this.target, this.calldata.substring(0, 10));
});
},
afterGrantDelay: function self() {
@ -2112,7 +2075,7 @@ contract('AccessManager', function () {
it('reverts as AccessManagerUnauthorizedCall', async function () {
await expect(this.manager.connect(this.caller).execute(this.target, this.calldata))
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall')
.withArgs(this.caller.address, this.target.target, this.calldata.substring(0, 10));
.withArgs(this.caller, this.target, this.calldata.substring(0, 10));
});
},
afterGrantDelay: function self() {
@ -2143,7 +2106,7 @@ contract('AccessManager', function () {
it('reverts as AccessManagerUnauthorizedCall', async function () {
await expect(this.manager.connect(this.caller).execute(this.target, this.calldata))
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall')
.withArgs(this.caller.address, this.target.target, this.calldata.substring(0, 10));
.withArgs(this.caller, this.target, this.calldata.substring(0, 10));
});
},
},
@ -2197,9 +2160,9 @@ contract('AccessManager', function () {
});
it('keeps the original _executionId after finishing the call', async function () {
const executionIdBefore = await getStorageAt(this.manager.target, EXECUTION_ID_STORAGE_SLOT);
const executionIdBefore = await ethers.provider.getStorage(this.manager, EXECUTION_ID_STORAGE_SLOT);
await this.manager.connect(this.caller).execute(this.target, this.calldata);
const executionIdAfter = await getStorageAt(this.manager.target, EXECUTION_ID_STORAGE_SLOT);
const executionIdAfter = await ethers.provider.getStorage(this.manager, EXECUTION_ID_STORAGE_SLOT);
expect(executionIdBefore).to.equal(executionIdAfter);
});
@ -2244,7 +2207,7 @@ contract('AccessManager', function () {
it('reverts as AccessManagerUnauthorizedConsume', async function () {
await expect(this.manager.connect(this.caller).consumeScheduledOp(this.caller, this.calldata))
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedConsume')
.withArgs(this.caller.address);
.withArgs(this.caller);
});
});
@ -2329,7 +2292,7 @@ contract('AccessManager', function () {
it('reverts as AccessManagerUnauthorizedCancel', async function () {
await expect(this.manager.connect(this.other).cancel(this.caller, this.target, this.calldata))
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCancel')
.withArgs(this.other.address, this.caller.address, this.target.target, this.method.selector);
.withArgs(this.other, this.caller, this.target, this.method.selector);
});
});
},
@ -2379,7 +2342,7 @@ contract('AccessManager', function () {
});
it('initial state', async function () {
expect(await this.ownable.owner()).to.be.equal(this.manager.target);
expect(await this.ownable.owner()).to.be.equal(this.manager);
});
describe('Contract is closed', function () {
@ -2390,7 +2353,7 @@ contract('AccessManager', function () {
it('directly call: reverts', async function () {
await expect(this.ownable.connect(this.user).$_checkOwner())
.to.be.revertedWithCustomError(this.ownable, 'OwnableUnauthorizedAccount')
.withArgs(this.user.address);
.withArgs(this.user);
});
it('relayed call (with role): reverts', async function () {
@ -2398,7 +2361,7 @@ contract('AccessManager', function () {
this.manager.connect(this.user).execute(this.ownable, this.ownable.$_checkOwner.getFragment().selector),
)
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall')
.withArgs(this.user.address, this.ownable.target, this.ownable.$_checkOwner.getFragment().selector);
.withArgs(this.user, this.ownable, this.ownable.$_checkOwner.getFragment().selector);
});
it('relayed call (without role): reverts', async function () {
@ -2406,7 +2369,7 @@ contract('AccessManager', function () {
this.manager.connect(this.other).execute(this.ownable, this.ownable.$_checkOwner.getFragment().selector),
)
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall')
.withArgs(this.other.address, this.ownable.target, this.ownable.$_checkOwner.getFragment().selector);
.withArgs(this.other, this.ownable, this.ownable.$_checkOwner.getFragment().selector);
});
});
@ -2423,7 +2386,7 @@ contract('AccessManager', function () {
it('directly call: reverts', async function () {
await expect(this.ownable.connect(this.user).$_checkOwner())
.to.be.revertedWithCustomError(this.ownable, 'OwnableUnauthorizedAccount')
.withArgs(this.user.address);
.withArgs(this.user);
});
it('relayed call (with role): success', async function () {
@ -2435,7 +2398,7 @@ contract('AccessManager', function () {
this.manager.connect(this.other).execute(this.ownable, this.ownable.$_checkOwner.getFragment().selector),
)
.to.be.revertedWithCustomError(this.manager, 'AccessManagerUnauthorizedCall')
.withArgs(this.other.address, this.ownable.target, this.ownable.$_checkOwner.getFragment().selector);
.withArgs(this.other, this.ownable, this.ownable.$_checkOwner.getFragment().selector);
});
});
@ -2451,7 +2414,7 @@ contract('AccessManager', function () {
it('directly call: reverts', async function () {
await expect(this.ownable.connect(this.user).$_checkOwner())
.to.be.revertedWithCustomError(this.ownable, 'OwnableUnauthorizedAccount')
.withArgs(this.user.address);
.withArgs(this.user);
});
it('relayed call (with role): success', async function () {

@ -1,4 +1,5 @@
const { ethers } = require('hardhat');
const { expect } = require('chai');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
async function fixture() {

@ -1,5 +1,5 @@
const { expect } = require('chai');
const { bigint: time } = require('../helpers/time');
const time = require('../helpers/time');
function shouldBehaveLikeVesting() {
it('check vesting schedule', async function () {

@ -3,7 +3,7 @@ const { expect } = require('chai');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { min } = require('../helpers/math');
const { bigint: time } = require('../helpers/time');
const time = require('../helpers/time');
const { shouldBehaveLikeVesting } = require('./VestingWallet.behavior');
@ -39,7 +39,7 @@ async function fixture() {
},
token: {
checkRelease: async (tx, amount) => {
await expect(tx).to.emit(token, 'Transfer').withArgs(mock.target, beneficiary.address, amount);
await expect(tx).to.emit(token, 'Transfer').withArgs(mock, beneficiary, amount);
await expect(tx).to.changeTokenBalances(token, [mock, beneficiary], [-amount, amount]);
},
setupFailure: async () => {
@ -50,8 +50,8 @@ async function fixture() {
};
},
releasedEvent: 'ERC20Released',
argsVerify: [token.target],
args: [ethers.Typed.address(token.target)],
argsVerify: [token],
args: [ethers.Typed.address(token)],
},
};
@ -76,7 +76,7 @@ describe('VestingWallet', function () {
});
it('check vesting contract', async function () {
expect(await this.mock.owner()).to.be.equal(this.beneficiary.address);
expect(await this.mock.owner()).to.be.equal(this.beneficiary);
expect(await this.mock.start()).to.be.equal(this.start);
expect(await this.mock.duration()).to.be.equal(this.duration);
expect(await this.mock.end()).to.be.equal(this.start + this.duration);

@ -4,8 +4,8 @@ const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { GovernorHelper } = require('../helpers/governance');
const { getDomain, Ballot } = require('../helpers/eip712');
const { bigint: Enums } = require('../helpers/enums');
const { bigint: time } = require('../helpers/time');
const { ProposalState, VoteType } = require('../helpers/enums');
const time = require('../helpers/time');
const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior');
const { shouldBehaveLikeERC6372 } = require('./utils/ERC6372.behavior');
@ -101,7 +101,7 @@ describe('Governor', function () {
it('deployment check', async function () {
expect(await this.mock.name()).to.equal(name);
expect(await this.mock.token()).to.equal(this.token.target);
expect(await this.mock.token()).to.equal(this.token);
expect(await this.mock.votingDelay()).to.equal(votingDelay);
expect(await this.mock.votingPeriod()).to.equal(votingPeriod);
expect(await this.mock.quorum(0)).to.equal(0n);
@ -128,7 +128,7 @@ describe('Governor', function () {
.to.emit(this.mock, 'ProposalCreated')
.withArgs(
this.proposal.id,
this.proposer.address,
this.proposer,
this.proposal.targets,
this.proposal.values,
this.proposal.signatures,
@ -140,21 +140,21 @@ describe('Governor', function () {
await this.helper.waitForSnapshot();
await expect(this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For, reason: 'This is nice' }))
await expect(this.helper.connect(this.voter1).vote({ support: VoteType.For, reason: 'This is nice' }))
.to.emit(this.mock, 'VoteCast')
.withArgs(this.voter1.address, this.proposal.id, Enums.VoteType.For, ethers.parseEther('10'), 'This is nice');
.withArgs(this.voter1, this.proposal.id, VoteType.For, ethers.parseEther('10'), 'This is nice');
await expect(this.helper.connect(this.voter2).vote({ support: Enums.VoteType.For }))
await expect(this.helper.connect(this.voter2).vote({ support: VoteType.For }))
.to.emit(this.mock, 'VoteCast')
.withArgs(this.voter2.address, this.proposal.id, Enums.VoteType.For, ethers.parseEther('7'), '');
.withArgs(this.voter2, this.proposal.id, VoteType.For, ethers.parseEther('7'), '');
await expect(this.helper.connect(this.voter3).vote({ support: Enums.VoteType.Against }))
await expect(this.helper.connect(this.voter3).vote({ support: VoteType.Against }))
.to.emit(this.mock, 'VoteCast')
.withArgs(this.voter3.address, this.proposal.id, Enums.VoteType.Against, ethers.parseEther('5'), '');
.withArgs(this.voter3, this.proposal.id, VoteType.Against, ethers.parseEther('5'), '');
await expect(this.helper.connect(this.voter4).vote({ support: Enums.VoteType.Abstain }))
await expect(this.helper.connect(this.voter4).vote({ support: VoteType.Abstain }))
.to.emit(this.mock, 'VoteCast')
.withArgs(this.voter4.address, this.proposal.id, Enums.VoteType.Abstain, ethers.parseEther('2'), '');
.withArgs(this.voter4, this.proposal.id, VoteType.Abstain, ethers.parseEther('2'), '');
await this.helper.waitForDeadline();
@ -165,7 +165,7 @@ describe('Governor', function () {
await expect(txExecute).to.emit(this.receiver, 'MockFunctionCalled');
// After
expect(await this.mock.proposalProposer(this.proposal.id)).to.equal(this.proposer.address);
expect(await this.mock.proposalProposer(this.proposal.id)).to.equal(this.proposer);
expect(await this.mock.hasVoted(this.proposal.id, this.owner)).to.be.false;
expect(await this.mock.hasVoted(this.proposal.id, this.voter1)).to.be.true;
expect(await this.mock.hasVoted(this.proposal.id, this.voter2)).to.be.true;
@ -191,7 +191,7 @@ describe('Governor', function () {
await expect(async () => {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
return this.helper.execute();
}).to.changeEtherBalances([this.mock, this.userEOA], [-value, value]);
@ -208,14 +208,14 @@ describe('Governor', function () {
await this.helper.waitForSnapshot();
await expect(
this.helper.vote({
support: Enums.VoteType.For,
support: VoteType.For,
voter: this.userEOA.address,
nonce,
signature: signBallot(this.userEOA),
}),
)
.to.emit(this.mock, 'VoteCast')
.withArgs(this.userEOA.address, this.proposal.id, Enums.VoteType.For, ethers.parseEther('10'), '');
.withArgs(this.userEOA, this.proposal.id, VoteType.For, ethers.parseEther('10'), '');
await this.helper.waitForDeadline();
await this.helper.execute();
@ -237,14 +237,14 @@ describe('Governor', function () {
await this.helper.waitForSnapshot();
await expect(
this.helper.vote({
support: Enums.VoteType.For,
support: VoteType.For,
voter: wallet.target,
nonce,
signature: signBallot(this.userEOA),
}),
)
.to.emit(this.mock, 'VoteCast')
.withArgs(wallet.target, this.proposal.id, Enums.VoteType.For, ethers.parseEther('10'), '');
.withArgs(wallet, this.proposal.id, VoteType.For, ethers.parseEther('10'), '');
await this.helper.waitForDeadline();
await this.helper.execute();
@ -266,7 +266,7 @@ describe('Governor', function () {
await this.helper.propose();
await expect(this.helper.propose())
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(this.proposal.id, Enums.ProposalState.Pending, ethers.ZeroHash);
.withArgs(this.proposal.id, ProposalState.Pending, ethers.ZeroHash);
});
it('if proposer has below threshold votes', async function () {
@ -275,25 +275,25 @@ describe('Governor', function () {
await this.mock.$_setProposalThreshold(threshold);
await expect(this.helper.connect(this.voter1).propose())
.to.be.revertedWithCustomError(this.mock, 'GovernorInsufficientProposerVotes')
.withArgs(this.voter1.address, votes, threshold);
.withArgs(this.voter1, votes, threshold);
});
});
describe('on vote', function () {
it('if proposal does not exist', async function () {
await expect(this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For }))
await expect(this.helper.connect(this.voter1).vote({ support: VoteType.For }))
.to.be.revertedWithCustomError(this.mock, 'GovernorNonexistentProposal')
.withArgs(this.proposal.id);
});
it('if voting has not started', async function () {
await this.helper.propose();
await expect(this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For }))
await expect(this.helper.connect(this.voter1).vote({ support: VoteType.For }))
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Pending,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Active]),
ProposalState.Pending,
GovernorHelper.proposalStatesToBitMap([ProposalState.Active]),
);
});
@ -309,21 +309,21 @@ describe('Governor', function () {
it('if vote was already casted', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await expect(this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For }))
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await expect(this.helper.connect(this.voter1).vote({ support: VoteType.For }))
.to.be.revertedWithCustomError(this.mock, 'GovernorAlreadyCastVote')
.withArgs(this.voter1.address);
.withArgs(this.voter1);
});
it('if voting is over', async function () {
await this.helper.propose();
await this.helper.waitForDeadline();
await expect(this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For }))
await expect(this.helper.connect(this.voter1).vote({ support: VoteType.For }))
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Defeated,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Active]),
ProposalState.Defeated,
GovernorHelper.proposalStatesToBitMap([ProposalState.Active]),
);
});
});
@ -341,13 +341,13 @@ describe('Governor', function () {
const nonce = await this.mock.nonces(this.userEOA);
function tamper(str, index, mask) {
const arrayStr = ethers.toBeArray(BigInt(str));
const arrayStr = ethers.getBytes(str);
arrayStr[index] ^= mask;
return ethers.hexlify(arrayStr);
}
const voteParams = {
support: Enums.VoteType.For,
support: VoteType.For,
voter: this.userEOA.address,
nonce,
signature: (...args) => signBallot(this.userEOA)(...args).then(sig => tamper(sig, 42, 0xff)),
@ -362,7 +362,7 @@ describe('Governor', function () {
const nonce = await this.mock.nonces(this.userEOA);
const voteParams = {
support: Enums.VoteType.For,
support: VoteType.For,
voter: this.userEOA.address,
nonce: nonce + 1n,
signature: signBallot(this.userEOA),
@ -378,7 +378,7 @@ describe('Governor', function () {
it('always', async function () {
await this.helper.connect(this.proposer).propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await expect(this.helper.queue()).to.be.revertedWithCustomError(this.mock, 'GovernorQueueNotImplemented');
});
@ -394,39 +394,39 @@ describe('Governor', function () {
it('if quorum is not reached', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter3).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter3).vote({ support: VoteType.For });
await expect(this.helper.execute())
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Active,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]),
ProposalState.Active,
GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]),
);
});
it('if score not reached', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.Against });
await this.helper.connect(this.voter1).vote({ support: VoteType.Against });
await expect(this.helper.execute())
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Active,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]),
ProposalState.Active,
GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]),
);
});
it('if voting is not over', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await expect(this.helper.execute())
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Active,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]),
ProposalState.Active,
GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]),
);
});
@ -443,7 +443,7 @@ describe('Governor', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await expect(this.helper.execute()).to.be.revertedWithCustomError(this.mock, 'FailedInnerCall');
});
@ -461,7 +461,7 @@ describe('Governor', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await expect(this.helper.execute()).to.be.revertedWith('CallReceiverMock: reverting');
});
@ -469,15 +469,15 @@ describe('Governor', function () {
it('if proposal was already executed', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.execute();
await expect(this.helper.execute())
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Executed,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]),
ProposalState.Executed,
GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]),
);
});
});
@ -492,38 +492,38 @@ describe('Governor', function () {
it('Pending & Active', async function () {
await this.helper.propose();
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Pending);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Pending);
await this.helper.waitForSnapshot();
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Pending);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Pending);
await this.helper.waitForSnapshot(1n);
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Active);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Active);
});
it('Defeated', async function () {
await this.helper.propose();
await this.helper.waitForDeadline();
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Active);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Active);
await this.helper.waitForDeadline(1n);
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Defeated);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Defeated);
});
it('Succeeded', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Active);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Active);
await this.helper.waitForDeadline(1n);
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Succeeded);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Succeeded);
});
it('Executed', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.execute();
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Executed);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Executed);
});
});
@ -539,58 +539,58 @@ describe('Governor', function () {
await this.helper.propose();
await this.helper.cancel('internal');
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Canceled);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Canceled);
await this.helper.waitForSnapshot();
await expect(this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For }))
await expect(this.helper.connect(this.voter1).vote({ support: VoteType.For }))
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Canceled,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Active]),
ProposalState.Canceled,
GovernorHelper.proposalStatesToBitMap([ProposalState.Active]),
);
});
it('after vote', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.cancel('internal');
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Canceled);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Canceled);
await this.helper.waitForDeadline();
await expect(this.helper.execute())
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Canceled,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]),
ProposalState.Canceled,
GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]),
);
});
it('after deadline', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.cancel('internal');
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Canceled);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Canceled);
await expect(this.helper.execute())
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Canceled,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]),
ProposalState.Canceled,
GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]),
);
});
it('after execution', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.execute();
@ -598,9 +598,9 @@ describe('Governor', function () {
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Executed,
ProposalState.Executed,
GovernorHelper.proposalStatesToBitMap(
[Enums.ProposalState.Canceled, Enums.ProposalState.Expired, Enums.ProposalState.Executed],
[ProposalState.Canceled, ProposalState.Expired, ProposalState.Executed],
{ inverted: true },
),
);
@ -625,7 +625,7 @@ describe('Governor', function () {
await expect(this.helper.connect(this.owner).cancel('external'))
.to.be.revertedWithCustomError(this.mock, 'GovernorOnlyProposer')
.withArgs(this.owner.address);
.withArgs(this.owner);
});
it('after vote started', async function () {
@ -636,44 +636,44 @@ describe('Governor', function () {
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Active,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Pending]),
ProposalState.Active,
GovernorHelper.proposalStatesToBitMap([ProposalState.Pending]),
);
});
it('after vote', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await expect(this.helper.cancel('external'))
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Active,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Pending]),
ProposalState.Active,
GovernorHelper.proposalStatesToBitMap([ProposalState.Pending]),
);
});
it('after deadline', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await expect(this.helper.cancel('external'))
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Succeeded,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Pending]),
ProposalState.Succeeded,
GovernorHelper.proposalStatesToBitMap([ProposalState.Pending]),
);
});
it('after execution', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.execute();
@ -681,8 +681,8 @@ describe('Governor', function () {
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Executed,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Pending]),
ProposalState.Executed,
GovernorHelper.proposalStatesToBitMap([ProposalState.Pending]),
);
});
});
@ -749,7 +749,7 @@ describe('Governor', function () {
.to.emit(this.mock, 'ProposalCreated')
.withArgs(
this.proposal.id,
this.proposer.address,
this.proposer,
this.proposal.targets,
this.proposal.values,
this.proposal.signatures,
@ -767,7 +767,7 @@ describe('Governor', function () {
.to.emit(this.mock, 'ProposalCreated')
.withArgs(
this.proposal.id,
this.voter1.address,
this.voter1,
this.proposal.targets,
this.proposal.values,
this.proposal.signatures,
@ -841,19 +841,19 @@ describe('Governor', function () {
it('setVotingDelay is protected', async function () {
await expect(this.mock.connect(this.owner).setVotingDelay(0n))
.to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor')
.withArgs(this.owner.address);
.withArgs(this.owner);
});
it('setVotingPeriod is protected', async function () {
await expect(this.mock.connect(this.owner).setVotingPeriod(32n))
.to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor')
.withArgs(this.owner.address);
.withArgs(this.owner);
});
it('setProposalThreshold is protected', async function () {
await expect(this.mock.connect(this.owner).setProposalThreshold(1_000_000_000_000_000_000n))
.to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor')
.withArgs(this.owner.address);
.withArgs(this.owner);
});
it('can setVotingDelay through governance', async function () {
@ -869,7 +869,7 @@ describe('Governor', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await expect(this.helper.execute()).to.emit(this.mock, 'VotingDelaySet').withArgs(4n, 0n);
@ -890,7 +890,7 @@ describe('Governor', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await expect(this.helper.execute()).to.emit(this.mock, 'VotingPeriodSet').withArgs(16n, 32n);
@ -913,7 +913,7 @@ describe('Governor', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await expect(this.helper.execute())
@ -934,7 +934,7 @@ describe('Governor', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await expect(this.helper.execute())
@ -955,7 +955,7 @@ describe('Governor', function () {
});
it('can receive an ERC721 safeTransfer', async function () {
await this.token.connect(this.owner).safeTransferFrom(this.owner, this.mock.target, tokenId);
await this.token.connect(this.owner).safeTransferFrom(this.owner, this.mock, tokenId);
});
});
@ -974,7 +974,7 @@ describe('Governor', function () {
it('can receive ERC1155 safeTransfer', async function () {
await this.token.connect(this.owner).safeTransferFrom(
this.owner,
this.mock.target,
this.mock,
...Object.entries(tokenIds)[0], // id + amount
'0x',
);
@ -983,13 +983,7 @@ describe('Governor', function () {
it('can receive ERC1155 safeBatchTransfer', async function () {
await this.token
.connect(this.owner)
.safeBatchTransferFrom(
this.owner,
this.mock.target,
Object.keys(tokenIds),
Object.values(tokenIds),
'0x',
);
.safeBatchTransferFrom(this.owner, this.mock, Object.keys(tokenIds), Object.values(tokenIds), '0x');
});
});
});

@ -4,10 +4,8 @@ const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic');
const { GovernorHelper } = require('../helpers/governance');
const { bigint: time } = require('../helpers/time');
const {
bigint: { OperationState },
} = require('../helpers/enums');
const { OperationState } = require('../helpers/enums');
const time = require('../helpers/time');
const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior');
@ -234,7 +232,7 @@ describe('TimelockController', function () {
),
)
.to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount')
.withArgs(this.other.address, PROPOSER_ROLE);
.withArgs(this.other, PROPOSER_ROLE);
});
it('enforce minimum delay', async function () {
@ -380,7 +378,7 @@ describe('TimelockController', function () {
),
)
.to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount')
.withArgs(this.other.address, EXECUTOR_ROLE);
.withArgs(this.other, EXECUTOR_ROLE);
});
it('prevents reentrancy execution', async function () {
@ -457,7 +455,7 @@ describe('TimelockController', function () {
.withArgs(
nonReentrantOperation.id,
0n,
getAddress(nonReentrantOperation.target),
getAddress(nonReentrantOperation),
nonReentrantOperation.value,
nonReentrantOperation.data,
);
@ -587,7 +585,7 @@ describe('TimelockController', function () {
),
)
.to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount')
.withArgs(this.other.address, PROPOSER_ROLE);
.withArgs(this.other, PROPOSER_ROLE);
});
it('enforce minimum delay', async function () {
@ -725,7 +723,7 @@ describe('TimelockController', function () {
),
)
.to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount')
.withArgs(this.other.address, EXECUTOR_ROLE);
.withArgs(this.other, EXECUTOR_ROLE);
});
it('length mismatch #1', async function () {
@ -939,7 +937,7 @@ describe('TimelockController', function () {
it('prevent non-canceller from canceling', async function () {
await expect(this.mock.connect(this.other).cancel(this.operation.id))
.to.be.revertedWithCustomError(this.mock, 'AccessControlUnauthorizedAccount')
.withArgs(this.other.address, CANCELLER_ROLE);
.withArgs(this.other, CANCELLER_ROLE);
});
});
});
@ -948,7 +946,7 @@ describe('TimelockController', function () {
it('prevent unauthorized maintenance', async function () {
await expect(this.mock.connect(this.other).updateDelay(0n))
.to.be.revertedWithCustomError(this.mock, 'TimelockUnauthorizedCaller')
.withArgs(this.other.address);
.withArgs(this.other);
});
it('timelock scheduled maintenance', async function () {

@ -3,7 +3,7 @@ const { expect } = require('chai');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { GovernorHelper } = require('../../helpers/governance');
const { bigint: Enums } = require('../../helpers/enums');
const { VoteType } = require('../../helpers/enums');
const TOKENS = [
{ Token: '$ERC721Votes', mode: 'blocknumber' },
@ -80,7 +80,7 @@ describe('GovernorERC721', function () {
it('deployment check', async function () {
expect(await this.mock.name()).to.equal(name);
expect(await this.mock.token()).to.equal(this.token.target);
expect(await this.mock.token()).to.equal(this.token);
expect(await this.mock.votingDelay()).to.equal(votingDelay);
expect(await this.mock.votingPeriod()).to.equal(votingPeriod);
expect(await this.mock.quorum(0n)).to.equal(0n);
@ -95,21 +95,21 @@ describe('GovernorERC721', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await expect(this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For }))
await expect(this.helper.connect(this.voter1).vote({ support: VoteType.For }))
.to.emit(this.mock, 'VoteCast')
.withArgs(this.voter1.address, this.proposal.id, Enums.VoteType.For, 1n, '');
.withArgs(this.voter1, this.proposal.id, VoteType.For, 1n, '');
await expect(this.helper.connect(this.voter2).vote({ support: Enums.VoteType.For }))
await expect(this.helper.connect(this.voter2).vote({ support: VoteType.For }))
.to.emit(this.mock, 'VoteCast')
.withArgs(this.voter2.address, this.proposal.id, Enums.VoteType.For, 2n, '');
.withArgs(this.voter2, this.proposal.id, VoteType.For, 2n, '');
await expect(this.helper.connect(this.voter3).vote({ support: Enums.VoteType.Against }))
await expect(this.helper.connect(this.voter3).vote({ support: VoteType.Against }))
.to.emit(this.mock, 'VoteCast')
.withArgs(this.voter3.address, this.proposal.id, Enums.VoteType.Against, 1n, '');
.withArgs(this.voter3, this.proposal.id, VoteType.Against, 1n, '');
await expect(this.helper.connect(this.voter4).vote({ support: Enums.VoteType.Abstain }))
await expect(this.helper.connect(this.voter4).vote({ support: VoteType.Abstain }))
.to.emit(this.mock, 'VoteCast')
.withArgs(this.voter4.address, this.proposal.id, Enums.VoteType.Abstain, 1n, '');
.withArgs(this.voter4, this.proposal.id, VoteType.Abstain, 1n, '');
await this.helper.waitForDeadline();
await this.helper.execute();

@ -3,8 +3,8 @@ const { expect } = require('chai');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { GovernorHelper } = require('../../helpers/governance');
const { bigint: Enums } = require('../../helpers/enums');
const { bigint: time } = require('../../helpers/time');
const { ProposalState, VoteType } = require('../../helpers/enums');
const time = require('../../helpers/time');
const TOKENS = [
{ Token: '$ERC20Votes', mode: 'blocknumber' },
@ -69,7 +69,7 @@ describe('GovernorPreventLateQuorum', function () {
it('deployment check', async function () {
expect(await this.mock.name()).to.equal(name);
expect(await this.mock.token()).to.equal(this.token.target);
expect(await this.mock.token()).to.equal(this.token);
expect(await this.mock.votingDelay()).to.equal(votingDelay);
expect(await this.mock.votingPeriod()).to.equal(votingPeriod);
expect(await this.mock.quorum(0)).to.equal(quorum);
@ -79,10 +79,10 @@ describe('GovernorPreventLateQuorum', function () {
it('nominal workflow unaffected', async function () {
const txPropose = await this.helper.connect(this.proposer).propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter2).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter3).vote({ support: Enums.VoteType.Against });
await this.helper.connect(this.voter4).vote({ support: Enums.VoteType.Abstain });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.connect(this.voter2).vote({ support: VoteType.For });
await this.helper.connect(this.voter3).vote({ support: VoteType.Against });
await this.helper.connect(this.voter4).vote({ support: VoteType.Abstain });
await this.helper.waitForDeadline();
await this.helper.execute();
@ -107,7 +107,7 @@ describe('GovernorPreventLateQuorum', function () {
.to.emit(this.mock, 'ProposalCreated')
.withArgs(
this.proposal.id,
this.proposer.address,
this.proposer,
this.proposal.targets,
this.proposal.values,
this.proposal.signatures,
@ -128,10 +128,10 @@ describe('GovernorPreventLateQuorum', function () {
expect(await this.mock.proposalDeadline(this.proposal.id)).to.equal(deadlineTimepoint);
// wait for the last minute to vote
await this.helper.waitForDeadline(-1n);
const txVote = await this.helper.connect(this.voter2).vote({ support: Enums.VoteType.For });
const txVote = await this.helper.connect(this.voter2).vote({ support: VoteType.For });
// cannot execute yet
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Active);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Active);
// compute new extended schedule
const extendedDeadline = (await time.clockFromReceipt[mode](txVote)) + lateQuorumVoteExtension;
@ -139,12 +139,12 @@ describe('GovernorPreventLateQuorum', function () {
expect(await this.mock.proposalDeadline(this.proposal.id)).to.equal(extendedDeadline);
// still possible to vote
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.Against });
await this.helper.connect(this.voter1).vote({ support: VoteType.Against });
await this.helper.waitForDeadline();
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Active);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Active);
await this.helper.waitForDeadline(1n);
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Defeated);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Defeated);
// check extension event
await expect(txVote).to.emit(this.mock, 'ProposalExtended').withArgs(this.proposal.id, extendedDeadline);
@ -154,7 +154,7 @@ describe('GovernorPreventLateQuorum', function () {
it('setLateQuorumVoteExtension is protected', async function () {
await expect(this.mock.connect(this.owner).setLateQuorumVoteExtension(0n))
.to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor')
.withArgs(this.owner.address);
.withArgs(this.owner);
});
it('can setLateQuorumVoteExtension through governance', async function () {
@ -170,7 +170,7 @@ describe('GovernorPreventLateQuorum', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await expect(this.helper.execute())

@ -5,7 +5,7 @@ const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs');
const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic');
const { GovernorHelper, timelockSalt } = require('../../helpers/governance');
const { bigint: Enums } = require('../../helpers/enums');
const { VoteType } = require('../../helpers/enums');
const TOKENS = [
{ Token: '$ERC20Votes', mode: 'blocknumber' },
@ -120,10 +120,10 @@ describe('GovernorStorage', function () {
it('queue and execute by id', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter2).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter3).vote({ support: Enums.VoteType.Against });
await this.helper.connect(this.voter4).vote({ support: Enums.VoteType.Abstain });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.connect(this.voter2).vote({ support: VoteType.For });
await this.helper.connect(this.voter3).vote({ support: VoteType.Against });
await this.helper.connect(this.voter4).vote({ support: VoteType.Abstain });
await this.helper.waitForDeadline();
await expect(this.mock.queue(this.proposal.id))

@ -4,11 +4,11 @@ const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs');
const { GovernorHelper } = require('../../helpers/governance');
const { bigint: Enums } = require('../../helpers/enums');
const { bigint: time } = require('../../helpers/time');
const { hashOperation } = require('../../helpers/access-manager');
const { max } = require('../../helpers/math');
const { selector } = require('../../helpers/methods');
const { hashOperation } = require('../../helpers/access-manager');
const { ProposalState, VoteType } = require('../../helpers/enums');
const time = require('../../helpers/time');
function prepareOperation({ sender, target, value = 0n, data = '0x' }) {
return {
@ -94,12 +94,12 @@ describe('GovernorTimelockAccess', function () {
it('post deployment check', async function () {
expect(await this.mock.name()).to.equal(name);
expect(await this.mock.token()).to.equal(this.token.target);
expect(await this.mock.token()).to.equal(this.token);
expect(await this.mock.votingDelay()).to.equal(votingDelay);
expect(await this.mock.votingPeriod()).to.equal(votingPeriod);
expect(await this.mock.quorum(0n)).to.equal(0n);
expect(await this.mock.accessManager()).to.equal(this.manager.target);
expect(await this.mock.accessManager()).to.equal(this.manager);
});
it('sets base delay (seconds)', async function () {
@ -108,7 +108,7 @@ describe('GovernorTimelockAccess', function () {
// Only through governance
await expect(this.mock.connect(this.voter1).setBaseDelaySeconds(baseDelay))
.to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor')
.withArgs(this.voter1.address);
.withArgs(this.voter1);
this.proposal = await this.helper.setProposal(
[
@ -122,7 +122,7 @@ describe('GovernorTimelockAccess', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await expect(this.helper.execute()).to.emit(this.mock, 'BaseDelaySet').withArgs(0n, baseDelay);
@ -136,7 +136,7 @@ describe('GovernorTimelockAccess', function () {
// Only through governance
await expect(this.mock.connect(this.voter1).setAccessManagerIgnored(this.other, selectors, true))
.to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor')
.withArgs(this.voter1.address);
.withArgs(this.voter1);
// Ignore
await this.helper.setProposal(
@ -154,14 +154,14 @@ describe('GovernorTimelockAccess', function () {
);
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
const ignoreReceipt = this.helper.execute();
for (const selector of selectors) {
await expect(ignoreReceipt)
.to.emit(this.mock, 'AccessManagerIgnoredSet')
.withArgs(this.other.address, selector, true);
.withArgs(this.other, selector, true);
expect(await this.mock.isAccessManagerIgnored(this.other, selector)).to.be.true;
}
@ -182,14 +182,14 @@ describe('GovernorTimelockAccess', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
const unignoreReceipt = this.helper.execute();
for (const selector of selectors) {
await expect(unignoreReceipt)
.to.emit(this.mock, 'AccessManagerIgnoredSet')
.withArgs(this.other.address, selector, false);
.withArgs(this.other, selector, false);
expect(await this.mock.isAccessManagerIgnored(this.other, selector)).to.be.false;
}
});
@ -213,12 +213,12 @@ describe('GovernorTimelockAccess', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
const tx = this.helper.execute();
for (const selector of selectors) {
await expect(tx).to.emit(this.mock, 'AccessManagerIgnoredSet').withArgs(this.mock.target, selector, true);
await expect(tx).to.emit(this.mock, 'AccessManagerIgnoredSet').withArgs(this.mock, selector, true);
expect(await this.mock.isAccessManagerIgnored(this.mock, selector)).to.be.true;
}
});
@ -365,7 +365,7 @@ describe('GovernorTimelockAccess', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
if (await this.mock.proposalNeedsQueuing(this.proposal.id)) {
expect(await this.helper.queue())
@ -391,7 +391,7 @@ describe('GovernorTimelockAccess', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.queue();
await expect(this.helper.execute())
@ -413,7 +413,7 @@ describe('GovernorTimelockAccess', function () {
// Go through all the governance process
await original.propose();
await original.waitForSnapshot();
await original.connect(this.voter1).vote({ support: Enums.VoteType.For });
await original.connect(this.voter1).vote({ support: VoteType.For });
await original.waitForDeadline();
await original.queue();
await original.waitForEta();
@ -428,7 +428,7 @@ describe('GovernorTimelockAccess', function () {
await rescheduled.setProposal([this.restricted.operation], 'descr');
await rescheduled.propose();
await rescheduled.waitForSnapshot();
await rescheduled.connect(this.voter1).vote({ support: Enums.VoteType.For });
await rescheduled.connect(this.voter1).vote({ support: VoteType.For });
await rescheduled.waitForDeadline();
await rescheduled.queue(); // This will schedule it again in the manager
await rescheduled.waitForEta();
@ -450,7 +450,7 @@ describe('GovernorTimelockAccess', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
const txQueue = await this.helper.queue();
await this.helper.waitForEta();
@ -494,7 +494,7 @@ describe('GovernorTimelockAccess', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
const txQueue = await this.helper.queue();
await this.helper.waitForEta();
@ -539,7 +539,7 @@ describe('GovernorTimelockAccess', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.queue();
@ -555,8 +555,8 @@ describe('GovernorTimelockAccess', function () {
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Canceled,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]),
ProposalState.Canceled,
GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]),
);
});
@ -568,7 +568,7 @@ describe('GovernorTimelockAccess', function () {
// Go through all the governance process
await original.propose();
await original.waitForSnapshot();
await original.connect(this.voter1).vote({ support: Enums.VoteType.For });
await original.connect(this.voter1).vote({ support: VoteType.For });
await original.waitForDeadline();
await original.queue();
@ -584,7 +584,7 @@ describe('GovernorTimelockAccess', function () {
// Queue the new proposal
await rescheduled.propose();
await rescheduled.waitForSnapshot();
await rescheduled.connect(this.voter1).vote({ support: Enums.VoteType.For });
await rescheduled.connect(this.voter1).vote({ support: VoteType.For });
await rescheduled.waitForDeadline();
await rescheduled.queue(); // This will schedule it again in the manager
@ -601,8 +601,8 @@ describe('GovernorTimelockAccess', function () {
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
original.currentProposal.id,
Enums.ProposalState.Canceled,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]),
ProposalState.Canceled,
GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]),
);
});
@ -611,7 +611,7 @@ describe('GovernorTimelockAccess', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.queue();
@ -627,8 +627,8 @@ describe('GovernorTimelockAccess', function () {
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Canceled,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]),
ProposalState.Canceled,
GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]),
);
});
@ -637,7 +637,7 @@ describe('GovernorTimelockAccess', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await expect(this.helper.cancel('internal'))
@ -648,8 +648,8 @@ describe('GovernorTimelockAccess', function () {
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Canceled,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]),
ProposalState.Canceled,
GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]),
);
});
@ -668,7 +668,7 @@ describe('GovernorTimelockAccess', function () {
for (const p of [proposal1, proposal2]) {
await p.propose();
await p.waitForSnapshot();
await p.connect(this.voter1).vote({ support: Enums.VoteType.For });
await p.connect(this.voter1).vote({ support: VoteType.For });
await p.waitForDeadline();
}
@ -717,13 +717,13 @@ describe('GovernorTimelockAccess', function () {
it('internal setter', async function () {
await expect(this.mock.$_setAccessManagerIgnored(this.receiver, this.restricted.selector, true))
.to.emit(this.mock, 'AccessManagerIgnoredSet')
.withArgs(this.receiver.target, this.restricted.selector, true);
.withArgs(this.receiver, this.restricted.selector, true);
expect(await this.mock.isAccessManagerIgnored(this.receiver, this.restricted.selector)).to.be.true;
await expect(this.mock.$_setAccessManagerIgnored(this.mock, '0x12341234', false))
.to.emit(this.mock, 'AccessManagerIgnoredSet')
.withArgs(this.mock.target, '0x12341234', false);
.withArgs(this.mock, '0x12341234', false);
expect(await this.mock.isAccessManagerIgnored(this.mock, '0x12341234')).to.be.false;
});
@ -752,7 +752,7 @@ describe('GovernorTimelockAccess', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await expect(this.helper.execute()).to.emit(this.mock, 'AccessManagerIgnoredSet');
@ -787,24 +787,22 @@ describe('GovernorTimelockAccess', function () {
await this.helper.setProposal([{ target, data }], 'descr #1');
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await expect(this.helper.execute())
.to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance')
.withArgs(this.manager.target, 0n, amount);
.withArgs(this.manager, 0n, amount);
await this.mock.$_setAccessManagerIgnored(target, selector, true);
await this.helper.setProposal([{ target, data }], 'descr #2');
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await expect(this.helper.execute())
.to.emit(this.token, 'Transfer')
.withArgs(this.mock.target, this.voter4.address, amount);
await expect(this.helper.execute()).to.emit(this.token, 'Transfer').withArgs(this.mock, this.voter4, amount);
});
});
@ -834,7 +832,7 @@ describe('GovernorTimelockAccess', function () {
await this.helper.setProposal([this.operation], `descr`);
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.queue();
await this.helper.waitForEta();
@ -856,7 +854,7 @@ describe('GovernorTimelockAccess', function () {
await this.helper.setProposal([this.operation], `descr`);
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.execute(); // Don't revert
});

@ -4,8 +4,8 @@ const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs');
const { GovernorHelper } = require('../../helpers/governance');
const { bigint: Enums } = require('../../helpers/enums');
const { bigint: time } = require('../../helpers/time');
const { ProposalState, VoteType } = require('../../helpers/enums');
const time = require('../../helpers/time');
const TOKENS = [
{ Token: '$ERC20Votes', mode: 'blocknumber' },
@ -81,13 +81,13 @@ describe('GovernorTimelockCompound', function () {
it('post deployment check', async function () {
expect(await this.mock.name()).to.equal(name);
expect(await this.mock.token()).to.equal(this.token.target);
expect(await this.mock.token()).to.equal(this.token);
expect(await this.mock.votingDelay()).to.equal(votingDelay);
expect(await this.mock.votingPeriod()).to.equal(votingPeriod);
expect(await this.mock.quorum(0n)).to.equal(0n);
expect(await this.mock.timelock()).to.equal(this.timelock.target);
expect(await this.timelock.admin()).to.equal(this.mock.target);
expect(await this.mock.timelock()).to.equal(this.timelock);
expect(await this.timelock.admin()).to.equal(this.mock);
});
it('nominal', async function () {
@ -96,10 +96,10 @@ describe('GovernorTimelockCompound', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter2).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter3).vote({ support: Enums.VoteType.Against });
await this.helper.connect(this.voter4).vote({ support: Enums.VoteType.Abstain });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.connect(this.voter2).vote({ support: VoteType.For });
await this.helper.connect(this.voter3).vote({ support: VoteType.Against });
await this.helper.connect(this.voter4).vote({ support: VoteType.Abstain });
await this.helper.waitForDeadline();
const txQueue = await this.helper.queue();
@ -129,15 +129,15 @@ describe('GovernorTimelockCompound', function () {
it('if already queued', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.queue();
await expect(this.helper.queue())
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Queued,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Succeeded]),
ProposalState.Queued,
GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded]),
);
});
@ -150,7 +150,7 @@ describe('GovernorTimelockCompound', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await expect(this.helper.queue())
.to.be.revertedWithCustomError(this.mock, 'GovernorAlreadyQueuedProposal')
@ -165,10 +165,10 @@ describe('GovernorTimelockCompound', function () {
it('if not queued', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline(1n);
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Succeeded);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Succeeded);
await expect(this.helper.execute())
.to.be.revertedWithCustomError(this.mock, 'GovernorNotQueuedProposal')
@ -178,11 +178,11 @@ describe('GovernorTimelockCompound', function () {
it('if too early', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.queue();
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Queued);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Queued);
await expect(this.helper.execute()).to.be.rejectedWith(
"Timelock::executeTransaction: Transaction hasn't surpassed time lock",
@ -192,26 +192,26 @@ describe('GovernorTimelockCompound', function () {
it('if too late', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.queue();
await this.helper.waitForEta(time.duration.days(30));
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Expired);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Expired);
await expect(this.helper.execute())
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Expired,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]),
ProposalState.Expired,
GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]),
);
});
it('if already executed', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.queue();
await this.helper.waitForEta();
@ -221,8 +221,8 @@ describe('GovernorTimelockCompound', function () {
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Executed,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]),
ProposalState.Executed,
GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]),
);
});
});
@ -281,28 +281,28 @@ describe('GovernorTimelockCompound', function () {
it('cancel before queue prevents scheduling', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await expect(this.helper.cancel('internal'))
.to.emit(this.mock, 'ProposalCanceled')
.withArgs(this.proposal.id);
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Canceled);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Canceled);
await expect(this.helper.queue())
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Canceled,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Succeeded]),
ProposalState.Canceled,
GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded]),
);
});
it('cancel after queue prevents executing', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.queue();
@ -310,14 +310,14 @@ describe('GovernorTimelockCompound', function () {
.to.emit(this.mock, 'ProposalCanceled')
.withArgs(this.proposal.id);
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Canceled);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Canceled);
await expect(this.helper.execute())
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Canceled,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]),
ProposalState.Canceled,
GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]),
);
});
});
@ -335,7 +335,7 @@ describe('GovernorTimelockCompound', function () {
.relay(this.token, 0, this.token.interface.encodeFunctionData('transfer', [this.other.address, 1n])),
)
.to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor')
.withArgs(this.owner.address);
.withArgs(this.owner);
});
it('can be executed through governance', async function () {
@ -355,7 +355,7 @@ describe('GovernorTimelockCompound', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.queue();
await this.helper.waitForEta();
@ -364,7 +364,7 @@ describe('GovernorTimelockCompound', function () {
await expect(txExecute).to.changeTokenBalances(this.token, [this.mock, this.other], [-1n, 1n]);
await expect(txExecute).to.emit(this.token, 'Transfer').withArgs(this.mock.target, this.other.address, 1n);
await expect(txExecute).to.emit(this.token, 'Transfer').withArgs(this.mock, this.other, 1n);
});
});
@ -376,7 +376,7 @@ describe('GovernorTimelockCompound', function () {
it('is protected', async function () {
await expect(this.mock.connect(this.owner).updateTimelock(this.newTimelock))
.to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor')
.withArgs(this.owner.address);
.withArgs(this.owner);
});
it('can be executed through governance to', async function () {
@ -396,16 +396,16 @@ describe('GovernorTimelockCompound', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.queue();
await this.helper.waitForEta();
await expect(this.helper.execute())
.to.emit(this.mock, 'TimelockChange')
.withArgs(this.timelock.target, this.newTimelock.target);
.withArgs(this.timelock, this.newTimelock);
expect(await this.mock.timelock()).to.equal(this.newTimelock.target);
expect(await this.mock.timelock()).to.equal(this.newTimelock);
});
});
@ -432,15 +432,15 @@ describe('GovernorTimelockCompound', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.queue();
await this.helper.waitForEta();
await expect(this.helper.execute()).to.emit(this.timelock, 'NewPendingAdmin').withArgs(newGovernor.target);
await expect(this.helper.execute()).to.emit(this.timelock, 'NewPendingAdmin').withArgs(newGovernor);
await newGovernor.__acceptAdmin();
expect(await this.timelock.admin()).to.equal(newGovernor.target);
expect(await this.timelock.admin()).to.equal(newGovernor);
});
});
});

@ -4,8 +4,8 @@ const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs');
const { GovernorHelper, timelockSalt } = require('../../helpers/governance');
const { bigint: Enums } = require('../../helpers/enums');
const { bigint: time } = require('../../helpers/time');
const { OperationState, ProposalState, VoteType } = require('../../helpers/enums');
const time = require('../../helpers/time');
const TOKENS = [
{ Token: '$ERC20Votes', mode: 'blocknumber' },
@ -95,12 +95,12 @@ describe('GovernorTimelockControl', function () {
it('post deployment check', async function () {
expect(await this.mock.name()).to.equal(name);
expect(await this.mock.token()).to.equal(this.token.target);
expect(await this.mock.token()).to.equal(this.token);
expect(await this.mock.votingDelay()).to.equal(votingDelay);
expect(await this.mock.votingPeriod()).to.equal(votingPeriod);
expect(await this.mock.quorum(0n)).to.equal(0n);
expect(await this.mock.timelock()).to.equal(this.timelock.target);
expect(await this.mock.timelock()).to.equal(this.timelock);
});
it('nominal', async function () {
@ -109,10 +109,10 @@ describe('GovernorTimelockControl', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter2).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter3).vote({ support: Enums.VoteType.Against });
await this.helper.connect(this.voter4).vote({ support: Enums.VoteType.Abstain });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.connect(this.voter2).vote({ support: VoteType.For });
await this.helper.connect(this.voter3).vote({ support: VoteType.Against });
await this.helper.connect(this.voter4).vote({ support: VoteType.Abstain });
await this.helper.waitForDeadline();
expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.true;
@ -145,15 +145,15 @@ describe('GovernorTimelockControl', function () {
it('if already queued', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.queue();
await expect(this.helper.queue())
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Queued,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Succeeded]),
ProposalState.Queued,
GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded]),
);
});
});
@ -162,34 +162,34 @@ describe('GovernorTimelockControl', function () {
it('if not queued', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline(1n);
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Succeeded);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Succeeded);
await expect(this.helper.execute())
.to.be.revertedWithCustomError(this.timelock, 'TimelockUnexpectedOperationState')
.withArgs(this.proposal.timelockid, GovernorHelper.proposalStatesToBitMap(Enums.OperationState.Ready));
.withArgs(this.proposal.timelockid, GovernorHelper.proposalStatesToBitMap(OperationState.Ready));
});
it('if too early', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.queue();
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Queued);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Queued);
await expect(this.helper.execute())
.to.be.revertedWithCustomError(this.timelock, 'TimelockUnexpectedOperationState')
.withArgs(this.proposal.timelockid, GovernorHelper.proposalStatesToBitMap(Enums.OperationState.Ready));
.withArgs(this.proposal.timelockid, GovernorHelper.proposalStatesToBitMap(OperationState.Ready));
});
it('if already executed', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.queue();
await this.helper.waitForEta();
@ -199,15 +199,15 @@ describe('GovernorTimelockControl', function () {
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Executed,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]),
ProposalState.Executed,
GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]),
);
});
it('if already executed by another proposer', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.queue();
await this.helper.waitForEta();
@ -222,8 +222,8 @@ describe('GovernorTimelockControl', function () {
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Executed,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]),
ProposalState.Executed,
GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]),
);
});
});
@ -233,28 +233,28 @@ describe('GovernorTimelockControl', function () {
it('cancel before queue prevents scheduling', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await expect(this.helper.cancel('internal'))
.to.emit(this.mock, 'ProposalCanceled')
.withArgs(this.proposal.id);
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Canceled);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Canceled);
await expect(this.helper.queue())
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Canceled,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Succeeded]),
ProposalState.Canceled,
GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded]),
);
});
it('cancel after queue prevents executing', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.queue();
@ -262,31 +262,31 @@ describe('GovernorTimelockControl', function () {
.to.emit(this.mock, 'ProposalCanceled')
.withArgs(this.proposal.id);
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Canceled);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Canceled);
await expect(this.helper.execute())
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Canceled,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]),
ProposalState.Canceled,
GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]),
);
});
it('cancel on timelock is reflected on governor', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.queue();
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Queued);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Queued);
await expect(this.timelock.connect(this.owner).cancel(this.proposal.timelockid))
.to.emit(this.timelock, 'Cancelled')
.withArgs(this.proposal.timelockid);
expect(await this.mock.state(this.proposal.id)).to.equal(Enums.ProposalState.Canceled);
expect(await this.mock.state(this.proposal.id)).to.equal(ProposalState.Canceled);
});
});
@ -303,7 +303,7 @@ describe('GovernorTimelockControl', function () {
.relay(this.token, 0n, this.token.interface.encodeFunctionData('transfer', [this.other.address, 1n])),
)
.to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor')
.withArgs(this.owner.address);
.withArgs(this.owner);
});
it('can be executed through governance', async function () {
@ -323,7 +323,7 @@ describe('GovernorTimelockControl', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.queue();
await this.helper.waitForEta();
@ -332,7 +332,7 @@ describe('GovernorTimelockControl', function () {
await expect(txExecute).to.changeTokenBalances(this.token, [this.mock, this.other], [-1n, 1n]);
await expect(txExecute).to.emit(this.token, 'Transfer').withArgs(this.mock.target, this.other.address, 1n);
await expect(txExecute).to.emit(this.token, 'Transfer').withArgs(this.mock, this.other, 1n);
});
it('is payable and can transfer eth to EOA', async function () {
@ -352,7 +352,7 @@ describe('GovernorTimelockControl', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.queue();
await this.helper.waitForEta();
@ -397,7 +397,7 @@ describe('GovernorTimelockControl', function () {
it('is protected', async function () {
await expect(this.mock.connect(this.owner).updateTimelock(this.newTimelock))
.to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor')
.withArgs(this.owner.address);
.withArgs(this.owner);
});
it('can be executed through governance to', async function () {
@ -413,16 +413,16 @@ describe('GovernorTimelockControl', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.queue();
await this.helper.waitForEta();
await expect(this.helper.execute())
.to.emit(this.mock, 'TimelockChange')
.withArgs(this.timelock.target, this.newTimelock.target);
.withArgs(this.timelock, this.newTimelock);
expect(await this.mock.timelock()).to.equal(this.newTimelock.target);
expect(await this.mock.timelock()).to.equal(this.newTimelock);
});
});
@ -489,7 +489,7 @@ describe('GovernorTimelockControl', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.queue();
await this.helper.waitForEta();

@ -3,8 +3,8 @@ const { expect } = require('chai');
const { loadFixture, mine } = require('@nomicfoundation/hardhat-network-helpers');
const { GovernorHelper } = require('../../helpers/governance');
const { bigint: Enums } = require('../../helpers/enums');
const { bigint: time } = require('../../helpers/time');
const { ProposalState, VoteType } = require('../../helpers/enums');
const time = require('../../helpers/time');
const TOKENS = [
{ Token: '$ERC20Votes', mode: 'blocknumber' },
@ -63,7 +63,7 @@ describe('GovernorVotesQuorumFraction', function () {
it('deployment check', async function () {
expect(await this.mock.name()).to.equal(name);
expect(await this.mock.token()).to.equal(this.token.target);
expect(await this.mock.token()).to.equal(this.token);
expect(await this.mock.votingDelay()).to.equal(votingDelay);
expect(await this.mock.votingPeriod()).to.equal(votingPeriod);
expect(await this.mock.quorum(0)).to.equal(0n);
@ -77,7 +77,7 @@ describe('GovernorVotesQuorumFraction', function () {
it('quroum reached', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await this.helper.execute();
});
@ -85,14 +85,14 @@ describe('GovernorVotesQuorumFraction', function () {
it('quroum not reached', async function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter2).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter2).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await expect(this.helper.execute())
.to.be.revertedWithCustomError(this.mock, 'GovernorUnexpectedProposalState')
.withArgs(
this.proposal.id,
Enums.ProposalState.Defeated,
GovernorHelper.proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]),
ProposalState.Defeated,
GovernorHelper.proposalStatesToBitMap([ProposalState.Succeeded, ProposalState.Queued]),
);
});
@ -100,7 +100,7 @@ describe('GovernorVotesQuorumFraction', function () {
it('updateQuorumNumerator is protected', async function () {
await expect(this.mock.connect(this.owner).updateQuorumNumerator(newRatio))
.to.be.revertedWithCustomError(this.mock, 'GovernorOnlyExecutor')
.withArgs(this.owner.address);
.withArgs(this.owner);
});
it('can updateQuorumNumerator through governance', async function () {
@ -116,7 +116,7 @@ describe('GovernorVotesQuorumFraction', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
await expect(this.helper.execute()).to.emit(this.mock, 'QuorumNumeratorUpdated').withArgs(ratio, newRatio);
@ -150,7 +150,7 @@ describe('GovernorVotesQuorumFraction', function () {
await this.helper.propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter1).vote({ support: VoteType.For });
await this.helper.waitForDeadline();
const quorumDenominator = await this.mock.quorumDenominator();

@ -3,7 +3,7 @@ const { expect } = require('chai');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { GovernorHelper } = require('../../helpers/governance');
const { bigint: Enums } = require('../../helpers/enums');
const { VoteType } = require('../../helpers/enums');
const { getDomain, ExtendedBallot } = require('../../helpers/eip712');
const TOKENS = [
@ -65,7 +65,7 @@ describe('GovernorWithParams', function () {
it('deployment check', async function () {
expect(await this.mock.name()).to.equal(name);
expect(await this.mock.token()).to.equal(this.token.target);
expect(await this.mock.token()).to.equal(this.token);
expect(await this.mock.votingDelay()).to.equal(votingDelay);
expect(await this.mock.votingPeriod()).to.equal(votingPeriod);
});
@ -73,10 +73,10 @@ describe('GovernorWithParams', function () {
it('nominal is unaffected', async function () {
await this.helper.connect(this.proposer).propose();
await this.helper.waitForSnapshot();
await this.helper.connect(this.voter1).vote({ support: Enums.VoteType.For, reason: 'This is nice' });
await this.helper.connect(this.voter2).vote({ support: Enums.VoteType.For });
await this.helper.connect(this.voter3).vote({ support: Enums.VoteType.Against });
await this.helper.connect(this.voter4).vote({ support: Enums.VoteType.Abstain });
await this.helper.connect(this.voter1).vote({ support: VoteType.For, reason: 'This is nice' });
await this.helper.connect(this.voter2).vote({ support: VoteType.For });
await this.helper.connect(this.voter3).vote({ support: VoteType.Against });
await this.helper.connect(this.voter4).vote({ support: VoteType.Abstain });
await this.helper.waitForDeadline();
await this.helper.execute();
@ -95,7 +95,7 @@ describe('GovernorWithParams', function () {
await expect(
this.helper.connect(this.voter2).vote({
support: Enums.VoteType.For,
support: VoteType.For,
reason: 'no particular reason',
params: params.encoded,
}),
@ -106,7 +106,7 @@ describe('GovernorWithParams', function () {
.withArgs(
this.voter2.address,
this.proposal.id,
Enums.VoteType.For,
VoteType.For,
weight,
'no particular reason',
params.encoded,
@ -128,7 +128,7 @@ describe('GovernorWithParams', function () {
const nonce = await this.mock.nonces(this.other);
const data = {
proposalId: this.proposal.id,
support: Enums.VoteType.For,
support: VoteType.For,
voter: this.other.address,
nonce,
reason: 'no particular reason',
@ -161,7 +161,7 @@ describe('GovernorWithParams', function () {
const nonce = await this.mock.nonces(this.other);
const data = {
proposalId: this.proposal.id,
support: Enums.VoteType.For,
support: VoteType.For,
voter: wallet.target,
nonce,
reason: 'no particular reason',
@ -192,7 +192,7 @@ describe('GovernorWithParams', function () {
const nonce = await this.mock.nonces(this.other);
const data = {
proposalId: this.proposal.id,
support: Enums.VoteType.For,
support: VoteType.For,
voter: this.other.address,
nonce,
reason: 'no particular reason',
@ -225,7 +225,7 @@ describe('GovernorWithParams', function () {
const nonce = await this.mock.nonces(this.other);
const data = {
proposalId: this.proposal.id,
support: Enums.VoteType.For,
support: VoteType.For,
voter: this.other.address,
nonce: nonce + 1n,
reason: 'no particular reason',

@ -1,4 +1,6 @@
const { bigint: time } = require('../../helpers/time');
const { expect } = require('chai');
const time = require('../../helpers/time');
function shouldBehaveLikeERC6372(mode = 'blocknumber') {
describe('should implement ERC-6372', function () {

@ -3,7 +3,7 @@ const { expect } = require('chai');
const { mine } = require('@nomicfoundation/hardhat-network-helpers');
const { getDomain, Delegation } = require('../../helpers/eip712');
const { bigint: time } = require('../../helpers/time');
const time = require('../../helpers/time');
const { shouldBehaveLikeERC6372 } = require('./ERC6372.behavior');
@ -30,10 +30,10 @@ function shouldBehaveLikeVotes(tokens, { mode = 'blocknumber', fungible = true }
await expect(this.votes.connect(this.alice).delegate(this.alice))
.to.emit(this.votes, 'DelegateChanged')
.withArgs(this.alice.address, ethers.ZeroAddress, this.alice.address)
.withArgs(this.alice, ethers.ZeroAddress, this.alice)
.to.not.emit(this.votes, 'DelegateVotesChanged');
expect(await this.votes.delegates(this.alice)).to.equal(this.alice.address);
expect(await this.votes.delegates(this.alice)).to.equal(this.alice);
});
it('delegation with tokens', async function () {
@ -47,11 +47,11 @@ function shouldBehaveLikeVotes(tokens, { mode = 'blocknumber', fungible = true }
await expect(tx)
.to.emit(this.votes, 'DelegateChanged')
.withArgs(this.alice.address, ethers.ZeroAddress, this.alice.address)
.withArgs(this.alice, ethers.ZeroAddress, this.alice)
.to.emit(this.votes, 'DelegateVotesChanged')
.withArgs(this.alice.address, 0n, weight);
.withArgs(this.alice, 0n, weight);
expect(await this.votes.delegates(this.alice)).to.equal(this.alice.address);
expect(await this.votes.delegates(this.alice)).to.equal(this.alice);
expect(await this.votes.getVotes(this.alice)).to.equal(weight);
expect(await this.votes.getPastVotes(this.alice, timepoint - 1n)).to.equal(0n);
await mine();
@ -63,7 +63,7 @@ function shouldBehaveLikeVotes(tokens, { mode = 'blocknumber', fungible = true }
await this.votes.$_mint(this.alice, token);
const weight = getWeight(token);
expect(await this.votes.delegates(this.alice)).to.equal(this.alice.address);
expect(await this.votes.delegates(this.alice)).to.equal(this.alice);
expect(await this.votes.getVotes(this.alice)).to.equal(weight);
expect(await this.votes.getVotes(this.bob)).to.equal(0);
@ -72,13 +72,13 @@ function shouldBehaveLikeVotes(tokens, { mode = 'blocknumber', fungible = true }
await expect(tx)
.to.emit(this.votes, 'DelegateChanged')
.withArgs(this.alice.address, this.alice.address, this.bob.address)
.withArgs(this.alice, this.alice, this.bob)
.to.emit(this.votes, 'DelegateVotesChanged')
.withArgs(this.alice.address, weight, 0)
.withArgs(this.alice, weight, 0)
.to.emit(this.votes, 'DelegateVotesChanged')
.withArgs(this.bob.address, 0, weight);
.withArgs(this.bob, 0, weight);
expect(await this.votes.delegates(this.alice)).to.equal(this.bob.address);
expect(await this.votes.delegates(this.alice)).to.equal(this.bob);
expect(await this.votes.getVotes(this.alice)).to.equal(0n);
expect(await this.votes.getVotes(this.bob)).to.equal(weight);
@ -93,7 +93,7 @@ function shouldBehaveLikeVotes(tokens, { mode = 'blocknumber', fungible = true }
const nonce = 0n;
it('accept signed delegation', async function () {
await this.votes.$_mint(this.delegator.address, token);
await this.votes.$_mint(this.delegator, token);
const weight = getWeight(token);
const { r, s, v } = await this.delegator
@ -108,18 +108,18 @@ function shouldBehaveLikeVotes(tokens, { mode = 'blocknumber', fungible = true }
)
.then(ethers.Signature.from);
expect(await this.votes.delegates(this.delegator.address)).to.equal(ethers.ZeroAddress);
expect(await this.votes.delegates(this.delegator)).to.equal(ethers.ZeroAddress);
const tx = await this.votes.delegateBySig(this.delegatee, nonce, ethers.MaxUint256, v, r, s);
const timepoint = await time.clockFromReceipt[mode](tx);
await expect(tx)
.to.emit(this.votes, 'DelegateChanged')
.withArgs(this.delegator.address, ethers.ZeroAddress, this.delegatee.address)
.withArgs(this.delegator, ethers.ZeroAddress, this.delegatee)
.to.emit(this.votes, 'DelegateVotesChanged')
.withArgs(this.delegatee.address, 0, weight);
.withArgs(this.delegatee, 0, weight);
expect(await this.votes.delegates(this.delegator.address)).to.equal(this.delegatee.address);
expect(await this.votes.delegates(this.delegator.address)).to.equal(this.delegatee);
expect(await this.votes.getVotes(this.delegator.address)).to.equal(0n);
expect(await this.votes.getVotes(this.delegatee)).to.equal(weight);
expect(await this.votes.getPastVotes(this.delegatee, timepoint - 1n)).to.equal(0n);
@ -144,7 +144,7 @@ function shouldBehaveLikeVotes(tokens, { mode = 'blocknumber', fungible = true }
await expect(this.votes.delegateBySig(this.delegatee, nonce, ethers.MaxUint256, v, r, s))
.to.be.revertedWithCustomError(this.votes, 'InvalidAccountNonce')
.withArgs(this.delegator.address, nonce + 1n);
.withArgs(this.delegator, nonce + 1n);
});
it('rejects bad delegatee', async function () {
@ -167,9 +167,9 @@ function shouldBehaveLikeVotes(tokens, { mode = 'blocknumber', fungible = true }
log => this.votes.interface.parseLog(log)?.name === 'DelegateChanged',
);
const { args } = this.votes.interface.parseLog(delegateChanged);
expect(args.delegator).to.not.be.equal(this.delegator.address);
expect(args.delegator).to.not.be.equal(this.delegator);
expect(args.fromDelegate).to.equal(ethers.ZeroAddress);
expect(args.toDelegate).to.equal(this.other.address);
expect(args.toDelegate).to.equal(this.other);
});
it('rejects bad nonce', async function () {
@ -187,7 +187,7 @@ function shouldBehaveLikeVotes(tokens, { mode = 'blocknumber', fungible = true }
await expect(this.votes.delegateBySig(this.delegatee, nonce + 1n, ethers.MaxUint256, v, r, s))
.to.be.revertedWithCustomError(this.votes, 'InvalidAccountNonce')
.withArgs(this.delegator.address, 0);
.withArgs(this.delegator, 0);
});
it('rejects expired permit', async function () {

@ -4,7 +4,7 @@ const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { sum } = require('../../helpers/math');
const { zip } = require('../../helpers/iterate');
const { bigint: time } = require('../../helpers/time');
const time = require('../../helpers/time');
const { shouldBehaveLikeVotes } = require('./Votes.behavior');
@ -71,7 +71,7 @@ describe('Votes', function () {
expect(await this.votes.getVotes(this.accounts[0])).to.equal(this.amounts[this.accounts[0].address]);
expect(await this.votes.getVotes(this.accounts[1])).to.equal(0n);
expect(await this.votes.delegates(this.accounts[0])).to.equal(this.accounts[0].address);
expect(await this.votes.delegates(this.accounts[0])).to.equal(this.accounts[0]);
expect(await this.votes.delegates(this.accounts[1])).to.equal(ethers.ZeroAddress);
await this.votes.delegate(this.accounts[1], ethers.Typed.address(this.accounts[0]));
@ -80,13 +80,13 @@ describe('Votes', function () {
this.amounts[this.accounts[0].address] + this.amounts[this.accounts[1].address],
);
expect(await this.votes.getVotes(this.accounts[1])).to.equal(0n);
expect(await this.votes.delegates(this.accounts[0])).to.equal(this.accounts[0].address);
expect(await this.votes.delegates(this.accounts[1])).to.equal(this.accounts[0].address);
expect(await this.votes.delegates(this.accounts[0])).to.equal(this.accounts[0]);
expect(await this.votes.delegates(this.accounts[1])).to.equal(this.accounts[0]);
});
it('cross delegates', async function () {
await this.votes.delegate(this.accounts[0], ethers.Typed.address(this.accounts[1].address));
await this.votes.delegate(this.accounts[1], ethers.Typed.address(this.accounts[0].address));
await this.votes.delegate(this.accounts[0], ethers.Typed.address(this.accounts[1]));
await this.votes.delegate(this.accounts[1], ethers.Typed.address(this.accounts[0]));
expect(await this.votes.getVotes(this.accounts[0])).to.equal(this.amounts[this.accounts[1].address]);
expect(await this.votes.getVotes(this.accounts[1])).to.equal(this.amounts[this.accounts[0].address]);

@ -1,7 +1,8 @@
const { ethers } = require('hardhat');
const { MAX_UINT64 } = require('./constants');
const { namespaceSlot } = require('./namespaced-storage');
const { bigint: time } = require('./time');
const time = require('./time');
const { upgradeableSlot } = require('./storage');
function buildBaseRoles() {
const roles = {
@ -45,8 +46,8 @@ const formatAccess = access => [access[0], access[1].toString()];
const MINSETBACK = time.duration.days(5);
const EXPIRATION = time.duration.weeks(1);
const EXECUTION_ID_STORAGE_SLOT = namespaceSlot('AccessManager', 3n);
const CONSUMING_SCHEDULE_STORAGE_SLOT = namespaceSlot('AccessManaged', 0n);
const EXECUTION_ID_STORAGE_SLOT = upgradeableSlot('AccessManager', 3n);
const CONSUMING_SCHEDULE_STORAGE_SLOT = upgradeableSlot('AccessManaged', 0n);
/**
* @requires this.{manager, caller, target, calldata}

@ -1,6 +0,0 @@
const { ethers } = require('hardhat');
module.exports = {
// TODO: remove conversion toNumber() when bigint are supported
getChainId: () => ethers.provider.getNetwork().then(network => ethers.toNumber(network.chainId)),
};

@ -1,4 +1,4 @@
const { ethers } = require('ethers');
const { ethers } = require('hardhat');
const types = require('./eip712-types');
async function getDomain(contract) {
@ -11,8 +11,7 @@ async function getDomain(contract) {
const domain = {
name,
version,
// TODO: remove check when contracts are all migrated to ethers
chainId: web3.utils.isBN(chainId) ? chainId.toNumber() : chainId,
chainId,
verifyingContract,
salt,
};

@ -1,22 +1,12 @@
function Enum(...options) {
return Object.fromEntries(options.map((key, i) => [key, web3.utils.toBN(i)]));
}
function EnumBigInt(...options) {
return Object.fromEntries(options.map((key, i) => [key, BigInt(i)]));
}
// TODO: remove web3, simplify code
function createExport(Enum) {
return {
module.exports = {
Enum,
ProposalState: Enum('Pending', 'Active', 'Canceled', 'Defeated', 'Succeeded', 'Queued', 'Expired', 'Executed'),
VoteType: Enum('Against', 'For', 'Abstain'),
Rounding: Enum('Floor', 'Ceil', 'Trunc', 'Expand'),
OperationState: Enum('Unset', 'Waiting', 'Ready', 'Done'),
RevertType: Enum('None', 'RevertWithoutMessage', 'RevertWithMessage', 'RevertWithCustomError', 'Panic'),
};
}
module.exports = createExport(Enum);
module.exports.bigint = createExport(EnumBigInt);
};

@ -172,7 +172,7 @@ class GovernorHelper {
if (!Array.isArray(proposalStates)) {
proposalStates = [proposalStates];
}
const statesCount = BigInt(Object.keys(ProposalState).length);
const statesCount = ethers.toBigInt(Object.keys(ProposalState).length);
let result = 0n;
for (const state of unique(...proposalStates)) {

@ -4,10 +4,7 @@ const min = (...values) => values.slice(1).reduce((x, y) => (x < y ? x : y), val
const sum = (...values) => values.slice(1).reduce((x, y) => x + y, values.at(0));
module.exports = {
// re-export min, max & sum of integer / bignumber
min,
max,
sum,
// deprecated: BN version of sum
BNsum: (...args) => args.slice(1).reduce((x, y) => x.add(y), args.at(0)),
};

@ -1,22 +0,0 @@
const { ethers, artifacts } = require('hardhat');
const { erc7201slot } = require('./erc1967');
function namespaceId(contractName) {
return `openzeppelin.storage.${contractName}`;
}
function namespaceSlot(contractName, offset) {
try {
// Try to get the artifact paths, will throw if it doesn't exist
artifacts._getArtifactPathSync(`${contractName}Upgradeable`);
return offset + ethers.toBigInt(erc7201slot(namespaceId(contractName)));
} catch (_) {
return offset;
}
}
module.exports = {
namespaceSlot,
namespaceLocation: erc7201slot,
namespaceId,
};

@ -1,5 +1,5 @@
const { ethers } = require('hardhat');
const { getStorageAt, setStorageAt } = require('@nomicfoundation/hardhat-network-helpers');
const { setStorageAt } = require('@nomicfoundation/hardhat-network-helpers');
const ImplementationLabel = 'eip1967.proxy.implementation';
const AdminLabel = 'eip1967.proxy.admin';
@ -7,11 +7,10 @@ const BeaconLabel = 'eip1967.proxy.beacon';
const erc1967slot = label => ethers.toBeHex(ethers.toBigInt(ethers.id(label)) - 1n);
const erc7201slot = label => ethers.toBeHex(ethers.toBigInt(ethers.keccak256(erc1967slot(label))) & ~0xffn);
const erc7201format = contractName => `openzeppelin.storage.${contractName}`;
const getSlot = (address, slot) =>
(ethers.isAddressable(address) ? address.getAddress() : Promise.resolve(address)).then(address =>
getStorageAt(address, ethers.isBytesLike(slot) ? slot : erc1967slot(slot)),
);
ethers.provider.getStorage(address, ethers.isBytesLike(slot) ? slot : erc1967slot(slot));
const setSlot = (address, slot, value) =>
Promise.all([
@ -22,6 +21,16 @@ const setSlot = (address, slot, value) =>
const getAddressInSlot = (address, slot) =>
getSlot(address, slot).then(slotValue => ethers.AbiCoder.defaultAbiCoder().decode(['address'], slotValue)[0]);
const upgradeableSlot = (contractName, offset) => {
try {
// Try to get the artifact paths, will throw if it doesn't exist
artifacts._getArtifactPathSync(`${contractName}Upgradeable`);
return offset + ethers.toBigInt(erc7201slot(erc7201format(contractName)));
} catch (_) {
return offset;
}
};
module.exports = {
ImplementationLabel,
AdminLabel,
@ -31,7 +40,9 @@ module.exports = {
BeaconSlot: erc1967slot(BeaconLabel),
erc1967slot,
erc7201slot,
erc7201format,
setSlot,
getSlot,
getAddressInSlot,
upgradeableSlot,
};

@ -3,12 +3,12 @@ const { time, mine, mineUpTo } = require('@nomicfoundation/hardhat-network-helpe
const { mapValues } = require('./iterate');
const clock = {
blocknumber: () => time.latestBlock(),
timestamp: () => time.latest(),
blocknumber: () => time.latestBlock().then(ethers.toBigInt),
timestamp: () => time.latest().then(ethers.toBigInt),
};
const clockFromReceipt = {
blocknumber: receipt => Promise.resolve(receipt.blockNumber),
timestamp: receipt => ethers.provider.getBlock(receipt.blockNumber).then(block => block.timestamp),
blocknumber: receipt => Promise.resolve(ethers.toBigInt(receipt.blockNumber)),
timestamp: receipt => ethers.provider.getBlock(receipt.blockNumber).then(block => ethers.toBigInt(block.timestamp)),
};
const increaseBy = {
blockNumber: mine,
@ -19,7 +19,7 @@ const increaseTo = {
blocknumber: mineUpTo,
timestamp: (to, mine = true) => (mine ? time.increaseTo(to) : time.setNextBlockTimestamp(to)),
};
const duration = time.duration;
const duration = mapValues(time.duration, fn => n => ethers.toBigInt(fn(ethers.toNumber(n))));
module.exports = {
clock,
@ -28,12 +28,3 @@ module.exports = {
increaseTo,
duration,
};
// TODO: deprecate the old version in favor of this one
module.exports.bigint = {
clock: mapValues(clock, fn => () => fn().then(ethers.toBigInt)),
clockFromReceipt: mapValues(clockFromReceipt, fn => receipt => fn(receipt).then(ethers.toBigInt)),
increaseBy: increaseBy,
increaseTo: increaseTo,
duration: mapValues(duration, fn => n => ethers.toBigInt(fn(ethers.toNumber(n)))),
};

@ -1,5 +1,7 @@
const { network } = require('hardhat');
const { expect } = require('chai');
const { mine } = require('@nomicfoundation/hardhat-network-helpers');
const { unique } = require('./iterate');
async function batchInBlock(txs) {

@ -30,7 +30,7 @@ describe('ERC2771Context', function () {
});
it('returns the trusted forwarder', async function () {
expect(await this.context.trustedForwarder()).to.equal(this.forwarder.target);
expect(await this.context.trustedForwarder()).to.equal(this.forwarder);
});
describe('when called directly', function () {
@ -57,14 +57,14 @@ describe('ERC2771Context', function () {
expect(await this.forwarder.verify(req)).to.equal(true);
await expect(this.forwarder.execute(req)).to.emit(this.context, 'Sender').withArgs(this.sender.address);
await expect(this.forwarder.execute(req)).to.emit(this.context, 'Sender').withArgs(this.sender);
});
it('returns the original sender when calldata length is less than 20 bytes (address length)', async function () {
// The forwarder doesn't produce calls with calldata length less than 20 bytes so `this.forwarderAsSigner` is used instead.
await expect(this.context.connect(this.forwarderAsSigner).msgSender())
.to.emit(this.context, 'Sender')
.withArgs(this.forwarder.target);
.withArgs(this.forwarder);
});
});
@ -128,6 +128,6 @@ describe('ERC2771Context', function () {
expect(await this.forwarder.verify(req)).to.equal(true);
await expect(this.forwarder.execute(req)).to.emit(this.context, 'Sender').withArgs(this.sender.address);
await expect(this.forwarder.execute(req)).to.emit(this.context, 'Sender').withArgs(this.sender);
});
});

@ -3,8 +3,8 @@ const { expect } = require('chai');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { getDomain, ForwardRequest } = require('../helpers/eip712');
const { bigint: time } = require('../helpers/time');
const { sum } = require('../helpers/math');
const time = require('../helpers/time');
async function fixture() {
const [sender, refundReceiver, another, ...accounts] = await ethers.getSigners();
@ -140,7 +140,7 @@ describe('ERC2771Forwarder', function () {
} else {
await expect(promise)
.to.be.revertedWithCustomError(this.forwarder, 'ERC2771UntrustfulTarget')
.withArgs(request.to, this.forwarder.target);
.withArgs(request.to, this.forwarder);
}
});
}
@ -299,7 +299,7 @@ describe('ERC2771Forwarder', function () {
} else {
await expect(promise)
.to.be.revertedWithCustomError(this.forwarder, 'ERC2771UntrustfulTarget')
.withArgs(this.requests[idx].to, this.forwarder.target);
.withArgs(this.requests[idx].to, this.forwarder);
}
});
}

@ -2,7 +2,7 @@ const { ethers } = require('hardhat');
const { expect } = require('chai');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { getAddressInSlot, setSlot, ImplementationSlot, AdminSlot, BeaconSlot } = require('../../helpers/erc1967');
const { getAddressInSlot, setSlot, ImplementationSlot, AdminSlot, BeaconSlot } = require('../../helpers/storage');
async function fixture() {
const [, admin, anotherAccount] = await ethers.getSigners();
@ -26,8 +26,8 @@ describe('ERC1967Utils', function () {
describe('getImplementation', function () {
it('returns current implementation and matches implementation slot value', async function () {
expect(await this.utils.$getImplementation()).to.equal(this.v1.target);
expect(await getAddressInSlot(this.utils, ImplementationSlot)).to.equal(this.v1.target);
expect(await this.utils.$getImplementation()).to.equal(this.v1);
expect(await getAddressInSlot(this.utils, ImplementationSlot)).to.equal(this.v1);
});
});
@ -36,14 +36,14 @@ describe('ERC1967Utils', function () {
const newImplementation = this.v2;
const tx = await this.utils.$upgradeToAndCall(newImplementation, '0x');
expect(await getAddressInSlot(this.utils, ImplementationSlot)).to.equal(newImplementation.target);
await expect(tx).to.emit(this.utils, 'Upgraded').withArgs(newImplementation.target);
expect(await getAddressInSlot(this.utils, ImplementationSlot)).to.equal(newImplementation);
await expect(tx).to.emit(this.utils, 'Upgraded').withArgs(newImplementation);
});
it('reverts when implementation does not contain code', async function () {
await expect(this.utils.$upgradeToAndCall(this.anotherAccount, '0x'))
.to.be.revertedWithCustomError(this.utils, 'ERC1967InvalidImplementation')
.withArgs(this.anotherAccount.address);
.withArgs(this.anotherAccount);
});
describe('when data is empty', function () {
@ -72,8 +72,8 @@ describe('ERC1967Utils', function () {
describe('getAdmin', function () {
it('returns current admin and matches admin slot value', async function () {
expect(await this.utils.$getAdmin()).to.equal(this.admin.address);
expect(await getAddressInSlot(this.utils, AdminSlot)).to.equal(this.admin.address);
expect(await this.utils.$getAdmin()).to.equal(this.admin);
expect(await getAddressInSlot(this.utils, AdminSlot)).to.equal(this.admin);
});
});
@ -82,8 +82,8 @@ describe('ERC1967Utils', function () {
const newAdmin = this.anotherAccount;
const tx = await this.utils.$changeAdmin(newAdmin);
expect(await getAddressInSlot(this.utils, AdminSlot)).to.equal(newAdmin.address);
await expect(tx).to.emit(this.utils, 'AdminChanged').withArgs(this.admin.address, newAdmin.address);
expect(await getAddressInSlot(this.utils, AdminSlot)).to.equal(newAdmin);
await expect(tx).to.emit(this.utils, 'AdminChanged').withArgs(this.admin, newAdmin);
});
it('reverts when setting the address zero as admin', async function () {
@ -102,8 +102,8 @@ describe('ERC1967Utils', function () {
describe('getBeacon', function () {
it('returns current beacon and matches beacon slot value', async function () {
expect(await this.utils.$getBeacon()).to.equal(this.beacon.target);
expect(await getAddressInSlot(this.utils, BeaconSlot)).to.equal(this.beacon.target);
expect(await this.utils.$getBeacon()).to.equal(this.beacon);
expect(await getAddressInSlot(this.utils, BeaconSlot)).to.equal(this.beacon);
});
});
@ -112,14 +112,14 @@ describe('ERC1967Utils', function () {
const newBeacon = await ethers.deployContract('UpgradeableBeaconMock', [this.v2]);
const tx = await this.utils.$upgradeBeaconToAndCall(newBeacon, '0x');
expect(await getAddressInSlot(this.utils, BeaconSlot)).to.equal(newBeacon.target);
await expect(tx).to.emit(this.utils, 'BeaconUpgraded').withArgs(newBeacon.target);
expect(await getAddressInSlot(this.utils, BeaconSlot)).to.equal(newBeacon);
await expect(tx).to.emit(this.utils, 'BeaconUpgraded').withArgs(newBeacon);
});
it('reverts when beacon does not contain code', async function () {
await expect(this.utils.$upgradeBeaconToAndCall(this.anotherAccount, '0x'))
.to.be.revertedWithCustomError(this.utils, 'ERC1967InvalidBeacon')
.withArgs(this.anotherAccount.address);
.withArgs(this.anotherAccount);
});
it("reverts when beacon's implementation does not contain code", async function () {
@ -127,7 +127,7 @@ describe('ERC1967Utils', function () {
await expect(this.utils.$upgradeBeaconToAndCall(newBeacon, '0x'))
.to.be.revertedWithCustomError(this.utils, 'ERC1967InvalidImplementation')
.withArgs(this.anotherAccount.address);
.withArgs(this.anotherAccount);
});
describe('when data is empty', function () {
@ -154,7 +154,7 @@ describe('ERC1967Utils', function () {
const newBeacon = await ethers.deployContract('UpgradeableBeaconReentrantMock');
await expect(this.utils.$upgradeBeaconToAndCall(newBeacon, '0x'))
.to.be.revertedWithCustomError(newBeacon, 'BeaconProxyBeaconSlotAddress')
.withArgs(newBeacon.target);
.withArgs(newBeacon);
});
});
});

@ -1,19 +1,19 @@
const { ethers } = require('hardhat');
const { expect } = require('chai');
const { getAddressInSlot, ImplementationSlot } = require('../helpers/erc1967');
const { getAddressInSlot, ImplementationSlot } = require('../helpers/storage');
module.exports = function shouldBehaveLikeProxy() {
it('cannot be initialized with a non-contract address', async function () {
const initializeData = '0x';
await expect(this.createProxy(this.nonContractAddress, initializeData))
.to.be.revertedWithCustomError(await ethers.getContractFactory('ERC1967Proxy'), 'ERC1967InvalidImplementation')
.withArgs(this.nonContractAddress.address);
.withArgs(this.nonContractAddress);
});
const assertProxyInitialization = function ({ value, balance }) {
it('sets the implementation address', async function () {
expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.implementation.target);
expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.implementation);
});
it('initializes the proxy', async function () {

@ -1,7 +1,8 @@
const { ethers } = require('hardhat');
const { expect } = require('chai');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { getAddressInSlot, BeaconSlot } = require('../../helpers/erc1967');
const { getAddressInSlot, BeaconSlot } = require('../../helpers/storage');
async function fixture() {
const [admin, other] = await ethers.getSigners();
@ -27,7 +28,7 @@ describe('BeaconProxy', function () {
await expect(this.newBeaconProxy(notBeacon, '0x'))
.to.be.revertedWithCustomError(this.factory, 'ERC1967InvalidBeacon')
.withArgs(notBeacon.address);
.withArgs(notBeacon);
});
it('non-compliant beacon', async function () {
@ -48,7 +49,7 @@ describe('BeaconProxy', function () {
describe('initialization', function () {
async function assertInitialized({ value, balance }) {
const beaconAddress = await getAddressInSlot(this.proxy, BeaconSlot);
expect(beaconAddress).to.equal(this.beacon.target);
expect(beaconAddress).to.equal(this.beacon);
const dummy = this.v1.attach(this.proxy);
expect(await dummy.value()).to.equal(value);

@ -20,36 +20,36 @@ describe('UpgradeableBeacon', function () {
it('cannot be created with non-contract implementation', async function () {
await expect(ethers.deployContract('UpgradeableBeacon', [this.other, this.admin]))
.to.be.revertedWithCustomError(this.beacon, 'BeaconInvalidImplementation')
.withArgs(this.other.address);
.withArgs(this.other);
});
describe('once deployed', async function () {
it('emits Upgraded event to the first implementation', async function () {
await expect(this.beacon.deploymentTransaction()).to.emit(this.beacon, 'Upgraded').withArgs(this.v1.target);
await expect(this.beacon.deploymentTransaction()).to.emit(this.beacon, 'Upgraded').withArgs(this.v1);
});
it('returns implementation', async function () {
expect(await this.beacon.implementation()).to.equal(this.v1.target);
expect(await this.beacon.implementation()).to.equal(this.v1);
});
it('can be upgraded by the admin', async function () {
await expect(this.beacon.connect(this.admin).upgradeTo(this.v2))
.to.emit(this.beacon, 'Upgraded')
.withArgs(this.v2.target);
.withArgs(this.v2);
expect(await this.beacon.implementation()).to.equal(this.v2.target);
expect(await this.beacon.implementation()).to.equal(this.v2);
});
it('cannot be upgraded to a non-contract', async function () {
await expect(this.beacon.connect(this.admin).upgradeTo(this.other))
.to.be.revertedWithCustomError(this.beacon, 'BeaconInvalidImplementation')
.withArgs(this.other.address);
.withArgs(this.other);
});
it('cannot be upgraded by other account', async function () {
await expect(this.beacon.connect(this.other).upgradeTo(this.v2))
.to.be.revertedWithCustomError(this.beacon, 'OwnableUnauthorizedAccount')
.withArgs(this.other.address);
.withArgs(this.other);
});
});
});

@ -1,7 +1,8 @@
const { ethers } = require('hardhat');
const { expect } = require('chai');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { getAddressInSlot, ImplementationSlot } = require('../../helpers/erc1967');
const { getAddressInSlot, ImplementationSlot } = require('../../helpers/storage');
async function fixture() {
const [admin, other] = await ethers.getSigners();
@ -27,7 +28,7 @@ describe('ProxyAdmin', function () {
});
it('has an owner', async function () {
expect(await this.proxyAdmin.owner()).to.equal(this.admin.address);
expect(await this.proxyAdmin.owner()).to.equal(this.admin);
});
it('has an interface version', async function () {
@ -39,14 +40,14 @@ describe('ProxyAdmin', function () {
it('fails to upgrade', async function () {
await expect(this.proxyAdmin.connect(this.other).upgradeAndCall(this.proxy, this.v2, '0x'))
.to.be.revertedWithCustomError(this.proxyAdmin, 'OwnableUnauthorizedAccount')
.withArgs(this.other.address);
.withArgs(this.other);
});
});
context('with authorized account', function () {
it('upgrades implementation', async function () {
await this.proxyAdmin.connect(this.admin).upgradeAndCall(this.proxy, this.v2, '0x');
expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.be.equal(this.v2.target);
expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.be.equal(this.v2);
});
});
});
@ -57,7 +58,7 @@ describe('ProxyAdmin', function () {
const data = this.v1.interface.encodeFunctionData('initializeNonPayableWithValue', [1337n]);
await expect(this.proxyAdmin.connect(this.other).upgradeAndCall(this.proxy, this.v2, data))
.to.be.revertedWithCustomError(this.proxyAdmin, 'OwnableUnauthorizedAccount')
.withArgs(this.other.address);
.withArgs(this.other);
});
});
@ -73,7 +74,7 @@ describe('ProxyAdmin', function () {
it('upgrades implementation', async function () {
const data = this.v2.interface.encodeFunctionData('initializeNonPayableWithValue', [1337n]);
await this.proxyAdmin.connect(this.admin).upgradeAndCall(this.proxy, this.v2, data);
expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.be.equal(this.v2.target);
expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.be.equal(this.v2);
});
});
});

@ -1,8 +1,8 @@
const { ethers } = require('hardhat');
const { expect } = require('chai');
const { getAddressInSlot, ImplementationSlot, AdminSlot } = require('../../helpers/erc1967');
const { impersonate } = require('../../helpers/account');
const { getAddressInSlot, ImplementationSlot, AdminSlot } = require('../../helpers/storage');
// createProxy, initialOwner, accounts
module.exports = function shouldBehaveLikeTransparentUpgradeableProxy() {
@ -43,7 +43,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy() {
describe('implementation', function () {
it('returns the current implementation address', async function () {
expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.implementationV0.target);
expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.implementationV0);
});
it('delegates to the implementation', async function () {
@ -53,26 +53,26 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy() {
describe('proxy admin', function () {
it('emits AdminChanged event during construction', async function () {
await expect(this.tx).to.emit(this.proxy, 'AdminChanged').withArgs(ethers.ZeroAddress, this.proxyAdmin.target);
await expect(this.tx).to.emit(this.proxy, 'AdminChanged').withArgs(ethers.ZeroAddress, this.proxyAdmin);
});
it('sets the proxy admin in storage with the correct initial owner', async function () {
expect(await getAddressInSlot(this.proxy, AdminSlot)).to.equal(this.proxyAdmin.target);
expect(await getAddressInSlot(this.proxy, AdminSlot)).to.equal(this.proxyAdmin);
expect(await this.proxyAdmin.owner()).to.equal(this.owner.address);
expect(await this.proxyAdmin.owner()).to.equal(this.owner);
});
it('can overwrite the admin by the implementation', async function () {
await this.instance.unsafeOverrideAdmin(this.other);
const ERC1967AdminSlotValue = await getAddressInSlot(this.proxy, AdminSlot);
expect(ERC1967AdminSlotValue).to.equal(this.other.address);
expect(ERC1967AdminSlotValue).to.not.equal(this.proxyAdmin.address);
expect(ERC1967AdminSlotValue).to.equal(this.other);
expect(ERC1967AdminSlotValue).to.not.equal(this.proxyAdmin);
// Still allows previous admin to execute admin operations
await expect(this.proxy.connect(this.proxyAdminAsSigner).upgradeToAndCall(this.implementationV1, '0x'))
.to.emit(this.proxy, 'Upgraded')
.withArgs(this.implementationV1.target);
.withArgs(this.implementationV1);
});
});
@ -99,11 +99,11 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy() {
});
it('upgrades to the requested implementation', async function () {
expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.behavior.target);
expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.behavior);
});
it('emits an event', async function () {
await expect(this.tx).to.emit(this.proxy, 'Upgraded').withArgs(this.behavior.target);
await expect(this.tx).to.emit(this.proxy, 'Upgraded').withArgs(this.behavior);
});
it('calls the initializer function', async function () {
@ -160,9 +160,9 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy() {
});
it('upgrades to the requested version and emits an event', async function () {
expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.behaviorV1.target);
expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.behaviorV1);
await expect(this.tx).to.emit(this.proxy, 'Upgraded').withArgs(this.behaviorV1.target);
await expect(this.tx).to.emit(this.proxy, 'Upgraded').withArgs(this.behaviorV1);
});
it("calls the 'initialize' function and sends given value to the proxy", async function () {
@ -184,9 +184,9 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy() {
});
it('upgrades to the requested version and emits an event', async function () {
expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.behaviorV2.target);
expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.behaviorV2);
await expect(this.tx).to.emit(this.proxy, 'Upgraded').withArgs(this.behaviorV2.target);
await expect(this.tx).to.emit(this.proxy, 'Upgraded').withArgs(this.behaviorV2);
});
it("calls the 'migrate' function and sends given value to the proxy", async function () {
@ -209,9 +209,9 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy() {
});
it('upgrades to the requested version and emits an event', async function () {
expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.behaviorV3.target);
expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.behaviorV3);
await expect(this.tx).to.emit(this.proxy, 'Upgraded').withArgs(this.behaviorV3.target);
await expect(this.tx).to.emit(this.proxy, 'Upgraded').withArgs(this.behaviorV3);
});
it("calls the 'migrate' function and sends given value to the proxy", async function () {
@ -255,7 +255,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy() {
it('executes the proxy function if the sender is the admin', async function () {
await expect(this.proxy.connect(this.proxyAdminAsSigner).upgradeToAndCall(this.clashingImplV1, '0x'))
.to.emit(this.proxy, 'Upgraded')
.withArgs(this.clashingImplV1.target);
.withArgs(this.clashingImplV1);
});
it('delegates the call to implementation when sender is not the admin', async function () {

@ -2,7 +2,7 @@ const { ethers } = require('hardhat');
const { expect } = require('chai');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { getAddressInSlot, ImplementationSlot } = require('../../helpers/erc1967');
const { getAddressInSlot, ImplementationSlot } = require('../../helpers/storage');
async function fixture() {
const implInitial = await ethers.deployContract('UUPSUpgradeableMock');
@ -40,9 +40,9 @@ describe('UUPSUpgradeable', function () {
it('upgrade to upgradeable implementation', async function () {
await expect(this.instance.upgradeToAndCall(this.implUpgradeOk, '0x'))
.to.emit(this.instance, 'Upgraded')
.withArgs(this.implUpgradeOk.target);
.withArgs(this.implUpgradeOk);
expect(await getAddressInSlot(this.instance, ImplementationSlot)).to.equal(this.implUpgradeOk.target);
expect(await getAddressInSlot(this.instance, ImplementationSlot)).to.equal(this.implUpgradeOk);
});
it('upgrade to upgradeable implementation with call', async function () {
@ -52,9 +52,9 @@ describe('UUPSUpgradeable', function () {
this.instance.upgradeToAndCall(this.implUpgradeOk, this.implUpgradeOk.interface.encodeFunctionData('increment')),
)
.to.emit(this.instance, 'Upgraded')
.withArgs(this.implUpgradeOk.target);
.withArgs(this.implUpgradeOk);
expect(await getAddressInSlot(this.instance, ImplementationSlot)).to.equal(this.implUpgradeOk.target);
expect(await getAddressInSlot(this.instance, ImplementationSlot)).to.equal(this.implUpgradeOk);
expect(await this.instance.current()).to.equal(1n);
});
@ -96,16 +96,16 @@ describe('UUPSUpgradeable', function () {
it('upgrade to and unsafe upgradeable implementation', async function () {
await expect(this.instance.upgradeToAndCall(this.implUpgradeUnsafe, '0x'))
.to.emit(this.instance, 'Upgraded')
.withArgs(this.implUpgradeUnsafe.target);
.withArgs(this.implUpgradeUnsafe);
expect(await getAddressInSlot(this.instance, ImplementationSlot)).to.equal(this.implUpgradeUnsafe.target);
expect(await getAddressInSlot(this.instance, ImplementationSlot)).to.equal(this.implUpgradeUnsafe);
});
// delegate to a non existing upgradeTo function causes a low level revert
it('reject upgrade to non uups implementation', async function () {
await expect(this.instance.upgradeToAndCall(this.implUpgradeNonUUPS, '0x'))
.to.be.revertedWithCustomError(this.instance, 'ERC1967InvalidImplementation')
.withArgs(this.implUpgradeNonUUPS.target);
.withArgs(this.implUpgradeNonUUPS);
});
it('reject proxy address as implementation', async function () {
@ -115,6 +115,6 @@ describe('UUPSUpgradeable', function () {
await expect(this.instance.upgradeToAndCall(otherInstance, '0x'))
.to.be.revertedWithCustomError(this.instance, 'ERC1967InvalidImplementation')
.withArgs(otherInstance.target);
.withArgs(otherInstance);
});
});

@ -8,16 +8,12 @@ async function fixture() {
return { signers, addresses };
}
contract('Environment sanity', function (accounts) {
describe('Environment sanity', function () {
beforeEach(async function () {
Object.assign(this, await loadFixture(fixture));
});
describe('[skip-on-coverage] signers', function () {
it('match accounts', async function () {
expect(this.addresses).to.deep.equal(accounts);
});
it('signer #0 is skipped', async function () {
const signer = await ethers.provider.getSigner(0);
expect(this.addresses).to.not.include(await signer.getAddress());

@ -2,9 +2,7 @@ const { ethers } = require('hardhat');
const { expect } = require('chai');
const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs');
const {
bigint: { RevertType },
} = require('../../helpers/enums');
const { RevertType } = require('../../helpers/enums');
const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior');
function shouldBehaveLikeERC1155() {
@ -118,9 +116,7 @@ function shouldBehaveLikeERC1155() {
});
it('emits an ApprovalForAll log', async function () {
await expect(this.tx)
.to.emit(this.token, 'ApprovalForAll')
.withArgs(this.holder.address, this.proxy.address, true);
await expect(this.tx).to.emit(this.token, 'ApprovalForAll').withArgs(this.holder, this.proxy, true);
});
it('can unset approval for an operator', async function () {
@ -148,7 +144,7 @@ function shouldBehaveLikeERC1155() {
.safeTransferFrom(this.holder, this.recipient, firstTokenId, firstTokenValue + 1n, '0x'),
)
.to.be.revertedWithCustomError(this.token, 'ERC1155InsufficientBalance')
.withArgs(this.holder.address, firstTokenValue, firstTokenValue + 1n, firstTokenId);
.withArgs(this.holder, firstTokenValue, firstTokenValue + 1n, firstTokenId);
});
it('reverts when transferring to zero address', async function () {
@ -173,13 +169,7 @@ function shouldBehaveLikeERC1155() {
it('emits a TransferSingle log', async function () {
await expect(this.tx)
.to.emit(this.token, 'TransferSingle')
.withArgs(
this.args.operator.address ?? this.args.operator.target ?? this.args.operator,
this.args.from.address ?? this.args.from.target ?? this.args.from,
this.args.to.address ?? this.args.to.target ?? this.args.to,
this.args.id,
this.args.value,
);
.withArgs(this.args.operator, this.args.from, this.args.to, this.args.id, this.args.value);
});
}
@ -219,7 +209,7 @@ function shouldBehaveLikeERC1155() {
.safeTransferFrom(this.holder, this.recipient, firstTokenId, firstTokenValue, '0x'),
)
.to.be.revertedWithCustomError(this.token, 'ERC1155MissingApprovalForAll')
.withArgs(this.proxy.address, this.holder.address);
.withArgs(this.proxy, this.holder);
});
});
@ -278,14 +268,7 @@ function shouldBehaveLikeERC1155() {
it('calls onERC1155Received', async function () {
await expect(this.tx)
.to.emit(this.receiver, 'Received')
.withArgs(
this.args.operator.address,
this.args.from.address,
this.args.id,
this.args.value,
this.args.data,
anyValue,
);
.withArgs(this.args.operator, this.args.from, this.args.id, this.args.value, this.args.data, anyValue);
});
});
@ -309,14 +292,7 @@ function shouldBehaveLikeERC1155() {
it('calls onERC1155Received', async function () {
await expect(this.tx)
.to.emit(this.receiver, 'Received')
.withArgs(
this.args.operator.address,
this.args.from.address,
this.args.id,
this.args.value,
this.args.data,
anyValue,
);
.withArgs(this.args.operator, this.args.from, this.args.id, this.args.value, this.args.data, anyValue);
});
});
});
@ -335,7 +311,7 @@ function shouldBehaveLikeERC1155() {
.safeTransferFrom(this.holder, receiver, firstTokenId, firstTokenValue, '0x'),
)
.to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver')
.withArgs(receiver.target);
.withArgs(receiver);
});
});
@ -370,7 +346,7 @@ function shouldBehaveLikeERC1155() {
.safeTransferFrom(this.holder, receiver, firstTokenId, firstTokenValue, '0x'),
)
.to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver')
.withArgs(receiver.target);
.withArgs(receiver);
});
});
@ -411,7 +387,7 @@ function shouldBehaveLikeERC1155() {
describe('to a contract that does not implement the required function', function () {
it('reverts', async function () {
const invalidReceiver = this.token.target;
const invalidReceiver = this.token;
await expect(
this.token
@ -443,7 +419,7 @@ function shouldBehaveLikeERC1155() {
),
)
.to.be.revertedWithCustomError(this.token, 'ERC1155InsufficientBalance')
.withArgs(this.holder.address, secondTokenValue, secondTokenValue + 1n, secondTokenId);
.withArgs(this.holder, secondTokenValue, secondTokenValue + 1n, secondTokenId);
});
it("reverts when ids array length doesn't match values array length", async function () {
@ -510,13 +486,7 @@ function shouldBehaveLikeERC1155() {
it('emits a TransferBatch log', async function () {
await expect(this.tx)
.to.emit(this.token, 'TransferBatch')
.withArgs(
this.args.operator.address ?? this.args.operator.target ?? this.args.operator,
this.args.from.address ?? this.args.from.target ?? this.args.from,
this.args.to.address ?? this.args.to.target ?? this.args.to,
this.args.ids,
this.args.values,
);
.withArgs(this.args.operator, this.args.from, this.args.to, this.args.ids, this.args.values);
});
}
@ -557,7 +527,7 @@ function shouldBehaveLikeERC1155() {
),
)
.to.be.revertedWithCustomError(this.token, 'ERC1155MissingApprovalForAll')
.withArgs(this.proxy.address, this.holder.address);
.withArgs(this.proxy, this.holder);
});
});
@ -616,14 +586,7 @@ function shouldBehaveLikeERC1155() {
it('calls onERC1155BatchReceived', async function () {
await expect(this.tx)
.to.emit(this.receiver, 'BatchReceived')
.withArgs(
this.holder.address,
this.holder.address,
this.args.ids,
this.args.values,
this.args.data,
anyValue,
);
.withArgs(this.holder, this.holder, this.args.ids, this.args.values, this.args.data, anyValue);
});
});
@ -647,14 +610,7 @@ function shouldBehaveLikeERC1155() {
it('calls onERC1155Received', async function () {
await expect(this.tx)
.to.emit(this.receiver, 'BatchReceived')
.withArgs(
this.holder.address,
this.holder.address,
this.args.ids,
this.args.values,
this.args.data,
anyValue,
);
.withArgs(this.holder, this.holder, this.args.ids, this.args.values, this.args.data, anyValue);
});
});
});
@ -679,7 +635,7 @@ function shouldBehaveLikeERC1155() {
),
)
.to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver')
.withArgs(receiver.target);
.withArgs(receiver);
});
});
@ -726,7 +682,7 @@ function shouldBehaveLikeERC1155() {
),
)
.to.be.revertedWithCustomError(this.token, 'ERC1155InvalidReceiver')
.withArgs(receiver.target);
.withArgs(receiver);
});
});
@ -779,7 +735,7 @@ function shouldBehaveLikeERC1155() {
describe('to a contract that does not implement the required function', function () {
it('reverts', async function () {
const invalidReceiver = this.token.target;
const invalidReceiver = this.token;
await expect(
this.token

@ -46,7 +46,7 @@ describe('ERC1155', function () {
it('emits a TransferSingle event', async function () {
await expect(this.tx)
.to.emit(this.token, 'TransferSingle')
.withArgs(this.operator.address, ethers.ZeroAddress, this.holder.address, tokenId, mintValue);
.withArgs(this.operator, ethers.ZeroAddress, this.holder, tokenId, mintValue);
});
it('credits the minted token value', async function () {
@ -80,7 +80,7 @@ describe('ERC1155', function () {
it('emits a TransferBatch event', async function () {
await expect(this.tx)
.to.emit(this.token, 'TransferBatch')
.withArgs(this.operator.address, ethers.ZeroAddress, this.holder.address, tokenBatchIds, mintValues);
.withArgs(this.operator, ethers.ZeroAddress, this.holder, tokenBatchIds, mintValues);
});
it('credits the minted batch of tokens', async function () {
@ -104,7 +104,7 @@ describe('ERC1155', function () {
it('reverts when burning a non-existent token id', async function () {
await expect(this.token.$_burn(this.holder, tokenId, mintValue))
.to.be.revertedWithCustomError(this.token, 'ERC1155InsufficientBalance')
.withArgs(this.holder.address, 0, mintValue, tokenId);
.withArgs(this.holder, 0, mintValue, tokenId);
});
it('reverts when burning more than available tokens', async function () {
@ -112,7 +112,7 @@ describe('ERC1155', function () {
await expect(this.token.$_burn(this.holder, tokenId, mintValue + 1n))
.to.be.revertedWithCustomError(this.token, 'ERC1155InsufficientBalance')
.withArgs(this.holder.address, mintValue, mintValue + 1n, tokenId);
.withArgs(this.holder, mintValue, mintValue + 1n, tokenId);
});
describe('with minted-then-burnt tokens', function () {
@ -124,7 +124,7 @@ describe('ERC1155', function () {
it('emits a TransferSingle event', async function () {
await expect(this.tx)
.to.emit(this.token, 'TransferSingle')
.withArgs(this.operator.address, this.holder.address, ethers.ZeroAddress, tokenId, burnValue);
.withArgs(this.operator, this.holder, ethers.ZeroAddress, tokenId, burnValue);
});
it('accounts for both minting and burning', async function () {
@ -153,7 +153,7 @@ describe('ERC1155', function () {
it('reverts when burning a non-existent token id', async function () {
await expect(this.token.$_burnBatch(this.holder, tokenBatchIds, burnValues))
.to.be.revertedWithCustomError(this.token, 'ERC1155InsufficientBalance')
.withArgs(this.holder.address, 0, burnValues[0], tokenBatchIds[0]);
.withArgs(this.holder, 0, burnValues[0], tokenBatchIds[0]);
});
describe('with minted-then-burnt tokens', function () {
@ -165,7 +165,7 @@ describe('ERC1155', function () {
it('emits a TransferBatch event', async function () {
await expect(this.tx)
.to.emit(this.token, 'TransferBatch')
.withArgs(this.operator.address, this.holder.address, ethers.ZeroAddress, tokenBatchIds, burnValues);
.withArgs(this.operator, this.holder, ethers.ZeroAddress, tokenBatchIds, burnValues);
});
it('accounts for both minting and burning', async function () {

@ -37,7 +37,7 @@ describe('ERC1155Burnable', function () {
it("unapproved accounts cannot burn the holder's tokens", async function () {
await expect(this.token.connect(this.other).burn(this.holder, ids[0], values[0] - 1n))
.to.be.revertedWithCustomError(this.token, 'ERC1155MissingApprovalForAll')
.withArgs(this.other.address, this.holder.address);
.withArgs(this.other, this.holder);
});
});
@ -60,7 +60,7 @@ describe('ERC1155Burnable', function () {
it("unapproved accounts cannot burn the holder's tokens", async function () {
await expect(this.token.connect(this.other).burnBatch(this.holder, ids, [values[0] - 1n, values[1] - 2n]))
.to.be.revertedWithCustomError(this.token, 'ERC1155MissingApprovalForAll')
.withArgs(this.other.address, this.holder.address);
.withArgs(this.other, this.holder);
});
});
});

@ -8,7 +8,7 @@ async function fixture() {
return { token, holder, operator, receiver, other };
}
contract('ERC1155Pausable', function () {
describe('ERC1155Pausable', function () {
const firstTokenId = 37n;
const firstTokenValue = 42n;
const secondTokenId = 19842n;

@ -58,7 +58,7 @@ function shouldBehaveLikeERC20(initialSupply, opts = {}) {
it('emits a transfer event', async function () {
await expect(this.tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.initialHolder.address, this.anotherAccount.address, value);
.withArgs(this.initialHolder, this.anotherAccount, value);
});
if (forcedApproval) {
@ -85,7 +85,7 @@ function shouldBehaveLikeERC20(initialSupply, opts = {}) {
this.token.connect(this.recipient).transferFrom(this.initialHolder, this.anotherAccount, value),
)
.to.revertedWithCustomError(this.token, 'ERC20InsufficientBalance')
.withArgs(this.initialHolder.address, value - 1n, value);
.withArgs(this.initialHolder, value - 1n, value);
});
});
@ -102,7 +102,7 @@ function shouldBehaveLikeERC20(initialSupply, opts = {}) {
this.token.connect(this.recipient).transferFrom(this.initialHolder, this.anotherAccount, value),
)
.to.be.revertedWithCustomError(this.token, 'ERC20InsufficientAllowance')
.withArgs(this.recipient.address, allowance, value);
.withArgs(this.recipient, allowance, value);
});
it('reverts when the token owner does not have enough balance', async function () {
@ -112,7 +112,7 @@ function shouldBehaveLikeERC20(initialSupply, opts = {}) {
this.token.connect(this.recipient).transferFrom(this.initialHolder, this.anotherAccount, value),
)
.to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance')
.withArgs(this.initialHolder.address, value - 1n, value);
.withArgs(this.initialHolder, value - 1n, value);
});
});
@ -166,7 +166,7 @@ function shouldBehaveLikeERC20Transfer(balance) {
const value = balance + 1n;
await expect(this.transfer(this.initialHolder, this.recipient, value))
.to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance')
.withArgs(this.initialHolder.address, balance, value);
.withArgs(this.initialHolder, balance, value);
});
describe('when the sender transfers all balance', function () {
@ -181,9 +181,7 @@ function shouldBehaveLikeERC20Transfer(balance) {
});
it('emits a transfer event', async function () {
await expect(this.tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.initialHolder.address, this.recipient.address, value);
await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(this.initialHolder, this.recipient, value);
});
});
@ -199,9 +197,7 @@ function shouldBehaveLikeERC20Transfer(balance) {
});
it('emits a transfer event', async function () {
await expect(this.tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.initialHolder.address, this.recipient.address, value);
await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(this.initialHolder, this.recipient, value);
});
});
});
@ -221,7 +217,7 @@ function shouldBehaveLikeERC20Approve(supply) {
it('emits an approval event', async function () {
await expect(this.approve(this.initialHolder, this.recipient, value))
.to.emit(this.token, 'Approval')
.withArgs(this.initialHolder.address, this.recipient.address, value);
.withArgs(this.initialHolder, this.recipient, value);
});
it('approves the requested value when there was no approved value before', async function () {
@ -244,7 +240,7 @@ function shouldBehaveLikeERC20Approve(supply) {
it('emits an approval event', async function () {
await expect(this.approve(this.initialHolder, this.recipient, value))
.to.emit(this.token, 'Approval')
.withArgs(this.initialHolder.address, this.recipient.address, value);
.withArgs(this.initialHolder, this.recipient, value);
});
it('approves the requested value when there was no approved value before', async function () {

@ -73,9 +73,7 @@ describe('ERC20', function () {
});
it('emits Transfer event', async function () {
await expect(this.tx)
.to.emit(this.token, 'Transfer')
.withArgs(ethers.ZeroAddress, this.recipient.address, value);
await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(ethers.ZeroAddress, this.recipient, value);
});
});
});
@ -91,7 +89,7 @@ describe('ERC20', function () {
it('rejects burning more than balance', async function () {
await expect(this.token.$_burn(this.initialHolder, initialSupply + 1n))
.to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance')
.withArgs(this.initialHolder.address, initialSupply, initialSupply + 1n);
.withArgs(this.initialHolder, initialSupply, initialSupply + 1n);
});
const describeBurn = function (description, value) {
@ -111,7 +109,7 @@ describe('ERC20', function () {
it('emits Transfer event', async function () {
await expect(this.tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.initialHolder.address, ethers.ZeroAddress, value);
.withArgs(this.initialHolder, ethers.ZeroAddress, value);
});
});
};
@ -130,9 +128,7 @@ describe('ERC20', function () {
it('from is the zero address', async function () {
const tx = await this.token.$_update(ethers.ZeroAddress, this.initialHolder, value);
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(ethers.ZeroAddress, this.initialHolder.address, value);
await expect(tx).to.emit(this.token, 'Transfer').withArgs(ethers.ZeroAddress, this.initialHolder, value);
expect(await this.token.totalSupply()).to.equal(this.totalSupply + value);
await expect(tx).to.changeTokenBalance(this.token, this.initialHolder, value);
@ -140,9 +136,7 @@ describe('ERC20', function () {
it('to is the zero address', async function () {
const tx = await this.token.$_update(this.initialHolder, ethers.ZeroAddress, value);
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.initialHolder.address, ethers.ZeroAddress, value);
await expect(tx).to.emit(this.token, 'Transfer').withArgs(this.initialHolder, ethers.ZeroAddress, value);
expect(await this.token.totalSupply()).to.equal(this.totalSupply - value);
await expect(tx).to.changeTokenBalance(this.token, this.initialHolder, -value);
@ -161,15 +155,13 @@ describe('ERC20', function () {
it('reverts without balance', async function () {
await expect(this.token.$_update(this.recipient, this.recipient, value))
.to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance')
.withArgs(this.recipient.address, 0n, value);
.withArgs(this.recipient, 0n, value);
});
it('executes with balance', async function () {
const tx = await this.token.$_update(this.initialHolder, this.initialHolder, value);
await expect(tx).to.changeTokenBalance(this.token, this.initialHolder, 0n);
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.initialHolder.address, this.initialHolder.address, value);
await expect(tx).to.emit(this.token, 'Transfer').withArgs(this.initialHolder, this.initialHolder, value);
});
});
});

@ -26,7 +26,7 @@ describe('ERC20Burnable', function () {
await expect(this.token.connect(this.owner).burn(value))
.to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance')
.withArgs(this.owner.address, this.initialBalance, value);
.withArgs(this.owner, this.initialBalance, value);
});
describe('on success', function () {
@ -44,9 +44,7 @@ describe('ERC20Burnable', function () {
});
it('emits a transfer event', async function () {
await expect(this.tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.owner.address, ethers.ZeroAddress, value);
await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(this.owner, ethers.ZeroAddress, value);
});
});
}
@ -62,7 +60,7 @@ describe('ERC20Burnable', function () {
await expect(this.token.connect(this.burner).burnFrom(this.owner, value))
.to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance')
.withArgs(this.owner.address, this.initialBalance, value);
.withArgs(this.owner, this.initialBalance, value);
});
it('if not enough allowance', async function () {
@ -72,7 +70,7 @@ describe('ERC20Burnable', function () {
await expect(this.token.connect(this.burner).burnFrom(this.owner, allowance + 1n))
.to.be.revertedWithCustomError(this.token, 'ERC20InsufficientAllowance')
.withArgs(this.burner.address, allowance, allowance + 1n);
.withArgs(this.burner, allowance, allowance + 1n);
});
});
@ -98,9 +96,7 @@ describe('ERC20Burnable', function () {
});
it('emits a transfer event', async function () {
await expect(this.tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.owner.address, ethers.ZeroAddress, value);
await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(this.owner, ethers.ZeroAddress, value);
});
});
}

@ -56,13 +56,13 @@ describe('ERC20FlashMint', function () {
const tx = await this.token.flashLoan(receiver, this.token, loanValue, '0x');
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(ethers.ZeroAddress, receiver.target, loanValue)
.withArgs(ethers.ZeroAddress, receiver, loanValue)
.to.emit(this.token, 'Transfer')
.withArgs(receiver.target, ethers.ZeroAddress, loanValue)
.withArgs(receiver, ethers.ZeroAddress, loanValue)
.to.emit(receiver, 'BalanceOf')
.withArgs(this.token.target, receiver.target, loanValue)
.withArgs(this.token, receiver, loanValue)
.to.emit(receiver, 'TotalSupply')
.withArgs(this.token.target, initialSupply + loanValue);
.withArgs(this.token, initialSupply + loanValue);
await expect(tx).to.changeTokenBalance(this.token, receiver, 0);
expect(await this.token.totalSupply()).to.equal(initialSupply);
@ -73,14 +73,14 @@ describe('ERC20FlashMint', function () {
const receiver = await ethers.deployContract('ERC3156FlashBorrowerMock', [false, true]);
await expect(this.token.flashLoan(receiver, this.token, loanValue, '0x'))
.to.be.revertedWithCustomError(this.token, 'ERC3156InvalidReceiver')
.withArgs(receiver.target);
.withArgs(receiver);
});
it('missing approval', async function () {
const receiver = await ethers.deployContract('ERC3156FlashBorrowerMock', [true, false]);
await expect(this.token.flashLoan(receiver, this.token, loanValue, '0x'))
.to.be.revertedWithCustomError(this.token, 'ERC20InsufficientAllowance')
.withArgs(this.token.target, 0, loanValue);
.withArgs(this.token, 0, loanValue);
});
it('unavailable funds', async function () {
@ -88,7 +88,7 @@ describe('ERC20FlashMint', function () {
const data = this.token.interface.encodeFunctionData('transfer', [this.other.address, 10]);
await expect(this.token.flashLoan(receiver, this.token, loanValue, data))
.to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance')
.withArgs(receiver.target, loanValue - 10n, loanValue);
.withArgs(receiver, loanValue - 10n, loanValue);
});
it('more than maxFlashLoan', async function () {
@ -109,7 +109,7 @@ describe('ERC20FlashMint', function () {
const tx = await this.token.$_mint(this.receiver, receiverInitialBalance);
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(ethers.ZeroAddress, this.receiver.target, receiverInitialBalance);
.withArgs(ethers.ZeroAddress, this.receiver, receiverInitialBalance);
await expect(tx).to.changeTokenBalance(this.token, this.receiver, receiverInitialBalance);
await this.token.setFlashFee(flashFee);
@ -120,13 +120,13 @@ describe('ERC20FlashMint', function () {
const tx = await this.token.flashLoan(this.receiver, this.token, loanValue, '0x');
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(ethers.ZeroAddress, this.receiver.target, loanValue)
.withArgs(ethers.ZeroAddress, this.receiver, loanValue)
.to.emit(this.token, 'Transfer')
.withArgs(this.receiver.target, ethers.ZeroAddress, loanValue + flashFee)
.withArgs(this.receiver, ethers.ZeroAddress, loanValue + flashFee)
.to.emit(this.receiver, 'BalanceOf')
.withArgs(this.token.target, this.receiver.target, receiverInitialBalance + loanValue)
.withArgs(this.token, this.receiver, receiverInitialBalance + loanValue)
.to.emit(this.receiver, 'TotalSupply')
.withArgs(this.token.target, initialSupply + receiverInitialBalance + loanValue);
.withArgs(this.token, initialSupply + receiverInitialBalance + loanValue);
await expect(tx).to.changeTokenBalances(this.token, [this.receiver, ethers.ZeroAddress], [-flashFee, 0]);
expect(await this.token.totalSupply()).to.equal(initialSupply + receiverInitialBalance - flashFee);
@ -136,20 +136,20 @@ describe('ERC20FlashMint', function () {
it('custom flash fee receiver', async function () {
const flashFeeReceiverAddress = this.anotherAccount;
await this.token.setFlashFeeReceiver(flashFeeReceiverAddress);
expect(await this.token.$_flashFeeReceiver()).to.equal(flashFeeReceiverAddress.address);
expect(await this.token.$_flashFeeReceiver()).to.equal(flashFeeReceiverAddress);
const tx = await this.token.flashLoan(this.receiver, this.token, loanValue, '0x');
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(ethers.ZeroAddress, this.receiver.target, loanValue)
.withArgs(ethers.ZeroAddress, this.receiver, loanValue)
.to.emit(this.token, 'Transfer')
.withArgs(this.receiver.target, ethers.ZeroAddress, loanValue)
.withArgs(this.receiver, ethers.ZeroAddress, loanValue)
.to.emit(this.token, 'Transfer')
.withArgs(this.receiver.target, flashFeeReceiverAddress.address, flashFee)
.withArgs(this.receiver, flashFeeReceiverAddress, flashFee)
.to.emit(this.receiver, 'BalanceOf')
.withArgs(this.token.target, this.receiver.target, receiverInitialBalance + loanValue)
.withArgs(this.token, this.receiver, receiverInitialBalance + loanValue)
.to.emit(this.receiver, 'TotalSupply')
.withArgs(this.token.target, initialSupply + receiverInitialBalance + loanValue);
.withArgs(this.token, initialSupply + receiverInitialBalance + loanValue);
await expect(tx).to.changeTokenBalances(
this.token,
[this.receiver, flashFeeReceiverAddress],

@ -3,7 +3,7 @@ const { expect } = require('chai');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { getDomain, domainSeparator, Permit } = require('../../../helpers/eip712');
const { bigint: time } = require('../../../helpers/time');
const time = require('../../../helpers/time');
const name = 'My Token';
const symbol = 'MTKN';
@ -81,7 +81,7 @@ describe('ERC20Permit', function () {
await expect(this.token.permit(this.owner, this.spender, value, maxDeadline, v, r, s))
.to.be.revertedWithCustomError(this.token, 'ERC2612InvalidSigner')
.withArgs(recovered, this.owner.address);
.withArgs(recovered, this.owner);
});
it('rejects other signature', async function () {
@ -91,7 +91,7 @@ describe('ERC20Permit', function () {
await expect(this.token.permit(this.owner, this.spender, value, maxDeadline, v, r, s))
.to.be.revertedWithCustomError(this.token, 'ERC2612InvalidSigner')
.withArgs(this.other.address, this.owner.address);
.withArgs(this.other, this.owner);
});
it('rejects expired permit', async function () {

@ -4,7 +4,7 @@ const { loadFixture, mine } = require('@nomicfoundation/hardhat-network-helpers'
const { getDomain, Delegation } = require('../../../helpers/eip712');
const { batchInBlock } = require('../../../helpers/txpool');
const { bigint: time } = require('../../../helpers/time');
const time = require('../../../helpers/time');
const { shouldBehaveLikeVotes } = require('../../../governance/utils/Votes.behavior');
@ -75,11 +75,11 @@ describe('ERC20Votes', function () {
await expect(tx)
.to.emit(this.token, 'DelegateChanged')
.withArgs(this.holder.address, ethers.ZeroAddress, this.holder.address)
.withArgs(this.holder, ethers.ZeroAddress, this.holder)
.to.emit(this.token, 'DelegateVotesChanged')
.withArgs(this.holder.address, 0n, supply);
.withArgs(this.holder, 0n, supply);
expect(await this.token.delegates(this.holder)).to.equal(this.holder.address);
expect(await this.token.delegates(this.holder)).to.equal(this.holder);
expect(await this.token.getVotes(this.holder)).to.equal(supply);
expect(await this.token.getPastVotes(this.holder, timepoint - 1n)).to.equal(0n);
await mine();
@ -91,10 +91,10 @@ describe('ERC20Votes', function () {
await expect(this.token.connect(this.holder).delegate(this.holder))
.to.emit(this.token, 'DelegateChanged')
.withArgs(this.holder.address, ethers.ZeroAddress, this.holder.address)
.withArgs(this.holder, ethers.ZeroAddress, this.holder)
.to.not.emit(this.token, 'DelegateVotesChanged');
expect(await this.token.delegates(this.holder)).to.equal(this.holder.address);
expect(await this.token.delegates(this.holder)).to.equal(this.holder);
});
});
@ -125,11 +125,11 @@ describe('ERC20Votes', function () {
await expect(tx)
.to.emit(this.token, 'DelegateChanged')
.withArgs(this.holder.address, ethers.ZeroAddress, this.holder.address)
.withArgs(this.holder, ethers.ZeroAddress, this.holder)
.to.emit(this.token, 'DelegateVotesChanged')
.withArgs(this.holder.address, 0n, supply);
.withArgs(this.holder, 0n, supply);
expect(await this.token.delegates(this.holder)).to.equal(this.holder.address);
expect(await this.token.delegates(this.holder)).to.equal(this.holder);
expect(await this.token.getVotes(this.holder)).to.equal(supply);
expect(await this.token.getPastVotes(this.holder, timepoint - 1n)).to.equal(0n);
@ -154,7 +154,7 @@ describe('ERC20Votes', function () {
await expect(this.token.delegateBySig(this.holder, nonce, ethers.MaxUint256, v, r, s))
.to.be.revertedWithCustomError(this.token, 'InvalidAccountNonce')
.withArgs(this.holder.address, nonce + 1n);
.withArgs(this.holder, nonce + 1n);
});
it('rejects bad delegatee', async function () {
@ -175,9 +175,9 @@ describe('ERC20Votes', function () {
const { args } = await tx
.wait()
.then(receipt => receipt.logs.find(event => event.fragment.name == 'DelegateChanged'));
expect(args[0]).to.not.equal(this.holder.address);
expect(args[0]).to.not.equal(this.holder);
expect(args[1]).to.equal(ethers.ZeroAddress);
expect(args[2]).to.equal(this.delegatee.address);
expect(args[2]).to.equal(this.delegatee);
});
it('rejects bad nonce', async function () {
@ -238,20 +238,20 @@ describe('ERC20Votes', function () {
});
it('call', async function () {
expect(await this.token.delegates(this.holder)).to.equal(this.holder.address);
expect(await this.token.delegates(this.holder)).to.equal(this.holder);
const tx = await this.token.connect(this.holder).delegate(this.delegatee);
const timepoint = await time.clockFromReceipt[mode](tx);
await expect(tx)
.to.emit(this.token, 'DelegateChanged')
.withArgs(this.holder.address, this.holder.address, this.delegatee.address)
.withArgs(this.holder, this.holder, this.delegatee)
.to.emit(this.token, 'DelegateVotesChanged')
.withArgs(this.holder.address, supply, 0n)
.withArgs(this.holder, supply, 0n)
.to.emit(this.token, 'DelegateVotesChanged')
.withArgs(this.delegatee.address, 0n, supply);
.withArgs(this.delegatee, 0n, supply);
expect(await this.token.delegates(this.holder)).to.equal(this.delegatee.address);
expect(await this.token.delegates(this.holder)).to.equal(this.delegatee);
expect(await this.token.getVotes(this.holder)).to.equal(0n);
expect(await this.token.getVotes(this.delegatee)).to.equal(supply);
@ -271,7 +271,7 @@ describe('ERC20Votes', function () {
it('no delegation', async function () {
await expect(this.token.connect(this.holder).transfer(this.recipient, 1n))
.to.emit(this.token, 'Transfer')
.withArgs(this.holder.address, this.recipient.address, 1n)
.withArgs(this.holder, this.recipient, 1n)
.to.not.emit(this.token, 'DelegateVotesChanged');
this.holderVotes = 0n;
@ -284,9 +284,9 @@ describe('ERC20Votes', function () {
const tx = await this.token.connect(this.holder).transfer(this.recipient, 1n);
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.holder.address, this.recipient.address, 1n)
.withArgs(this.holder, this.recipient, 1n)
.to.emit(this.token, 'DelegateVotesChanged')
.withArgs(this.holder.address, supply, supply - 1n);
.withArgs(this.holder, supply, supply - 1n);
const { logs } = await tx.wait();
const { index } = logs.find(event => event.fragment.name == 'DelegateVotesChanged');
@ -304,9 +304,9 @@ describe('ERC20Votes', function () {
const tx = await this.token.connect(this.holder).transfer(this.recipient, 1n);
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.holder.address, this.recipient.address, 1n)
.withArgs(this.holder, this.recipient, 1n)
.to.emit(this.token, 'DelegateVotesChanged')
.withArgs(this.recipient.address, 0n, 1n);
.withArgs(this.recipient, 0n, 1n);
const { logs } = await tx.wait();
const { index } = logs.find(event => event.fragment.name == 'DelegateVotesChanged');
@ -325,11 +325,11 @@ describe('ERC20Votes', function () {
const tx = await this.token.connect(this.holder).transfer(this.recipient, 1n);
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.holder.address, this.recipient.address, 1n)
.withArgs(this.holder, this.recipient, 1n)
.to.emit(this.token, 'DelegateVotesChanged')
.withArgs(this.holder.address, supply, supply - 1n)
.withArgs(this.holder, supply, supply - 1n)
.to.emit(this.token, 'DelegateVotesChanged')
.withArgs(this.recipient.address, 0n, 1n);
.withArgs(this.recipient, 0n, 1n);
const { logs } = await tx.wait();
const { index } = logs.find(event => event.fragment.name == 'DelegateVotesChanged');

@ -48,7 +48,7 @@ describe('ERC20Wrapper', function () {
});
it('has underlying', async function () {
expect(await this.token.underlying()).to.be.equal(this.underlying.target);
expect(await this.token.underlying()).to.be.equal(this.underlying);
});
describe('deposit', function () {
@ -58,9 +58,9 @@ describe('ERC20Wrapper', function () {
const tx = await this.token.connect(this.initialHolder).depositFor(this.initialHolder, initialSupply);
await expect(tx)
.to.emit(this.underlying, 'Transfer')
.withArgs(this.initialHolder.address, this.token.target, initialSupply)
.withArgs(this.initialHolder, this.token, initialSupply)
.to.emit(this.token, 'Transfer')
.withArgs(ethers.ZeroAddress, this.initialHolder.address, initialSupply);
.withArgs(ethers.ZeroAddress, this.initialHolder, initialSupply);
await expect(tx).to.changeTokenBalances(
this.underlying,
[this.initialHolder, this.token],
@ -72,7 +72,7 @@ describe('ERC20Wrapper', function () {
it('reverts when missing approval', async function () {
await expect(this.token.connect(this.initialHolder).depositFor(this.initialHolder, initialSupply))
.to.be.revertedWithCustomError(this.underlying, 'ERC20InsufficientAllowance')
.withArgs(this.token.target, 0, initialSupply);
.withArgs(this.token, 0, initialSupply);
});
it('reverts when inssuficient balance', async function () {
@ -80,7 +80,7 @@ describe('ERC20Wrapper', function () {
await expect(this.token.connect(this.initialHolder).depositFor(this.initialHolder, ethers.MaxUint256))
.to.be.revertedWithCustomError(this.underlying, 'ERC20InsufficientBalance')
.withArgs(this.initialHolder.address, initialSupply, ethers.MaxUint256);
.withArgs(this.initialHolder, initialSupply, ethers.MaxUint256);
});
it('deposits to other account', async function () {
@ -89,9 +89,9 @@ describe('ERC20Wrapper', function () {
const tx = await this.token.connect(this.initialHolder).depositFor(this.recipient, initialSupply);
await expect(tx)
.to.emit(this.underlying, 'Transfer')
.withArgs(this.initialHolder.address, this.token.target, initialSupply)
.withArgs(this.initialHolder, this.token, initialSupply)
.to.emit(this.token, 'Transfer')
.withArgs(ethers.ZeroAddress, this.recipient.address, initialSupply);
.withArgs(ethers.ZeroAddress, this.recipient, initialSupply);
await expect(tx).to.changeTokenBalances(
this.underlying,
[this.initialHolder, this.token],
@ -105,7 +105,7 @@ describe('ERC20Wrapper', function () {
await expect(this.token.connect(this.initialHolder).depositFor(this.token, ethers.MaxUint256))
.to.be.revertedWithCustomError(this.token, 'ERC20InvalidReceiver')
.withArgs(this.token.target);
.withArgs(this.token);
});
});
@ -118,7 +118,7 @@ describe('ERC20Wrapper', function () {
it('reverts when inssuficient balance', async function () {
await expect(this.token.connect(this.initialHolder).withdrawTo(this.initialHolder, ethers.MaxInt256))
.to.be.revertedWithCustomError(this.token, 'ERC20InsufficientBalance')
.withArgs(this.initialHolder.address, initialSupply, ethers.MaxInt256);
.withArgs(this.initialHolder, initialSupply, ethers.MaxInt256);
});
it('executes when operation is valid', async function () {
@ -127,9 +127,9 @@ describe('ERC20Wrapper', function () {
const tx = await this.token.connect(this.initialHolder).withdrawTo(this.initialHolder, value);
await expect(tx)
.to.emit(this.underlying, 'Transfer')
.withArgs(this.token.target, this.initialHolder.address, value)
.withArgs(this.token, this.initialHolder, value)
.to.emit(this.token, 'Transfer')
.withArgs(this.initialHolder.address, ethers.ZeroAddress, value);
.withArgs(this.initialHolder, ethers.ZeroAddress, value);
await expect(tx).to.changeTokenBalances(this.underlying, [this.token, this.initialHolder], [-value, value]);
await expect(tx).to.changeTokenBalance(this.token, this.initialHolder, -value);
});
@ -138,9 +138,9 @@ describe('ERC20Wrapper', function () {
const tx = await this.token.connect(this.initialHolder).withdrawTo(this.initialHolder, initialSupply);
await expect(tx)
.to.emit(this.underlying, 'Transfer')
.withArgs(this.token.target, this.initialHolder.address, initialSupply)
.withArgs(this.token, this.initialHolder, initialSupply)
.to.emit(this.token, 'Transfer')
.withArgs(this.initialHolder.address, ethers.ZeroAddress, initialSupply);
.withArgs(this.initialHolder, ethers.ZeroAddress, initialSupply);
await expect(tx).to.changeTokenBalances(
this.underlying,
[this.token, this.initialHolder],
@ -153,9 +153,9 @@ describe('ERC20Wrapper', function () {
const tx = await this.token.connect(this.initialHolder).withdrawTo(this.recipient, initialSupply);
await expect(tx)
.to.emit(this.underlying, 'Transfer')
.withArgs(this.token.target, this.recipient.address, initialSupply)
.withArgs(this.token, this.recipient, initialSupply)
.to.emit(this.token, 'Transfer')
.withArgs(this.initialHolder.address, ethers.ZeroAddress, initialSupply);
.withArgs(this.initialHolder, ethers.ZeroAddress, initialSupply);
await expect(tx).to.changeTokenBalances(
this.underlying,
[this.token, this.initialHolder, this.recipient],
@ -167,7 +167,7 @@ describe('ERC20Wrapper', function () {
it('reverts withdrawing to the wrapper contract', async function () {
await expect(this.token.connect(this.initialHolder).withdrawTo(this.token, initialSupply))
.to.be.revertedWithCustomError(this.token, 'ERC20InvalidReceiver')
.withArgs(this.token.target);
.withArgs(this.token);
});
});
@ -177,7 +177,7 @@ describe('ERC20Wrapper', function () {
await this.token.connect(this.initialHolder).depositFor(this.initialHolder, initialSupply);
const tx = await this.token.$_recover(this.recipient);
await expect(tx).to.emit(this.token, 'Transfer').withArgs(ethers.ZeroAddress, this.recipient.address, 0n);
await expect(tx).to.emit(this.token, 'Transfer').withArgs(ethers.ZeroAddress, this.recipient, 0n);
await expect(tx).to.changeTokenBalance(this.token, this.recipient, 0);
});
@ -185,9 +185,7 @@ describe('ERC20Wrapper', function () {
await this.underlying.connect(this.initialHolder).transfer(this.token, initialSupply);
const tx = await this.token.$_recover(this.recipient);
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(ethers.ZeroAddress, this.recipient.address, initialSupply);
await expect(tx).to.emit(this.token, 'Transfer').withArgs(ethers.ZeroAddress, this.recipient, initialSupply);
await expect(tx).to.changeTokenBalance(this.token, this.recipient, initialSupply);
});
});

@ -3,9 +3,7 @@ const { expect } = require('chai');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic');
const {
bigint: { Enum },
} = require('../../../helpers/enums');
const { Enum } = require('../../../helpers/enums');
const name = 'My Token';
const symbol = 'MTKN';
@ -90,10 +88,10 @@ describe('ERC4626', function () {
await expect(this.vault.connect(this.holder).deposit(value, this.holder))
// Deposit normally, reentering before the internal `_update`
.to.emit(this.vault, 'Deposit')
.withArgs(this.holder.address, this.holder.address, value, sharesForDeposit)
.withArgs(this.holder, this.holder, value, sharesForDeposit)
// Reentrant deposit event → uses the same price
.to.emit(this.vault, 'Deposit')
.withArgs(this.token.target, this.holder.address, reenterValue, sharesForReenter);
.withArgs(this.token, this.holder, reenterValue, sharesForReenter);
// Assert prices is kept
expect(await this.vault.previewDeposit(value)).to.equal(sharesForDeposit);
@ -123,10 +121,10 @@ describe('ERC4626', function () {
await expect(this.vault.connect(this.holder).withdraw(value, this.holder, this.holder))
// Main withdraw event
.to.emit(this.vault, 'Withdraw')
.withArgs(this.holder.address, this.holder.address, this.holder.address, value, sharesForWithdraw)
.withArgs(this.holder, this.holder, this.holder, value, sharesForWithdraw)
// Reentrant withdraw event → uses the same price
.to.emit(this.vault, 'Withdraw')
.withArgs(this.token.target, this.holder.address, this.token.target, reenterValue, sharesForReenter);
.withArgs(this.token, this.holder, this.token, reenterValue, sharesForReenter);
// Assert price is kept
expect(await this.vault.previewWithdraw(value)).to.equal(sharesForWithdraw);
@ -150,7 +148,7 @@ describe('ERC4626', function () {
await expect(this.vault.connect(this.holder).deposit(value, this.holder))
// Price is as previewed
.to.emit(this.vault, 'Deposit')
.withArgs(this.holder.address, this.holder.address, value, sharesBefore);
.withArgs(this.holder, this.holder, value, sharesBefore);
// Price was modified during reentrancy
expect(await this.vault.previewDeposit(value)).to.lt(sharesBefore);
@ -177,7 +175,7 @@ describe('ERC4626', function () {
await expect(this.vault.connect(this.holder).withdraw(value, this.holder, this.holder))
// Price is as previewed
.to.emit(this.vault, 'Withdraw')
.withArgs(this.holder.address, this.holder.address, this.holder.address, value, sharesBefore);
.withArgs(this.holder, this.holder, this.holder, value, sharesBefore);
// Price was modified during reentrancy
expect(await this.vault.previewWithdraw(value)).to.gt(sharesBefore);
@ -196,7 +194,7 @@ describe('ERC4626', function () {
const maxDeposit = await this.vault.maxDeposit(this.holder);
await expect(this.vault.connect(this.holder).deposit(maxDeposit + 1n, this.recipient))
.to.be.revertedWithCustomError(this.vault, 'ERC4626ExceededMaxDeposit')
.withArgs(this.recipient.address, maxDeposit + 1n, maxDeposit);
.withArgs(this.recipient, maxDeposit + 1n, maxDeposit);
});
it('reverts on mint() above max mint', async function () {
@ -204,7 +202,7 @@ describe('ERC4626', function () {
await expect(this.vault.connect(this.holder).mint(maxMint + 1n, this.recipient))
.to.be.revertedWithCustomError(this.vault, 'ERC4626ExceededMaxMint')
.withArgs(this.recipient.address, maxMint + 1n, maxMint);
.withArgs(this.recipient, maxMint + 1n, maxMint);
});
it('reverts on withdraw() above max withdraw', async function () {
@ -212,7 +210,7 @@ describe('ERC4626', function () {
await expect(this.vault.connect(this.holder).withdraw(maxWithdraw + 1n, this.recipient, this.holder))
.to.be.revertedWithCustomError(this.vault, 'ERC4626ExceededMaxWithdraw')
.withArgs(this.holder.address, maxWithdraw + 1n, maxWithdraw);
.withArgs(this.holder, maxWithdraw + 1n, maxWithdraw);
});
it('reverts on redeem() above max redeem', async function () {
@ -220,7 +218,7 @@ describe('ERC4626', function () {
await expect(this.vault.connect(this.holder).redeem(maxRedeem + 1n, this.recipient, this.holder))
.to.be.revertedWithCustomError(this.vault, 'ERC4626ExceededMaxRedeem')
.withArgs(this.holder.address, maxRedeem + 1n, maxRedeem);
.withArgs(this.holder, maxRedeem + 1n, maxRedeem);
});
});
@ -247,7 +245,7 @@ describe('ERC4626', function () {
expect(await this.vault.name()).to.equal(name + ' Vault');
expect(await this.vault.symbol()).to.equal(symbol + 'V');
expect(await this.vault.decimals()).to.equal(decimals + offset);
expect(await this.vault.asset()).to.equal(this.token.target);
expect(await this.vault.asset()).to.equal(this.token);
});
describe('empty vault: no assets & no shares', function () {
@ -269,11 +267,11 @@ describe('ERC4626', function () {
await expect(tx).to.changeTokenBalance(this.vault, this.recipient, parseShare(1n));
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.holder.address, this.vault.target, parseToken(1n))
.withArgs(this.holder, this.vault, parseToken(1n))
.to.emit(this.vault, 'Transfer')
.withArgs(ethers.ZeroAddress, this.recipient.address, parseShare(1n))
.withArgs(ethers.ZeroAddress, this.recipient, parseShare(1n))
.to.emit(this.vault, 'Deposit')
.withArgs(this.holder.address, this.recipient.address, parseToken(1n), parseShare(1n));
.withArgs(this.holder, this.recipient, parseToken(1n), parseShare(1n));
});
it('mint', async function () {
@ -290,11 +288,11 @@ describe('ERC4626', function () {
await expect(tx).to.changeTokenBalance(this.vault, this.recipient, parseShare(1n));
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.holder.address, this.vault.target, parseToken(1n))
.withArgs(this.holder, this.vault, parseToken(1n))
.to.emit(this.vault, 'Transfer')
.withArgs(ethers.ZeroAddress, this.recipient.address, parseShare(1n))
.withArgs(ethers.ZeroAddress, this.recipient, parseShare(1n))
.to.emit(this.vault, 'Deposit')
.withArgs(this.holder.address, this.recipient.address, parseToken(1n), parseShare(1n));
.withArgs(this.holder, this.recipient, parseToken(1n), parseShare(1n));
});
it('withdraw', async function () {
@ -307,11 +305,11 @@ describe('ERC4626', function () {
await expect(tx).to.changeTokenBalance(this.vault, this.holder, 0n);
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.vault.target, this.recipient.address, 0n)
.withArgs(this.vault, this.recipient, 0n)
.to.emit(this.vault, 'Transfer')
.withArgs(this.holder.address, ethers.ZeroAddress, 0n)
.withArgs(this.holder, ethers.ZeroAddress, 0n)
.to.emit(this.vault, 'Withdraw')
.withArgs(this.holder.address, this.recipient.address, this.holder.address, 0n, 0n);
.withArgs(this.holder, this.recipient, this.holder, 0n, 0n);
});
it('redeem', async function () {
@ -324,11 +322,11 @@ describe('ERC4626', function () {
await expect(tx).to.changeTokenBalance(this.vault, this.holder, 0n);
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.vault.target, this.recipient.address, 0n)
.withArgs(this.vault, this.recipient, 0n)
.to.emit(this.vault, 'Transfer')
.withArgs(this.holder.address, ethers.ZeroAddress, 0n)
.withArgs(this.holder, ethers.ZeroAddress, 0n)
.to.emit(this.vault, 'Withdraw')
.withArgs(this.holder.address, this.recipient.address, this.holder.address, 0n, 0n);
.withArgs(this.holder, this.recipient, this.holder, 0n, 0n);
});
});
@ -374,11 +372,11 @@ describe('ERC4626', function () {
await expect(tx).to.changeTokenBalance(this.vault, this.recipient, expectedShares);
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.holder.address, this.vault.target, depositAssets)
.withArgs(this.holder, this.vault, depositAssets)
.to.emit(this.vault, 'Transfer')
.withArgs(ethers.ZeroAddress, this.recipient.address, expectedShares)
.withArgs(ethers.ZeroAddress, this.recipient, expectedShares)
.to.emit(this.vault, 'Deposit')
.withArgs(this.holder.address, this.recipient.address, depositAssets, expectedShares);
.withArgs(this.holder, this.recipient, depositAssets, expectedShares);
});
/**
@ -412,11 +410,11 @@ describe('ERC4626', function () {
await expect(tx).to.changeTokenBalance(this.vault, this.recipient, mintShares);
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.holder.address, this.vault.target, expectedAssets)
.withArgs(this.holder, this.vault, expectedAssets)
.to.emit(this.vault, 'Transfer')
.withArgs(ethers.ZeroAddress, this.recipient.address, mintShares)
.withArgs(ethers.ZeroAddress, this.recipient, mintShares)
.to.emit(this.vault, 'Deposit')
.withArgs(this.holder.address, this.recipient.address, expectedAssets, mintShares);
.withArgs(this.holder, this.recipient, expectedAssets, mintShares);
});
it('withdraw', async function () {
@ -429,11 +427,11 @@ describe('ERC4626', function () {
await expect(tx).to.changeTokenBalance(this.vault, this.holder, 0n);
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.vault.target, this.recipient.address, 0n)
.withArgs(this.vault, this.recipient, 0n)
.to.emit(this.vault, 'Transfer')
.withArgs(this.holder.address, ethers.ZeroAddress, 0n)
.withArgs(this.holder, ethers.ZeroAddress, 0n)
.to.emit(this.vault, 'Withdraw')
.withArgs(this.holder.address, this.recipient.address, this.holder.address, 0n, 0n);
.withArgs(this.holder, this.recipient, this.holder, 0n, 0n);
});
it('redeem', async function () {
@ -446,11 +444,11 @@ describe('ERC4626', function () {
await expect(tx).to.changeTokenBalance(this.vault, this.holder, 0n);
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.vault.target, this.recipient.address, 0n)
.withArgs(this.vault, this.recipient, 0n)
.to.emit(this.vault, 'Transfer')
.withArgs(this.holder.address, ethers.ZeroAddress, 0n)
.withArgs(this.holder, ethers.ZeroAddress, 0n)
.to.emit(this.vault, 'Withdraw')
.withArgs(this.holder.address, this.recipient.address, this.holder.address, 0n, 0n);
.withArgs(this.holder, this.recipient, this.holder, 0n, 0n);
});
});
@ -495,11 +493,11 @@ describe('ERC4626', function () {
await expect(tx).to.changeTokenBalance(this.vault, this.recipient, expectedShares);
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.holder.address, this.vault.target, depositAssets)
.withArgs(this.holder, this.vault, depositAssets)
.to.emit(this.vault, 'Transfer')
.withArgs(ethers.ZeroAddress, this.recipient.address, expectedShares)
.withArgs(ethers.ZeroAddress, this.recipient, expectedShares)
.to.emit(this.vault, 'Deposit')
.withArgs(this.holder.address, this.recipient.address, depositAssets, expectedShares);
.withArgs(this.holder, this.recipient, depositAssets, expectedShares);
});
/**
@ -531,11 +529,11 @@ describe('ERC4626', function () {
await expect(tx).to.changeTokenBalance(this.vault, this.recipient, mintShares);
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.holder.address, this.vault.target, expectedAssets)
.withArgs(this.holder, this.vault, expectedAssets)
.to.emit(this.vault, 'Transfer')
.withArgs(ethers.ZeroAddress, this.recipient.address, mintShares)
.withArgs(ethers.ZeroAddress, this.recipient, mintShares)
.to.emit(this.vault, 'Deposit')
.withArgs(this.holder.address, this.recipient.address, expectedAssets, mintShares);
.withArgs(this.holder, this.recipient, expectedAssets, mintShares);
});
it('withdraw', async function () {
@ -558,11 +556,11 @@ describe('ERC4626', function () {
await expect(tx).to.changeTokenBalance(this.vault, this.holder, -expectedShares);
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.vault.target, this.recipient.address, withdrawAssets)
.withArgs(this.vault, this.recipient, withdrawAssets)
.to.emit(this.vault, 'Transfer')
.withArgs(this.holder.address, ethers.ZeroAddress, expectedShares)
.withArgs(this.holder, ethers.ZeroAddress, expectedShares)
.to.emit(this.vault, 'Withdraw')
.withArgs(this.holder.address, this.recipient.address, this.holder.address, withdrawAssets, expectedShares);
.withArgs(this.holder, this.recipient, this.holder, withdrawAssets, expectedShares);
});
it('withdraw with approval', async function () {
@ -570,7 +568,7 @@ describe('ERC4626', function () {
await expect(this.vault.connect(this.other).withdraw(parseToken(1n), this.recipient, this.holder))
.to.be.revertedWithCustomError(this.vault, 'ERC20InsufficientAllowance')
.withArgs(this.other.address, 0n, assets);
.withArgs(this.other, 0n, assets);
await expect(this.vault.connect(this.spender).withdraw(parseToken(1n), this.recipient, this.holder)).to.not.be
.reverted;
@ -596,17 +594,17 @@ describe('ERC4626', function () {
await expect(tx).to.changeTokenBalance(this.vault, this.holder, -redeemShares);
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.vault.target, this.recipient.address, expectedAssets)
.withArgs(this.vault, this.recipient, expectedAssets)
.to.emit(this.vault, 'Transfer')
.withArgs(this.holder.address, ethers.ZeroAddress, redeemShares)
.withArgs(this.holder, ethers.ZeroAddress, redeemShares)
.to.emit(this.vault, 'Withdraw')
.withArgs(this.holder.address, this.recipient.address, this.holder.address, expectedAssets, redeemShares);
.withArgs(this.holder, this.recipient, this.holder, expectedAssets, redeemShares);
});
it('redeem with approval', async function () {
await expect(this.vault.connect(this.other).redeem(parseShare(100n), this.recipient, this.holder))
.to.be.revertedWithCustomError(this.vault, 'ERC20InsufficientAllowance')
.withArgs(this.other.address, 0n, parseShare(100n));
.withArgs(this.other, 0n, parseShare(100n));
await expect(this.vault.connect(this.spender).redeem(parseShare(100n), this.recipient, this.holder)).to.not.be
.reverted;
@ -660,16 +658,16 @@ describe('ERC4626', function () {
await expect(this.tx)
// get total
.to.emit(this.token, 'Transfer')
.withArgs(this.holder.address, this.vault.target, valueWithFees)
.withArgs(this.holder, this.vault, valueWithFees)
// redirect fees
.to.emit(this.token, 'Transfer')
.withArgs(this.vault.target, this.other.address, fees)
.withArgs(this.vault, this.other, fees)
// mint shares
.to.emit(this.vault, 'Transfer')
.withArgs(ethers.ZeroAddress, this.recipient.address, valueWithoutFees)
.withArgs(ethers.ZeroAddress, this.recipient, valueWithoutFees)
// deposit event
.to.emit(this.vault, 'Deposit')
.withArgs(this.holder.address, this.recipient.address, valueWithFees, valueWithoutFees);
.withArgs(this.holder, this.recipient, valueWithFees, valueWithoutFees);
});
});
@ -712,16 +710,16 @@ describe('ERC4626', function () {
await expect(this.tx)
// withdraw principal
.to.emit(this.token, 'Transfer')
.withArgs(this.vault.target, this.recipient.address, valueWithoutFees)
.withArgs(this.vault, this.recipient, valueWithoutFees)
// redirect fees
.to.emit(this.token, 'Transfer')
.withArgs(this.vault.target, this.other.address, fees)
.withArgs(this.vault, this.other, fees)
// mint shares
.to.emit(this.vault, 'Transfer')
.withArgs(this.holder.address, ethers.ZeroAddress, valueWithFees)
.withArgs(this.holder, ethers.ZeroAddress, valueWithFees)
// withdraw event
.to.emit(this.vault, 'Withdraw')
.withArgs(this.holder.address, this.recipient.address, this.holder.address, valueWithoutFees, valueWithFees);
.withArgs(this.holder, this.recipient, this.holder, valueWithoutFees, valueWithFees);
});
});
});
@ -742,9 +740,9 @@ describe('ERC4626', function () {
// 1. Alice mints 2000 shares (costs 2000 tokens)
await expect(vault.connect(alice).mint(2000n, alice))
.to.emit(token, 'Transfer')
.withArgs(alice.address, vault.target, 2000n)
.withArgs(alice, vault, 2000n)
.to.emit(vault, 'Transfer')
.withArgs(ethers.ZeroAddress, alice.address, 2000n);
.withArgs(ethers.ZeroAddress, alice, 2000n);
expect(await vault.previewDeposit(2000n)).to.equal(2000n);
expect(await vault.balanceOf(alice)).to.equal(2000n);
@ -758,9 +756,9 @@ describe('ERC4626', function () {
// 2. Bruce deposits 4000 tokens (mints 4000 shares)
await expect(vault.connect(bruce).mint(4000n, bruce))
.to.emit(token, 'Transfer')
.withArgs(bruce.address, vault.target, 4000n)
.withArgs(bruce, vault, 4000n)
.to.emit(vault, 'Transfer')
.withArgs(ethers.ZeroAddress, bruce.address, 4000n);
.withArgs(ethers.ZeroAddress, bruce, 4000n);
expect(await vault.previewDeposit(4000n)).to.equal(4000n);
expect(await vault.balanceOf(alice)).to.equal(2000n);
@ -785,9 +783,9 @@ describe('ERC4626', function () {
// 4. Alice deposits 2000 tokens (mints 1333 shares)
await expect(vault.connect(alice).deposit(2000n, alice))
.to.emit(token, 'Transfer')
.withArgs(alice.address, vault.target, 2000n)
.withArgs(alice, vault, 2000n)
.to.emit(vault, 'Transfer')
.withArgs(ethers.ZeroAddress, alice.address, 1333n);
.withArgs(ethers.ZeroAddress, alice, 1333n);
expect(await vault.balanceOf(alice)).to.equal(3333n);
expect(await vault.balanceOf(bruce)).to.equal(4000n);
@ -802,9 +800,9 @@ describe('ERC4626', function () {
// NOTE: Alices's vault assets got rounded towards infinity
await expect(vault.connect(bruce).mint(2000n, bruce))
.to.emit(token, 'Transfer')
.withArgs(bruce.address, vault.target, 3000n)
.withArgs(bruce, vault, 3000n)
.to.emit(vault, 'Transfer')
.withArgs(ethers.ZeroAddress, bruce.address, 2000n);
.withArgs(ethers.ZeroAddress, bruce, 2000n);
expect(await vault.balanceOf(alice)).to.equal(3333n);
expect(await vault.balanceOf(bruce)).to.equal(6000n);
@ -829,9 +827,9 @@ describe('ERC4626', function () {
// 7. Alice redeem 1333 shares (2428 assets)
await expect(vault.connect(alice).redeem(1333n, alice, alice))
.to.emit(vault, 'Transfer')
.withArgs(alice.address, ethers.ZeroAddress, 1333n)
.withArgs(alice, ethers.ZeroAddress, 1333n)
.to.emit(token, 'Transfer')
.withArgs(vault.target, alice.address, 2427n); // used to be 2428
.withArgs(vault, alice, 2427n); // used to be 2428
expect(await vault.balanceOf(alice)).to.equal(2000n);
expect(await vault.balanceOf(bruce)).to.equal(6000n);
@ -844,9 +842,9 @@ describe('ERC4626', function () {
// 8. Bruce withdraws 2929 assets (1608 shares)
await expect(vault.connect(bruce).withdraw(2929n, bruce, bruce))
.to.emit(vault, 'Transfer')
.withArgs(bruce.address, ethers.ZeroAddress, 1608n)
.withArgs(bruce, ethers.ZeroAddress, 1608n)
.to.emit(token, 'Transfer')
.withArgs(vault.target, bruce.address, 2929n);
.withArgs(vault, bruce, 2929n);
expect(await vault.balanceOf(alice)).to.equal(2000n);
expect(await vault.balanceOf(bruce)).to.equal(4392n);
@ -860,9 +858,9 @@ describe('ERC4626', function () {
// NOTE: Bruce's assets have been rounded back towards infinity
await expect(vault.connect(alice).withdraw(3643n, alice, alice))
.to.emit(vault, 'Transfer')
.withArgs(alice.address, ethers.ZeroAddress, 2000n)
.withArgs(alice, ethers.ZeroAddress, 2000n)
.to.emit(token, 'Transfer')
.withArgs(vault.target, alice.address, 3643n);
.withArgs(vault, alice, 3643n);
expect(await vault.balanceOf(alice)).to.equal(0n);
expect(await vault.balanceOf(bruce)).to.equal(4392n);
@ -875,9 +873,9 @@ describe('ERC4626', function () {
// 10. Bruce redeem 4392 shares (8001 tokens)
await expect(vault.connect(bruce).redeem(4392n, bruce, bruce))
.to.emit(vault, 'Transfer')
.withArgs(bruce.address, ethers.ZeroAddress, 4392n)
.withArgs(bruce, ethers.ZeroAddress, 4392n)
.to.emit(token, 'Transfer')
.withArgs(vault.target, bruce.address, 8000n); // used to be 8001
.withArgs(vault, bruce, 8000n); // used to be 8001
expect(await vault.balanceOf(alice)).to.equal(0n);
expect(await vault.balanceOf(bruce)).to.equal(0n);

@ -40,13 +40,13 @@ describe('SafeERC20', function () {
it('reverts on transfer', async function () {
await expect(this.mock.$safeTransfer(this.token, this.receiver, 0n))
.to.be.revertedWithCustomError(this.mock, 'AddressEmptyCode')
.withArgs(this.token.address);
.withArgs(this.token);
});
it('reverts on transferFrom', async function () {
await expect(this.mock.$safeTransferFrom(this.token, this.mock, this.receiver, 0n))
.to.be.revertedWithCustomError(this.mock, 'AddressEmptyCode')
.withArgs(this.token.address);
.withArgs(this.token);
});
it('reverts on increaseAllowance', async function () {
@ -62,7 +62,7 @@ describe('SafeERC20', function () {
it('reverts on forceApprove', async function () {
await expect(this.mock.$forceApprove(this.token, this.spender, 0n))
.to.be.revertedWithCustomError(this.mock, 'AddressEmptyCode')
.withArgs(this.token.address);
.withArgs(this.token);
});
});
@ -74,31 +74,31 @@ describe('SafeERC20', function () {
it('reverts on transfer', async function () {
await expect(this.mock.$safeTransfer(this.token, this.receiver, 0n))
.to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation')
.withArgs(this.token.target);
.withArgs(this.token);
});
it('reverts on transferFrom', async function () {
await expect(this.mock.$safeTransferFrom(this.token, this.mock, this.receiver, 0n))
.to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation')
.withArgs(this.token.target);
.withArgs(this.token);
});
it('reverts on increaseAllowance', async function () {
await expect(this.mock.$safeIncreaseAllowance(this.token, this.spender, 0n))
.to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation')
.withArgs(this.token.target);
.withArgs(this.token);
});
it('reverts on decreaseAllowance', async function () {
await expect(this.mock.$safeDecreaseAllowance(this.token, this.spender, 0n))
.to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation')
.withArgs(this.token.target);
.withArgs(this.token);
});
it('reverts on forceApprove', async function () {
await expect(this.mock.$forceApprove(this.token, this.spender, 0n))
.to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedOperation')
.withArgs(this.token.target);
.withArgs(this.token);
});
});
@ -157,13 +157,13 @@ function shouldOnlyRevertOnErrors() {
it("doesn't revert on transfer", async function () {
await expect(this.mock.$safeTransfer(this.token, this.receiver, 10n))
.to.emit(this.token, 'Transfer')
.withArgs(this.mock.target, this.receiver.address, 10n);
.withArgs(this.mock, this.receiver, 10n);
});
it("doesn't revert on transferFrom", async function () {
await expect(this.mock.$safeTransferFrom(this.token, this.owner, this.receiver, 10n))
.to.emit(this.token, 'Transfer')
.withArgs(this.owner.address, this.receiver.address, 10n);
.withArgs(this.owner, this.receiver, 10n);
});
});
@ -191,7 +191,7 @@ function shouldOnlyRevertOnErrors() {
it('reverts when decreasing the allowance', async function () {
await expect(this.mock.$safeDecreaseAllowance(this.token, this.spender, 10n))
.to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedDecreaseAllowance')
.withArgs(this.spender.address, 0n, 10n);
.withArgs(this.spender, 0n, 10n);
});
});
@ -223,7 +223,7 @@ function shouldOnlyRevertOnErrors() {
it('reverts when decreasing the allowance to a negative value', async function () {
await expect(this.mock.$safeDecreaseAllowance(this.token, this.spender, 200n))
.to.be.revertedWithCustomError(this.mock, 'SafeERC20FailedDecreaseAllowance')
.withArgs(this.spender.address, 100n, 200n);
.withArgs(this.spender, 100n, 200n);
});
});
});

@ -4,9 +4,7 @@ const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic');
const { anyValue } = require('@nomicfoundation/hardhat-chai-matchers/withArgs');
const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior');
const {
bigint: { RevertType },
} = require('../../helpers/enums');
const { RevertType } = require('../../helpers/enums');
const firstTokenId = 5042n;
const secondTokenId = 79217n;
@ -58,7 +56,7 @@ function shouldBehaveLikeERC721() {
const tokenId = firstTokenId;
it('returns the owner of the given token ID', async function () {
expect(await this.token.ownerOf(tokenId)).to.equal(this.owner.address);
expect(await this.token.ownerOf(tokenId)).to.equal(this.owner);
});
});
@ -85,13 +83,11 @@ function shouldBehaveLikeERC721() {
const transferWasSuccessful = () => {
it('transfers the ownership of the given token ID to the given address', async function () {
await this.tx();
expect(await this.token.ownerOf(tokenId)).to.equal(this.to.address ?? this.to.target);
expect(await this.token.ownerOf(tokenId)).to.equal(this.to);
});
it('emits a Transfer event', async function () {
await expect(this.tx())
.to.emit(this.token, 'Transfer')
.withArgs(this.owner.address, this.to.address ?? this.to.target, tokenId);
await expect(this.tx()).to.emit(this.token, 'Transfer').withArgs(this.owner, this.to, tokenId);
});
it('clears the approval for the token ID with no event', async function () {
@ -157,7 +153,7 @@ function shouldBehaveLikeERC721() {
it('keeps ownership of the token', async function () {
await this.tx();
expect(await this.token.ownerOf(tokenId)).to.equal(this.owner.address);
expect(await this.token.ownerOf(tokenId)).to.equal(this.owner);
});
it('clears the approval for the token ID', async function () {
@ -166,9 +162,7 @@ function shouldBehaveLikeERC721() {
});
it('emits only a transfer event', async function () {
await expect(this.tx())
.to.emit(this.token, 'Transfer')
.withArgs(this.owner.address, this.owner.address, tokenId);
await expect(this.tx()).to.emit(this.token, 'Transfer').withArgs(this.owner, this.owner, tokenId);
});
it('keeps the owner balance', async function () {
@ -192,7 +186,7 @@ function shouldBehaveLikeERC721() {
this.token.connect(this.owner)[fragment](this.other, this.other, tokenId, ...(opts.extra ?? [])),
)
.to.be.revertedWithCustomError(this.token, 'ERC721IncorrectOwner')
.withArgs(this.other.address, tokenId, this.owner.address);
.withArgs(this.other, tokenId, this.owner);
});
});
@ -207,7 +201,7 @@ function shouldBehaveLikeERC721() {
this.token.connect(this.other)[fragment](this.owner, this.other, tokenId, ...(opts.extra ?? [])),
)
.to.be.revertedWithCustomError(this.token, 'ERC721InsufficientApproval')
.withArgs(this.other.address, tokenId);
.withArgs(this.other, tokenId);
});
}
});
@ -255,7 +249,7 @@ function shouldBehaveLikeERC721() {
it('calls onERC721Received', async function () {
await expect(this.token.connect(this.owner)[fragment](this.owner, this.to, tokenId, ...(opts.extra ?? [])))
.to.emit(this.to, 'Received')
.withArgs(this.owner.address, this.owner.address, tokenId, data, anyValue);
.withArgs(this.owner, this.owner, tokenId, data, anyValue);
});
it('calls onERC721Received from approved', async function () {
@ -263,7 +257,7 @@ function shouldBehaveLikeERC721() {
this.token.connect(this.approved)[fragment](this.owner, this.to, tokenId, ...(opts.extra ?? [])),
)
.to.emit(this.to, 'Received')
.withArgs(this.approved.address, this.owner.address, tokenId, data, anyValue);
.withArgs(this.approved, this.owner, tokenId, data, anyValue);
});
describe('with an invalid token id', function () {
@ -311,7 +305,7 @@ function shouldBehaveLikeERC721() {
await expect(this.token.connect(this.owner)[fnName](this.owner, invalidReceiver, tokenId))
.to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver')
.withArgs(invalidReceiver.target);
.withArgs(invalidReceiver);
});
});
@ -337,7 +331,7 @@ function shouldBehaveLikeERC721() {
await expect(this.token.connect(this.owner)[fnName](this.owner, revertingReceiver, tokenId))
.to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver')
.withArgs(revertingReceiver.target);
.withArgs(revertingReceiver);
});
});
@ -373,7 +367,7 @@ function shouldBehaveLikeERC721() {
await expect(this.token.connect(this.owner)[fnName](this.owner, nonReceiver, tokenId))
.to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver')
.withArgs(nonReceiver.target);
.withArgs(nonReceiver);
});
});
});
@ -408,7 +402,7 @@ function shouldBehaveLikeERC721() {
await expect(this.token.$_safeMint(invalidReceiver, tokenId))
.to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver')
.withArgs(invalidReceiver.target);
.withArgs(invalidReceiver);
});
});
@ -434,7 +428,7 @@ function shouldBehaveLikeERC721() {
await expect(this.token.$_safeMint(revertingReceiver, tokenId))
.to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver')
.withArgs(revertingReceiver.target);
.withArgs(revertingReceiver);
});
});
@ -470,7 +464,7 @@ function shouldBehaveLikeERC721() {
await expect(this.token.$_safeMint(nonReceiver, tokenId))
.to.be.revertedWithCustomError(this.token, 'ERC721InvalidReceiver')
.withArgs(nonReceiver.target);
.withArgs(nonReceiver);
});
});
});
@ -487,7 +481,7 @@ function shouldBehaveLikeERC721() {
const itApproves = function () {
it('sets the approval for the target address', async function () {
expect(await this.token.getApproved(tokenId)).to.equal(this.approved.address ?? this.approved);
expect(await this.token.getApproved(tokenId)).to.equal(this.approved ?? this.approved);
});
};
@ -495,7 +489,7 @@ function shouldBehaveLikeERC721() {
it('emits an approval event', async function () {
await expect(this.tx)
.to.emit(this.token, 'Approval')
.withArgs(this.owner.address, this.approved.address ?? this.approved, tokenId);
.withArgs(this.owner, this.approved ?? this.approved, tokenId);
});
};
@ -557,7 +551,7 @@ function shouldBehaveLikeERC721() {
it('reverts', async function () {
await expect(this.token.connect(this.other).approve(this.approved, tokenId))
.to.be.revertedWithCustomError(this.token, 'ERC721InvalidApprover')
.withArgs(this.other.address);
.withArgs(this.other);
});
});
@ -567,7 +561,7 @@ function shouldBehaveLikeERC721() {
await expect(this.token.connect(this.approved).approve(this.other, tokenId))
.to.be.revertedWithCustomError(this.token, 'ERC721InvalidApprover')
.withArgs(this.approved.address);
.withArgs(this.approved);
});
});
@ -603,7 +597,7 @@ function shouldBehaveLikeERC721() {
it('emits an approval event', async function () {
await expect(this.token.connect(this.owner).setApprovalForAll(this.operator, true))
.to.emit(this.token, 'ApprovalForAll')
.withArgs(this.owner.address, this.operator.address, true);
.withArgs(this.owner, this.operator, true);
});
});
@ -621,7 +615,7 @@ function shouldBehaveLikeERC721() {
it('emits an approval event', async function () {
await expect(this.token.connect(this.owner).setApprovalForAll(this.operator, true))
.to.emit(this.token, 'ApprovalForAll')
.withArgs(this.owner.address, this.operator.address, true);
.withArgs(this.owner, this.operator, true);
});
it('can unset the operator approval', async function () {
@ -645,7 +639,7 @@ function shouldBehaveLikeERC721() {
it('emits an approval event', async function () {
await expect(this.token.connect(this.owner).setApprovalForAll(this.operator, true))
.to.emit(this.token, 'ApprovalForAll')
.withArgs(this.owner.address, this.operator.address, true);
.withArgs(this.owner, this.operator, true);
});
});
});
@ -679,7 +673,7 @@ function shouldBehaveLikeERC721() {
});
it('returns approved account', async function () {
expect(await this.token.getApproved(firstTokenId)).to.equal(this.approved.address);
expect(await this.token.getApproved(firstTokenId)).to.equal(this.approved);
});
});
});
@ -699,14 +693,12 @@ function shouldBehaveLikeERC721() {
});
it('emits a Transfer event', async function () {
await expect(this.tx)
.to.emit(this.token, 'Transfer')
.withArgs(ethers.ZeroAddress, this.owner.address, firstTokenId);
await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(ethers.ZeroAddress, this.owner, firstTokenId);
});
it('creates the token', async function () {
expect(await this.token.balanceOf(this.owner)).to.equal(1n);
expect(await this.token.ownerOf(firstTokenId)).to.equal(this.owner.address);
expect(await this.token.ownerOf(firstTokenId)).to.equal(this.owner);
});
it('reverts when adding a token id that already exists', async function () {
@ -736,9 +728,7 @@ function shouldBehaveLikeERC721() {
});
it('emits a Transfer event', async function () {
await expect(this.tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.owner.address, ethers.ZeroAddress, firstTokenId);
await expect(this.tx).to.emit(this.token, 'Transfer').withArgs(this.owner, ethers.ZeroAddress, firstTokenId);
});
it('deletes the token', async function () {
@ -790,7 +780,7 @@ function shouldBehaveLikeERC721Enumerable() {
it('reverts', async function () {
await expect(this.token.tokenOfOwnerByIndex(this.owner, 2n))
.to.be.revertedWithCustomError(this.token, 'ERC721OutOfBoundsIndex')
.withArgs(this.owner.address, 2n);
.withArgs(this.owner, 2n);
});
});
@ -798,7 +788,7 @@ function shouldBehaveLikeERC721Enumerable() {
it('reverts', async function () {
await expect(this.token.tokenOfOwnerByIndex(this.other, 0n))
.to.be.revertedWithCustomError(this.token, 'ERC721OutOfBoundsIndex')
.withArgs(this.other.address, 0n);
.withArgs(this.other, 0n);
});
});
@ -821,7 +811,7 @@ function shouldBehaveLikeERC721Enumerable() {
expect(await this.token.balanceOf(this.owner)).to.equal(0n);
await expect(this.token.tokenOfOwnerByIndex(this.owner, 0n))
.to.be.revertedWithCustomError(this.token, 'ERC721OutOfBoundsIndex')
.withArgs(this.owner.address, 0n);
.withArgs(this.owner, 0n);
});
});
});

@ -32,7 +32,7 @@ describe('ERC721Burnable', function () {
await expect(this.token.connect(this.owner).burn(tokenId))
.to.emit(this.token, 'Transfer')
.withArgs(this.owner.address, ethers.ZeroAddress, tokenId);
.withArgs(this.owner, ethers.ZeroAddress, tokenId);
await expect(this.token.ownerOf(tokenId))
.to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken')
@ -61,7 +61,7 @@ describe('ERC721Burnable', function () {
it('reverts', async function () {
await expect(this.token.connect(this.another).burn(tokenId))
.to.be.revertedWithCustomError(this.token, 'ERC721InsufficientApproval')
.withArgs(this.another.address, tokenId);
.withArgs(this.another, tokenId);
});
});

@ -51,7 +51,7 @@ describe('ERC721Consecutive', function () {
first /* fromTokenId */,
first + batch.amount - 1n /* toTokenId */,
ethers.ZeroAddress /* fromAddress */,
batch.receiver.address /* toAddress */,
batch.receiver /* toAddress */,
);
} else {
// ".to.not.emit" only looks at event name, and doesn't check the parameters
@ -125,7 +125,7 @@ describe('ERC721Consecutive', function () {
await expect(this.token.$_mint(this.alice, tokenId))
.to.emit(this.token, 'Transfer')
.withArgs(ethers.ZeroAddress, this.alice.address, tokenId);
.withArgs(ethers.ZeroAddress, this.alice, tokenId);
});
it('cannot mint a token that has been batched minted', async function () {
@ -145,13 +145,13 @@ describe('ERC721Consecutive', function () {
it('core takes over ownership on transfer', async function () {
await this.token.connect(this.alice).transferFrom(this.alice, this.receiver, tokenId);
expect(await this.token.ownerOf(tokenId)).to.equal(this.receiver.address);
expect(await this.token.ownerOf(tokenId)).to.equal(this.receiver);
});
it('tokens can be burned and re-minted #1', async function () {
await expect(this.token.connect(this.alice).$_burn(tokenId))
.to.emit(this.token, 'Transfer')
.withArgs(this.alice.address, ethers.ZeroAddress, tokenId);
.withArgs(this.alice, ethers.ZeroAddress, tokenId);
await expect(this.token.ownerOf(tokenId))
.to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken')
@ -159,9 +159,9 @@ describe('ERC721Consecutive', function () {
await expect(this.token.$_mint(this.bruce, tokenId))
.to.emit(this.token, 'Transfer')
.withArgs(ethers.ZeroAddress, this.bruce.address, tokenId);
.withArgs(ethers.ZeroAddress, this.bruce, tokenId);
expect(await this.token.ownerOf(tokenId)).to.equal(this.bruce.address);
expect(await this.token.ownerOf(tokenId)).to.equal(this.bruce);
});
it('tokens can be burned and re-minted #2', async function () {
@ -174,14 +174,14 @@ describe('ERC721Consecutive', function () {
// mint
await expect(this.token.$_mint(this.alice, tokenId))
.to.emit(this.token, 'Transfer')
.withArgs(ethers.ZeroAddress, this.alice.address, tokenId);
.withArgs(ethers.ZeroAddress, this.alice, tokenId);
expect(await this.token.ownerOf(tokenId)).to.equal(this.alice.address);
expect(await this.token.ownerOf(tokenId)).to.equal(this.alice);
// burn
await expect(await this.token.$_burn(tokenId))
.to.emit(this.token, 'Transfer')
.withArgs(this.alice.address, ethers.ZeroAddress, tokenId);
.withArgs(this.alice, ethers.ZeroAddress, tokenId);
await expect(this.token.ownerOf(tokenId))
.to.be.revertedWithCustomError(this.token, 'ERC721NonexistentToken')
@ -190,9 +190,9 @@ describe('ERC721Consecutive', function () {
// re-mint
await expect(this.token.$_mint(this.bruce, tokenId))
.to.emit(this.token, 'Transfer')
.withArgs(ethers.ZeroAddress, this.bruce.address, tokenId);
.withArgs(ethers.ZeroAddress, this.bruce, tokenId);
expect(await this.token.ownerOf(tokenId)).to.equal(this.bruce.address);
expect(await this.token.ownerOf(tokenId)).to.equal(this.bruce);
});
});
});

@ -68,7 +68,7 @@ describe('ERC721Pausable', function () {
describe('ownerOf', function () {
it('returns the amount of tokens owned by the given address', async function () {
expect(await this.token.ownerOf(tokenId)).to.equal(this.owner.address);
expect(await this.token.ownerOf(tokenId)).to.equal(this.owner);
});
});

@ -18,7 +18,7 @@ async function fixture() {
return { owner, token };
}
contract('ERC721URIStorage', function () {
describe('ERC721URIStorage', function () {
beforeEach(async function () {
Object.assign(this, await loadFixture(fixture));
});

@ -2,7 +2,7 @@ const { ethers } = require('hardhat');
const { expect } = require('chai');
const { loadFixture, mine } = require('@nomicfoundation/hardhat-network-helpers');
const { bigint: time } = require('../../../helpers/time');
const time = require('../../../helpers/time');
const { shouldBehaveLikeVotes } = require('../../../governance/utils/Votes.behavior');
@ -58,7 +58,7 @@ describe('ERC721Votes', function () {
it('no delegation', async function () {
await expect(this.votes.connect(this.holder).transferFrom(this.holder, this.recipient, tokens[0]))
.to.emit(this.token, 'Transfer')
.withArgs(this.holder.address, this.recipient.address, tokens[0])
.withArgs(this.holder, this.recipient, tokens[0])
.to.not.emit(this.token, 'DelegateVotesChanged');
this.holderVotes = 0n;
@ -71,9 +71,9 @@ describe('ERC721Votes', function () {
const tx = await this.votes.connect(this.holder).transferFrom(this.holder, this.recipient, tokens[0]);
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.holder.address, this.recipient.address, tokens[0])
.withArgs(this.holder, this.recipient, tokens[0])
.to.emit(this.token, 'DelegateVotesChanged')
.withArgs(this.holder.address, 1n, 0n);
.withArgs(this.holder, 1n, 0n);
const { logs } = await tx.wait();
const { index } = logs.find(event => event.fragment.name == 'DelegateVotesChanged');
@ -91,9 +91,9 @@ describe('ERC721Votes', function () {
const tx = await this.votes.connect(this.holder).transferFrom(this.holder, this.recipient, tokens[0]);
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.holder.address, this.recipient.address, tokens[0])
.withArgs(this.holder, this.recipient, tokens[0])
.to.emit(this.token, 'DelegateVotesChanged')
.withArgs(this.recipient.address, 0n, 1n);
.withArgs(this.recipient, 0n, 1n);
const { logs } = await tx.wait();
const { index } = logs.find(event => event.fragment.name == 'DelegateVotesChanged');
@ -112,11 +112,11 @@ describe('ERC721Votes', function () {
const tx = await this.votes.connect(this.holder).transferFrom(this.holder, this.recipient, tokens[0]);
await expect(tx)
.to.emit(this.token, 'Transfer')
.withArgs(this.holder.address, this.recipient.address, tokens[0])
.withArgs(this.holder, this.recipient, tokens[0])
.to.emit(this.token, 'DelegateVotesChanged')
.withArgs(this.holder.address, 1n, 0n)
.withArgs(this.holder, 1n, 0n)
.to.emit(this.token, 'DelegateVotesChanged')
.withArgs(this.recipient.address, 0n, 1n);
.withArgs(this.recipient, 0n, 1n);
const { logs } = await tx.wait();
const { index } = logs.find(event => event.fragment.name == 'DelegateVotesChanged');

@ -35,7 +35,7 @@ describe('ERC721Wrapper', function () {
});
it('has underlying', async function () {
expect(await this.token.underlying()).to.equal(this.underlying.target);
expect(await this.token.underlying()).to.equal(this.underlying);
});
describe('depositFor', function () {
@ -44,9 +44,9 @@ describe('ERC721Wrapper', function () {
await expect(this.token.connect(this.owner).depositFor(this.owner, [tokenId]))
.to.emit(this.underlying, 'Transfer')
.withArgs(this.owner.address, this.token.target, tokenId)
.withArgs(this.owner, this.token, tokenId)
.to.emit(this.token, 'Transfer')
.withArgs(ethers.ZeroAddress, this.owner.address, tokenId);
.withArgs(ethers.ZeroAddress, this.owner, tokenId);
});
it('works with approval for all', async function () {
@ -54,9 +54,9 @@ describe('ERC721Wrapper', function () {
await expect(this.token.connect(this.owner).depositFor(this.owner, [tokenId]))
.to.emit(this.underlying, 'Transfer')
.withArgs(this.owner.address, this.token.target, tokenId)
.withArgs(this.owner, this.token, tokenId)
.to.emit(this.token, 'Transfer')
.withArgs(ethers.ZeroAddress, this.owner.address, tokenId);
.withArgs(ethers.ZeroAddress, this.owner, tokenId);
});
it('works sending to another account', async function () {
@ -64,9 +64,9 @@ describe('ERC721Wrapper', function () {
await expect(this.token.connect(this.owner).depositFor(this.other, [tokenId]))
.to.emit(this.underlying, 'Transfer')
.withArgs(this.owner.address, this.token.target, tokenId)
.withArgs(this.owner, this.token, tokenId)
.to.emit(this.token, 'Transfer')
.withArgs(ethers.ZeroAddress, this.other.address, tokenId);
.withArgs(ethers.ZeroAddress, this.other, tokenId);
});
it('works with multiple tokens', async function () {
@ -75,19 +75,19 @@ describe('ERC721Wrapper', function () {
await expect(this.token.connect(this.owner).depositFor(this.owner, [tokenId, otherTokenId]))
.to.emit(this.underlying, 'Transfer')
.withArgs(this.owner.address, this.token.target, tokenId)
.withArgs(this.owner, this.token, tokenId)
.to.emit(this.token, 'Transfer')
.withArgs(ethers.ZeroAddress, this.owner.address, tokenId)
.withArgs(ethers.ZeroAddress, this.owner, tokenId)
.to.emit(this.underlying, 'Transfer')
.withArgs(this.owner.address, this.token.target, otherTokenId)
.withArgs(this.owner, this.token, otherTokenId)
.to.emit(this.token, 'Transfer')
.withArgs(ethers.ZeroAddress, this.owner.address, otherTokenId);
.withArgs(ethers.ZeroAddress, this.owner, otherTokenId);
});
it('reverts with missing approval', async function () {
await expect(this.token.connect(this.owner).depositFor(this.owner, [tokenId]))
.to.be.revertedWithCustomError(this.token, 'ERC721InsufficientApproval')
.withArgs(this.token.target, tokenId);
.withArgs(this.token, tokenId);
});
});
@ -100,9 +100,9 @@ describe('ERC721Wrapper', function () {
it('works for an owner', async function () {
await expect(this.token.connect(this.owner).withdrawTo(this.owner, [tokenId]))
.to.emit(this.underlying, 'Transfer')
.withArgs(this.token.target, this.owner.address, tokenId)
.withArgs(this.token, this.owner, tokenId)
.to.emit(this.token, 'Transfer')
.withArgs(this.owner.address, ethers.ZeroAddress, tokenId);
.withArgs(this.owner, ethers.ZeroAddress, tokenId);
});
it('works for an approved', async function () {
@ -110,9 +110,9 @@ describe('ERC721Wrapper', function () {
await expect(this.token.connect(this.approved).withdrawTo(this.owner, [tokenId]))
.to.emit(this.underlying, 'Transfer')
.withArgs(this.token.target, this.owner.address, tokenId)
.withArgs(this.token, this.owner, tokenId)
.to.emit(this.token, 'Transfer')
.withArgs(this.owner.address, ethers.ZeroAddress, tokenId);
.withArgs(this.owner, ethers.ZeroAddress, tokenId);
});
it('works for an approved for all', async function () {
@ -120,15 +120,15 @@ describe('ERC721Wrapper', function () {
await expect(this.token.connect(this.approved).withdrawTo(this.owner, [tokenId]))
.to.emit(this.underlying, 'Transfer')
.withArgs(this.token.target, this.owner.address, tokenId)
.withArgs(this.token, this.owner, tokenId)
.to.emit(this.token, 'Transfer')
.withArgs(this.owner.address, ethers.ZeroAddress, tokenId);
.withArgs(this.owner, ethers.ZeroAddress, tokenId);
});
it("doesn't work for a non-owner nor approved", async function () {
await expect(this.token.connect(this.other).withdrawTo(this.owner, [tokenId]))
.to.be.revertedWithCustomError(this.token, 'ERC721InsufficientApproval')
.withArgs(this.other.address, tokenId);
.withArgs(this.other, tokenId);
});
it('works with multiple tokens', async function () {
@ -137,21 +137,21 @@ describe('ERC721Wrapper', function () {
await expect(this.token.connect(this.owner).withdrawTo(this.owner, [tokenId, otherTokenId]))
.to.emit(this.underlying, 'Transfer')
.withArgs(this.token.target, this.owner.address, tokenId)
.withArgs(this.token, this.owner, tokenId)
.to.emit(this.underlying, 'Transfer')
.withArgs(this.token.target, this.owner.address, tokenId)
.withArgs(this.token, this.owner, tokenId)
.to.emit(this.token, 'Transfer')
.withArgs(this.owner.address, ethers.ZeroAddress, tokenId)
.withArgs(this.owner, ethers.ZeroAddress, tokenId)
.to.emit(this.token, 'Transfer')
.withArgs(this.owner.address, ethers.ZeroAddress, tokenId);
.withArgs(this.owner, ethers.ZeroAddress, tokenId);
});
it('works to another account', async function () {
await expect(this.token.connect(this.owner).withdrawTo(this.other, [tokenId]))
.to.emit(this.underlying, 'Transfer')
.withArgs(this.token.target, this.other.address, tokenId)
.withArgs(this.token, this.other, tokenId)
.to.emit(this.token, 'Transfer')
.withArgs(this.owner.address, ethers.ZeroAddress, tokenId);
.withArgs(this.owner, ethers.ZeroAddress, tokenId);
});
});
@ -166,13 +166,13 @@ describe('ERC721Wrapper', function () {
),
)
.to.be.revertedWithCustomError(this.token, 'ERC721UnsupportedToken')
.withArgs(this.other.address);
.withArgs(this.other);
});
it('mints a token to from', async function () {
await expect(this.underlying.connect(this.owner).safeTransferFrom(this.owner, this.token, tokenId))
.to.emit(this.token, 'Transfer')
.withArgs(ethers.ZeroAddress, this.owner.address, tokenId);
.withArgs(ethers.ZeroAddress, this.owner, tokenId);
});
});
@ -183,7 +183,7 @@ describe('ERC721Wrapper', function () {
await expect(this.token.$_recover(this.other, tokenId))
.to.emit(this.token, 'Transfer')
.withArgs(ethers.ZeroAddress, this.other.address, tokenId);
.withArgs(ethers.ZeroAddress, this.other, tokenId);
});
it('reverts if there is nothing to recover', async function () {
@ -191,7 +191,7 @@ describe('ERC721Wrapper', function () {
await expect(this.token.$_recover(holder, tokenId))
.to.be.revertedWithCustomError(this.token, 'ERC721IncorrectOwner')
.withArgs(this.token.target, tokenId, holder);
.withArgs(this.token, tokenId, holder);
});
});

@ -15,6 +15,6 @@ describe('ERC721Holder', function () {
const receiver = await ethers.deployContract('$ERC721Holder');
await token.connect(owner).safeTransferFrom(owner, receiver, tokenId);
expect(await token.ownerOf(tokenId)).to.equal(receiver.target);
expect(await token.ownerOf(tokenId)).to.equal(receiver);
});
});

@ -29,7 +29,7 @@ describe('Address', function () {
it('reverts when sending non-zero amounts', async function () {
await expect(this.mock.$sendValue(this.other, 1))
.to.be.revertedWithCustomError(this.mock, 'AddressInsufficientBalance')
.withArgs(this.mock.target);
.withArgs(this.mock);
});
});
@ -42,7 +42,7 @@ describe('Address', function () {
describe('with EOA recipient', function () {
it('sends 0 wei', async function () {
await expect(this.mock.$sendValue(this.recipient, 0)).to.changeEtherBalance(this.recipient.address, 0);
await expect(this.mock.$sendValue(this.recipient, 0)).to.changeEtherBalance(this.recipient, 0);
});
it('sends non-zero amounts', async function () {
@ -60,7 +60,7 @@ describe('Address', function () {
it('reverts when sending more than the balance', async function () {
await expect(this.mock.$sendValue(this.recipient, funds + 1n))
.to.be.revertedWithCustomError(this.mock, 'AddressInsufficientBalance')
.withArgs(this.mock.target);
.withArgs(this.mock);
});
});
@ -145,7 +145,7 @@ describe('Address', function () {
await expect(this.mock.$functionCall(this.recipient, call))
.to.be.revertedWithCustomError(this.mock, 'AddressEmptyCode')
.withArgs(this.recipient.address);
.withArgs(this.recipient);
});
});
});
@ -170,7 +170,7 @@ describe('Address', function () {
await expect(this.mock.$functionCallWithValue(this.target, call, value))
.to.be.revertedWithCustomError(this.mock, 'AddressInsufficientBalance')
.withArgs(this.mock.target);
.withArgs(this.mock);
});
it('calls the requested function with existing value', async function () {
@ -240,7 +240,7 @@ describe('Address', function () {
await expect(this.mock.$functionStaticCall(this.recipient, call))
.to.be.revertedWithCustomError(this.mock, 'AddressEmptyCode')
.withArgs(this.recipient.address);
.withArgs(this.recipient);
});
});
@ -273,7 +273,7 @@ describe('Address', function () {
await expect(this.mock.$functionDelegateCall(this.recipient, call))
.to.be.revertedWithCustomError(this.mock, 'AddressEmptyCode')
.withArgs(this.recipient.address);
.withArgs(this.recipient);
});
});

@ -12,15 +12,13 @@ function shouldBehaveLikeRegularContext() {
describe('msgSender', function () {
it('returns the transaction sender when called from an EOA', async function () {
await expect(this.context.connect(this.sender).msgSender())
.to.emit(this.context, 'Sender')
.withArgs(this.sender.address);
await expect(this.context.connect(this.sender).msgSender()).to.emit(this.context, 'Sender').withArgs(this.sender);
});
it('returns the transaction sender when called from another contract', async function () {
await expect(this.contextHelper.connect(this.sender).callSender(this.context))
.to.emit(this.context, 'Sender')
.withArgs(this.contextHelper.target);
.withArgs(this.contextHelper);
});
});

@ -68,7 +68,7 @@ describe('Create2', function () {
.to.emit(this.factory, 'return$deploy')
.withArgs(offChainComputed);
expect(this.constructorLessBytecode).to.include((await web3.eth.getCode(offChainComputed)).slice(2));
expect(this.constructorLessBytecode).to.include((await ethers.provider.getCode(offChainComputed)).slice(2));
});
it('deploys a contract with constructor arguments', async function () {
@ -84,7 +84,7 @@ describe('Create2', function () {
const instance = await ethers.getContractAt('VestingWallet', offChainComputed);
expect(await instance.owner()).to.equal(this.other.address);
expect(await instance.owner()).to.equal(this.other);
});
it('deploys a contract with funds deposited in the factory', async function () {

@ -29,9 +29,9 @@ describe('Multicall', function () {
]),
)
.to.emit(this.mock, 'Transfer')
.withArgs(this.holder.address, this.alice.address, this.amount / 2n)
.withArgs(this.holder, this.alice, this.amount / 2n)
.to.emit(this.mock, 'Transfer')
.withArgs(this.holder.address, this.bruce.address, this.amount / 3n);
.withArgs(this.holder, this.bruce, this.amount / 3n);
expect(await this.mock.balanceOf(this.alice)).to.equal(this.amount / 2n);
expect(await this.mock.balanceOf(this.bruce)).to.equal(this.amount / 3n);
@ -54,7 +54,7 @@ describe('Multicall', function () {
]),
)
.to.be.revertedWithCustomError(this.mock, 'ERC20InsufficientBalance')
.withArgs(this.holder.address, 0, this.amount);
.withArgs(this.holder, 0, this.amount);
expect(await this.mock.balanceOf(this.alice)).to.equal(0n);
});
@ -67,6 +67,6 @@ describe('Multicall', function () {
]),
)
.to.be.revertedWithCustomError(this.mock, 'ERC20InsufficientBalance')
.withArgs(this.holder.address, 0, this.amount);
.withArgs(this.holder, 0, this.amount);
});
});

@ -69,7 +69,7 @@ describe('Nonces', function () {
await expect(this.mock.$_useCheckedNonce(this.sender, currentNonce + 1n))
.to.be.revertedWithCustomError(this.mock, 'InvalidAccountNonce')
.withArgs(this.sender.address, currentNonce);
.withArgs(this.sender, currentNonce);
});
});
});

@ -39,7 +39,7 @@ describe('Pausable', function () {
});
it('emits a Paused event', async function () {
await expect(this.tx).to.emit(this.mock, 'Paused').withArgs(this.pauser.address);
await expect(this.tx).to.emit(this.mock, 'Paused').withArgs(this.pauser);
});
it('cannot perform normal process in pause', async function () {
@ -67,7 +67,7 @@ describe('Pausable', function () {
});
it('emits an Unpaused event', async function () {
await expect(this.tx).to.emit(this.mock, 'Unpaused').withArgs(this.pauser.address);
await expect(this.tx).to.emit(this.mock, 'Unpaused').withArgs(this.pauser);
});
it('should resume allowing normal process', async function () {

@ -6,10 +6,6 @@ const TEST_MESSAGE = ethers.id('OpenZeppelin');
const WRONG_MESSAGE = ethers.id('Nope');
const NON_HASH_MESSAGE = '0xabcd';
function toSignature(signature) {
return ethers.Signature.from(signature);
}
async function fixture() {
const [signer] = await ethers.getSigners();
const mock = await ethers.deployContract('$ECDSA');
@ -48,7 +44,7 @@ describe('ECDSA', function () {
const signature = await this.signer.signMessage(TEST_MESSAGE);
// Recover the signer address from the generated message and signature.
expect(await this.mock.$recover(ethers.hashMessage(TEST_MESSAGE), signature)).to.equal(this.signer.address);
expect(await this.mock.$recover(ethers.hashMessage(TEST_MESSAGE), signature)).to.equal(this.signer);
});
it('returns signer address with correct signature for arbitrary length message', async function () {
@ -56,12 +52,12 @@ describe('ECDSA', function () {
const signature = await this.signer.signMessage(NON_HASH_MESSAGE);
// Recover the signer address from the generated message and signature.
expect(await this.mock.$recover(ethers.hashMessage(NON_HASH_MESSAGE), signature)).to.equal(this.signer.address);
expect(await this.mock.$recover(ethers.hashMessage(NON_HASH_MESSAGE), signature)).to.equal(this.signer);
});
it('returns a different address', async function () {
const signature = await this.signer.signMessage(TEST_MESSAGE);
expect(await this.mock.$recover(WRONG_MESSAGE, signature)).to.not.be.equal(this.signer.address);
expect(await this.mock.$recover(WRONG_MESSAGE, signature)).to.not.be.equal(this.signer);
});
it('reverts with invalid signature', async function () {
@ -76,7 +72,6 @@ describe('ECDSA', function () {
});
describe('with v=27 signature', function () {
// Signature generated outside ganache with method web3.eth.sign(signer, message)
const signer = '0x2cc1166f6212628A0deEf2B33BEFB2187D35b86c';
// eslint-disable-next-line max-len
const signatureWithoutV =
@ -87,7 +82,7 @@ describe('ECDSA', function () {
const signature = ethers.concat([signatureWithoutV, v]);
expect(await this.mock.$recover(TEST_MESSAGE, signature)).to.equal(signer);
const { r, s, yParityAndS: vs } = toSignature(signature);
const { r, s, yParityAndS: vs } = ethers.Signature.from(signature);
expect(await this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s)).to.equal(
signer,
);
@ -100,7 +95,7 @@ describe('ECDSA', function () {
const signature = ethers.concat([signatureWithoutV, v]);
expect(await this.mock.$recover(TEST_MESSAGE, signature)).to.not.equal(signer);
const { r, s, yParityAndS: vs } = toSignature(signature);
const { r, s, yParityAndS: vs } = ethers.Signature.from(signature);
expect(
await this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s),
).to.not.equal(signer);
@ -118,7 +113,7 @@ describe('ECDSA', function () {
'ECDSAInvalidSignature',
);
const { r, s } = toSignature(signature);
const { r, s } = ethers.Signature.from(signature);
await expect(
this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s),
).to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignature');
@ -128,7 +123,9 @@ describe('ECDSA', function () {
it('rejects short EIP2098 format', async function () {
const v = '0x1b'; // 27 = 1b.
const signature = ethers.concat([signatureWithoutV, v]);
await expect(this.mock.$recover(TEST_MESSAGE, toSignature(signature).compactSerialized))
const { compactSerialized } = ethers.Signature.from(signature);
await expect(this.mock.$recover(TEST_MESSAGE, compactSerialized))
.to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureLength')
.withArgs(64);
});
@ -145,7 +142,7 @@ describe('ECDSA', function () {
const signature = ethers.concat([signatureWithoutV, v]);
expect(await this.mock.$recover(TEST_MESSAGE, signature)).to.equal(signer);
const { r, s, yParityAndS: vs } = toSignature(signature);
const { r, s, yParityAndS: vs } = ethers.Signature.from(signature);
expect(await this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s)).to.equal(
signer,
);
@ -158,7 +155,7 @@ describe('ECDSA', function () {
const signature = ethers.concat([signatureWithoutV, v]);
expect(await this.mock.$recover(TEST_MESSAGE, signature)).to.not.equal(signer);
const { r, s, yParityAndS: vs } = toSignature(signature);
const { r, s, yParityAndS: vs } = ethers.Signature.from(signature);
expect(
await this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s),
).to.not.equal(signer);
@ -176,7 +173,7 @@ describe('ECDSA', function () {
'ECDSAInvalidSignature',
);
const { r, s } = toSignature(signature);
const { r, s } = ethers.Signature.from(signature);
await expect(
this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s),
).to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignature');
@ -184,9 +181,11 @@ describe('ECDSA', function () {
});
it('rejects short EIP2098 format', async function () {
const v = '0x1c'; // 27 = 1b.
const v = '0x1b'; // 28 = 1b.
const signature = ethers.concat([signatureWithoutV, v]);
await expect(this.mock.$recover(TEST_MESSAGE, toSignature(signature).compactSerialized))
const { compactSerialized } = ethers.Signature.from(signature);
await expect(this.mock.$recover(TEST_MESSAGE, compactSerialized))
.to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureLength')
.withArgs(64);
});
@ -208,7 +207,7 @@ describe('ECDSA', function () {
await expect(this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s))
.to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureS')
.withArgs(s);
expect(() => toSignature(highSSignature)).to.throw('non-canonical s');
expect(() => ethers.Signature.from(highSSignature)).to.throw('non-canonical s');
});
});
});

@ -4,7 +4,6 @@ const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { getDomain, domainSeparator, hashTypedData } = require('../../helpers/eip712');
const { formatType } = require('../../helpers/eip712-types');
const { getChainId } = require('../../helpers/chainid');
const LENGTHS = {
short: ['A Name', '1'],
@ -21,7 +20,7 @@ const fixture = async () => {
lengths[shortOrLong].domain = {
name,
version,
chainId: await getChainId(),
chainId: await ethers.provider.getNetwork().then(({ chainId }) => chainId),
verifyingContract: lengths[shortOrLong].eip712.target,
};
}

@ -9,7 +9,7 @@ async function fixture() {
};
}
contract('ERC165', function () {
describe('ERC165', function () {
beforeEach(async function () {
Object.assign(this, await loadFixture(fixture));
});

@ -1,5 +1,5 @@
const { expect } = require('chai');
const { selector, interfaceId } = require('../../helpers/methods');
const { interfaceId } = require('../../helpers/methods');
const { mapValues } = require('../../helpers/iterate');
const INVALID_ID = '0xffffffff';
@ -123,15 +123,6 @@ function shouldSupportInterfaces(interfaces = []) {
// Check the presence of each function in the contract's interface
for (const fnSig of SIGNATURES[k]) {
// TODO: Remove Truffle case when ethersjs migration is done
if (this.contractUnderTest.abi) {
const fnSelector = selector(fnSig);
return expect(this.contractUnderTest.abi.filter(fn => fn.signature === fnSelector).length).to.equal(
1,
`did not find ${fnSig}`,
);
}
expect(this.contractUnderTest.interface.hasFunction(fnSig), `did not find ${fnSig}`).to.be.true;
}
}

@ -3,10 +3,8 @@ const { expect } = require('chai');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic');
const { Rounding } = require('../../helpers/enums');
const { min, max } = require('../../helpers/math');
const {
bigint: { Rounding },
} = require('../../helpers/enums.js');
const RoundingDown = [Rounding.Floor, Rounding.Trunc];
const RoundingUp = [Rounding.Ceil, Rounding.Expand];

@ -9,7 +9,7 @@ async function fixture() {
return { mock };
}
contract('SafeCast', function () {
describe('SafeCast', function () {
beforeEach(async function () {
Object.assign(this, await loadFixture(fixture));
});

@ -14,7 +14,7 @@ async function fixture() {
return { mock };
}
contract('SignedMath', function () {
describe('SignedMath', function () {
beforeEach(async function () {
Object.assign(this, await loadFixture(fixture));
});

@ -2,7 +2,7 @@ const { ethers } = require('hardhat');
const { expect } = require('chai');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { VALUE_SIZES } = require('../../../scripts/generate/templates/Checkpoints.opts.js');
const { VALUE_SIZES } = require('../../../scripts/generate/templates/Checkpoints.opts');
const last = array => (array.length ? array[array.length - 1] : undefined);

@ -4,9 +4,7 @@ const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { product } = require('../../helpers/iterate');
const { max } = require('../../helpers/math');
const {
bigint: { clock },
} = require('../../helpers/time');
const time = require('../../helpers/time');
const MAX_UINT32 = 1n << (32n - 1n);
const MAX_UINT48 = 1n << (48n - 1n);
@ -43,18 +41,18 @@ async function fixture() {
return { mock };
}
contract('Time', function () {
describe('Time', function () {
beforeEach(async function () {
Object.assign(this, await loadFixture(fixture));
});
describe('clocks', function () {
it('timestamp', async function () {
expect(await this.mock.$timestamp()).to.equal(await clock.timestamp());
expect(await this.mock.$timestamp()).to.equal(await time.clock.timestamp());
});
it('block number', async function () {
expect(await this.mock.$blockNumber()).to.equal(await clock.blocknumber());
expect(await this.mock.$blockNumber()).to.equal(await time.clock.blocknumber());
});
});
@ -92,7 +90,7 @@ contract('Time', function () {
});
it('get & getFull', async function () {
const timepoint = await clock.timestamp().then(BigInt);
const timepoint = await time.clock.timestamp();
const valueBefore = 24194n;
const valueAfter = 4214143n;
@ -110,7 +108,7 @@ contract('Time', function () {
});
it('withUpdate', async function () {
const timepoint = await clock.timestamp().then(BigInt);
const timepoint = await time.clock.timestamp();
const valueBefore = 24194n;
const valueAfter = 4214143n;
const newvalueAfter = 94716n;

Loading…
Cancel
Save