@keep-network/tbtc-v2 0.1.0 → 0.1.1-dev

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (296) hide show
  1. package/README.adoc +12 -0
  2. package/artifacts/.chainId +1 -1
  3. package/artifacts/Bank.json +807 -0
  4. package/artifacts/Bridge.json +2300 -0
  5. package/artifacts/Deposit.json +117 -0
  6. package/artifacts/DepositSweep.json +77 -0
  7. package/artifacts/EcdsaDkgValidator.json +532 -0
  8. package/artifacts/EcdsaInactivity.json +156 -0
  9. package/artifacts/EcdsaSortitionPool.json +1004 -0
  10. package/artifacts/Fraud.json +164 -0
  11. package/artifacts/KeepRegistry.json +99 -0
  12. package/artifacts/KeepStake.json +286 -0
  13. package/artifacts/KeepToken.json +711 -0
  14. package/artifacts/KeepTokenStaking.json +483 -0
  15. package/artifacts/MovingFunds.json +249 -0
  16. package/artifacts/NuCypherStakingEscrow.json +256 -0
  17. package/artifacts/NuCypherToken.json +711 -0
  18. package/artifacts/RandomBeaconStub.json +141 -0
  19. package/artifacts/Redemption.json +174 -0
  20. package/artifacts/ReimbursementPool.json +509 -0
  21. package/artifacts/Relay.json +123 -0
  22. package/artifacts/T.json +1148 -0
  23. package/artifacts/TBTC.json +36 -35
  24. package/artifacts/TBTCToken.json +738 -0
  25. package/artifacts/TBTCVault.json +691 -0
  26. package/artifacts/TokenStaking.json +2288 -0
  27. package/artifacts/TokenholderGovernor.json +1795 -0
  28. package/artifacts/TokenholderTimelock.json +1058 -0
  29. package/artifacts/VendingMachine.json +34 -33
  30. package/artifacts/VendingMachineKeep.json +400 -0
  31. package/artifacts/VendingMachineNuCypher.json +400 -0
  32. package/artifacts/WalletRegistry.json +1843 -0
  33. package/artifacts/WalletRegistryGovernance.json +2754 -0
  34. package/artifacts/Wallets.json +186 -0
  35. package/artifacts/solcInputs/5e62cff1ead0900b07facca4b559e818.json +314 -0
  36. package/build/contracts/GovernanceUtils.sol/GovernanceUtils.dbg.json +1 -1
  37. package/build/contracts/GovernanceUtils.sol/GovernanceUtils.json +2 -2
  38. package/build/contracts/bank/Bank.sol/Bank.dbg.json +4 -0
  39. package/build/contracts/bank/Bank.sol/Bank.json +542 -0
  40. package/build/contracts/bank/IReceiveBalanceApproval.sol/IReceiveBalanceApproval.dbg.json +4 -0
  41. package/build/contracts/bank/IReceiveBalanceApproval.sol/IReceiveBalanceApproval.json +34 -0
  42. package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.dbg.json +4 -0
  43. package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.json +10 -0
  44. package/build/contracts/bridge/Bridge.sol/Bridge.dbg.json +4 -0
  45. package/build/contracts/bridge/Bridge.sol/Bridge.json +2686 -0
  46. package/build/contracts/bridge/BridgeState.sol/BridgeState.dbg.json +4 -0
  47. package/build/contracts/bridge/BridgeState.sol/BridgeState.json +226 -0
  48. package/build/contracts/bridge/Deposit.sol/Deposit.dbg.json +4 -0
  49. package/build/contracts/bridge/Deposit.sol/Deposit.json +72 -0
  50. package/build/contracts/bridge/DepositSweep.sol/DepositSweep.dbg.json +4 -0
  51. package/build/contracts/bridge/DepositSweep.sol/DepositSweep.json +30 -0
  52. package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.dbg.json +4 -0
  53. package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.json +10 -0
  54. package/build/contracts/bridge/Fraud.sol/Fraud.dbg.json +4 -0
  55. package/build/contracts/bridge/Fraud.sol/Fraud.json +86 -0
  56. package/build/contracts/bridge/Heartbeat.sol/Heartbeat.dbg.json +4 -0
  57. package/build/contracts/bridge/Heartbeat.sol/Heartbeat.json +10 -0
  58. package/build/contracts/bridge/IRelay.sol/IRelay.dbg.json +4 -0
  59. package/build/contracts/bridge/IRelay.sol/IRelay.json +37 -0
  60. package/build/contracts/bridge/MovingFunds.sol/MovingFunds.dbg.json +4 -0
  61. package/build/contracts/bridge/MovingFunds.sol/MovingFunds.json +138 -0
  62. package/build/contracts/bridge/Redemption.sol/OutboundTx.dbg.json +4 -0
  63. package/build/contracts/bridge/Redemption.sol/OutboundTx.json +10 -0
  64. package/build/contracts/bridge/Redemption.sol/Redemption.dbg.json +4 -0
  65. package/build/contracts/bridge/Redemption.sol/Redemption.json +92 -0
  66. package/build/contracts/bridge/VendingMachine.sol/VendingMachine.dbg.json +1 -1
  67. package/build/contracts/bridge/VendingMachine.sol/VendingMachine.json +2 -2
  68. package/build/contracts/bridge/Wallets.sol/Wallets.dbg.json +4 -0
  69. package/build/contracts/bridge/Wallets.sol/Wallets.json +112 -0
  70. package/build/contracts/token/TBTC.sol/TBTC.dbg.json +1 -1
  71. package/build/contracts/token/TBTC.sol/TBTC.json +4 -4
  72. package/build/contracts/vault/DonationVault.sol/DonationVault.dbg.json +4 -0
  73. package/build/contracts/vault/DonationVault.sol/DonationVault.json +108 -0
  74. package/build/contracts/vault/IVault.sol/IVault.dbg.json +4 -0
  75. package/build/contracts/vault/IVault.sol/IVault.json +52 -0
  76. package/build/contracts/vault/TBTCVault.sol/TBTCVault.dbg.json +4 -0
  77. package/build/contracts/vault/TBTCVault.sol/TBTCVault.json +449 -0
  78. package/contracts/GovernanceUtils.sol +4 -4
  79. package/contracts/bank/Bank.sol +436 -0
  80. package/contracts/bank/IReceiveBalanceApproval.sol +45 -0
  81. package/contracts/bridge/BitcoinTx.sol +326 -0
  82. package/contracts/bridge/Bridge.sol +1793 -0
  83. package/contracts/bridge/BridgeState.sol +739 -0
  84. package/contracts/bridge/Deposit.sol +269 -0
  85. package/contracts/bridge/DepositSweep.sol +574 -0
  86. package/contracts/bridge/EcdsaLib.sol +45 -0
  87. package/contracts/bridge/Fraud.sol +579 -0
  88. package/contracts/bridge/Heartbeat.sol +112 -0
  89. package/contracts/bridge/IRelay.sol +28 -0
  90. package/contracts/bridge/MovingFunds.sol +1077 -0
  91. package/contracts/bridge/Redemption.sol +1020 -0
  92. package/contracts/bridge/VendingMachine.sol +2 -2
  93. package/contracts/bridge/Wallets.sol +719 -0
  94. package/contracts/hardhat-dependency-compiler/.hardhat-dependency-compiler +1 -0
  95. package/contracts/hardhat-dependency-compiler/@keep-network/ecdsa/contracts/WalletRegistry.sol +3 -0
  96. package/contracts/hardhat-dependency-compiler/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol +3 -0
  97. package/contracts/hardhat-dependency-compiler/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol +3 -0
  98. package/contracts/token/TBTC.sol +1 -1
  99. package/contracts/vault/DonationVault.sol +125 -0
  100. package/contracts/vault/IVault.sol +44 -0
  101. package/contracts/vault/TBTCVault.sol +305 -0
  102. package/deploy/00_resolve_relay.ts +28 -0
  103. package/deploy/00_resolve_tbtc_v1_token.ts +1 -1
  104. package/deploy/01_deploy_tbtc_v2_token.ts +8 -1
  105. package/deploy/02_deploy_vending_machine.ts +7 -0
  106. package/deploy/{03_transfer_roles.ts → 03_transfer_vending_machine_roles.ts} +1 -1
  107. package/deploy/04_deploy_bank.ts +27 -0
  108. package/deploy/05_deploy_bridge.ts +80 -0
  109. package/deploy/06_deploy_tbtc_vault.ts +30 -0
  110. package/deploy/07_bank_update_bridge.ts +19 -0
  111. package/deploy/08_transfer_bank_ownership.ts +15 -0
  112. package/deploy/09_transfer_tbtc_vault_ownership.ts +15 -0
  113. package/deploy/10_transfer_bridge_governance.ts +20 -0
  114. package/deploy/11_initialize_wallet_owner.ts +18 -0
  115. package/deploy/11_transfer_proxy_admin_ownership.ts +30 -0
  116. package/deploy/12_deploy_proxy_admin_with_deputy.ts +33 -0
  117. package/export/deploy/00_resolve_relay.js +24 -0
  118. package/export/deploy/00_resolve_tbtc_v1_token.js +24 -0
  119. package/export/deploy/01_deploy_tbtc_v2_token.js +19 -0
  120. package/export/deploy/02_deploy_vending_machine.js +25 -0
  121. package/export/deploy/03_transfer_vending_machine_roles.js +19 -0
  122. package/export/deploy/04_deploy_bank.js +21 -0
  123. package/export/deploy/05_deploy_bridge.js +69 -0
  124. package/export/deploy/06_deploy_tbtc_vault.js +24 -0
  125. package/export/deploy/07_bank_update_bridge.js +13 -0
  126. package/export/deploy/08_transfer_bank_ownership.js +11 -0
  127. package/export/deploy/09_transfer_tbtc_vault_ownership.js +11 -0
  128. package/export/deploy/10_transfer_bridge_governance.js +11 -0
  129. package/export/deploy/11_initialize_wallet_owner.js +14 -0
  130. package/export/deploy/11_transfer_proxy_admin_ownership.js +23 -0
  131. package/export/deploy/12_deploy_proxy_admin_with_deputy.js +22 -0
  132. package/export/hardhat.config.js +169 -0
  133. package/export/test/bank/Bank.test.js +1012 -0
  134. package/export/test/bridge/Bridge.Deployment.test.js +76 -0
  135. package/export/test/bridge/Bridge.Deposit.test.js +1834 -0
  136. package/export/test/bridge/Bridge.Frauds.test.js +1349 -0
  137. package/export/test/bridge/Bridge.MovingFunds.test.js +2437 -0
  138. package/export/test/bridge/Bridge.Parameters.test.js +400 -0
  139. package/export/test/bridge/Bridge.Redemption.test.js +2523 -0
  140. package/export/test/bridge/Bridge.Vaults.test.js +74 -0
  141. package/export/test/bridge/Bridge.Wallets.test.js +1017 -0
  142. package/export/test/bridge/EcdsaLib.test.js +46 -0
  143. package/export/test/bridge/Heartbeat.test.js +77 -0
  144. package/export/test/bridge/VendingMachine.Upgrade.test.js +160 -0
  145. package/export/test/bridge/VendingMachine.test.js +762 -0
  146. package/export/test/data/deposit-sweep.js +655 -0
  147. package/export/test/data/ecdsa.js +18 -0
  148. package/export/test/data/fraud.js +158 -0
  149. package/export/test/data/moving-funds.js +815 -0
  150. package/export/test/data/redemption.js +1011 -0
  151. package/export/test/fixtures/bridge.js +54 -0
  152. package/export/test/fixtures/index.js +57 -0
  153. package/export/test/helpers/contract-test-helpers.js +18 -0
  154. package/export/test/integration/Slashing.test.js +279 -0
  155. package/export/test/integration/WalleCreation.test.js +66 -0
  156. package/export/test/integration/utils/ecdsa-wallet-registry.js +137 -0
  157. package/export/test/integration/utils/fixture.js +77 -0
  158. package/export/test/integration/utils/gas.js +36 -0
  159. package/export/test/integration/utils/random-beacon.js +26 -0
  160. package/export/test/integration/utils/staking.js +19 -0
  161. package/export/test/vault/DonationVault.test.js +202 -0
  162. package/export/test/vault/TBTCVault.Redemption.test.js +357 -0
  163. package/export/test/vault/TBTCVault.test.js +768 -0
  164. package/export/typechain/BTCUtils.js +2 -0
  165. package/export/typechain/Bank.js +2 -0
  166. package/export/typechain/BankStub.js +2 -0
  167. package/export/typechain/Bridge.js +2 -0
  168. package/export/typechain/BridgeState.js +2 -0
  169. package/export/typechain/BridgeStub.js +2 -0
  170. package/export/typechain/Deposit.js +2 -0
  171. package/export/typechain/DepositSweep.js +2 -0
  172. package/export/typechain/DonationVault.js +2 -0
  173. package/export/typechain/ERC165.js +2 -0
  174. package/export/typechain/ERC1967Proxy.js +2 -0
  175. package/export/typechain/ERC1967Upgrade.js +2 -0
  176. package/export/typechain/ERC20WithPermit.js +2 -0
  177. package/export/typechain/ERC721.js +2 -0
  178. package/export/typechain/EcdsaAuthorization.js +2 -0
  179. package/export/typechain/EcdsaDkg.js +2 -0
  180. package/export/typechain/EcdsaDkgValidator.js +2 -0
  181. package/export/typechain/EcdsaInactivity.js +2 -0
  182. package/export/typechain/Fraud.js +2 -0
  183. package/export/typechain/Governable.js +2 -0
  184. package/export/typechain/HeartbeatStub.js +2 -0
  185. package/export/typechain/IApplication.js +2 -0
  186. package/export/typechain/IApproveAndCall.js +2 -0
  187. package/export/typechain/IBeacon.js +2 -0
  188. package/export/typechain/IERC165.js +2 -0
  189. package/export/typechain/IERC1822Proxiable.js +2 -0
  190. package/export/typechain/IERC20.js +2 -0
  191. package/export/typechain/IERC20Metadata.js +2 -0
  192. package/export/typechain/IERC20WithPermit.js +2 -0
  193. package/export/typechain/IERC721.js +2 -0
  194. package/export/typechain/IERC721Metadata.js +2 -0
  195. package/export/typechain/IERC721Receiver.js +2 -0
  196. package/export/typechain/IRandomBeacon.js +2 -0
  197. package/export/typechain/IRandomBeaconConsumer.js +2 -0
  198. package/export/typechain/IReceiveApproval.js +2 -0
  199. package/export/typechain/IReceiveBalanceApproval.js +2 -0
  200. package/export/typechain/IRelay.js +2 -0
  201. package/export/typechain/IStaking.js +2 -0
  202. package/export/typechain/IVault.js +2 -0
  203. package/export/typechain/IWalletOwner.js +2 -0
  204. package/export/typechain/IWalletRegistry.js +2 -0
  205. package/export/typechain/Initializable.js +2 -0
  206. package/export/typechain/MisfundRecovery.js +2 -0
  207. package/export/typechain/MovingFunds.js +2 -0
  208. package/export/typechain/Ownable.js +2 -0
  209. package/export/typechain/Proxy.js +2 -0
  210. package/export/typechain/ProxyAdmin.js +2 -0
  211. package/export/typechain/ReceiveApprovalStub.js +2 -0
  212. package/export/typechain/Redemption.js +2 -0
  213. package/export/typechain/Reimbursable.js +2 -0
  214. package/export/typechain/ReimbursementPool.js +2 -0
  215. package/export/typechain/Rewards.js +2 -0
  216. package/export/typechain/SortitionPool.js +2 -0
  217. package/export/typechain/SortitionTree.js +2 -0
  218. package/export/typechain/TBTC.js +2 -0
  219. package/export/typechain/TBTCVault.js +2 -0
  220. package/export/typechain/TestERC20.js +2 -0
  221. package/export/typechain/TestERC721.js +2 -0
  222. package/export/typechain/TestEcdsaLib.js +2 -0
  223. package/export/typechain/TestRelay.js +2 -0
  224. package/export/typechain/TransparentUpgradeableProxy.js +2 -0
  225. package/export/typechain/VendingMachine.js +2 -0
  226. package/export/typechain/WalletRegistry.js +2 -0
  227. package/export/typechain/Wallets.js +2 -0
  228. package/export/typechain/common.js +2 -0
  229. package/export/typechain/factories/BTCUtils__factory.js +94 -0
  230. package/export/typechain/factories/BankStub__factory.js +586 -0
  231. package/export/typechain/factories/Bank__factory.js +573 -0
  232. package/export/typechain/factories/BridgeState__factory.js +257 -0
  233. package/export/typechain/factories/BridgeStub__factory.js +2912 -0
  234. package/export/typechain/factories/Bridge__factory.js +2526 -0
  235. package/export/typechain/factories/DepositSweep__factory.js +61 -0
  236. package/export/typechain/factories/Deposit__factory.js +103 -0
  237. package/export/typechain/factories/DonationVault__factory.js +139 -0
  238. package/export/typechain/factories/ERC165__factory.js +38 -0
  239. package/export/typechain/factories/ERC1967Proxy__factory.js +111 -0
  240. package/export/typechain/factories/ERC1967Upgrade__factory.js +64 -0
  241. package/export/typechain/factories/ERC20WithPermit__factory.js +524 -0
  242. package/export/typechain/factories/ERC721__factory.js +388 -0
  243. package/export/typechain/factories/EcdsaAuthorization__factory.js +211 -0
  244. package/export/typechain/factories/EcdsaDkgValidator__factory.js +441 -0
  245. package/export/typechain/factories/EcdsaDkg__factory.js +192 -0
  246. package/export/typechain/factories/EcdsaInactivity__factory.js +134 -0
  247. package/export/typechain/factories/Fraud__factory.js +117 -0
  248. package/export/typechain/factories/Governable__factory.js +64 -0
  249. package/export/typechain/factories/HeartbeatStub__factory.js +61 -0
  250. package/export/typechain/factories/IApplication__factory.js +152 -0
  251. package/export/typechain/factories/IApproveAndCall__factory.js +48 -0
  252. package/export/typechain/factories/IBeacon__factory.js +32 -0
  253. package/export/typechain/factories/IERC165__factory.js +38 -0
  254. package/export/typechain/factories/IERC1822Proxiable__factory.js +32 -0
  255. package/export/typechain/factories/IERC20Metadata__factory.js +241 -0
  256. package/export/typechain/factories/IERC20WithPermit__factory.js +389 -0
  257. package/export/typechain/factories/IERC20__factory.js +202 -0
  258. package/export/typechain/factories/IERC721Metadata__factory.js +349 -0
  259. package/export/typechain/factories/IERC721Receiver__factory.js +53 -0
  260. package/export/typechain/factories/IERC721__factory.js +304 -0
  261. package/export/typechain/factories/IRandomBeaconConsumer__factory.js +37 -0
  262. package/export/typechain/factories/IRandomBeacon__factory.js +32 -0
  263. package/export/typechain/factories/IReceiveApproval__factory.js +47 -0
  264. package/export/typechain/factories/IReceiveBalanceApproval__factory.js +42 -0
  265. package/export/typechain/factories/IRelay__factory.js +45 -0
  266. package/export/typechain/factories/IStaking__factory.js +722 -0
  267. package/export/typechain/factories/IVault__factory.js +60 -0
  268. package/export/typechain/factories/IWalletOwner__factory.js +65 -0
  269. package/export/typechain/factories/IWalletRegistry__factory.js +138 -0
  270. package/export/typechain/factories/Initializable__factory.js +32 -0
  271. package/export/typechain/factories/MisfundRecovery__factory.js +145 -0
  272. package/export/typechain/factories/MovingFunds__factory.js +169 -0
  273. package/export/typechain/factories/Ownable__factory.js +71 -0
  274. package/export/typechain/factories/ProxyAdmin__factory.js +191 -0
  275. package/export/typechain/factories/Proxy__factory.js +27 -0
  276. package/export/typechain/factories/ReceiveApprovalStub__factory.js +127 -0
  277. package/export/typechain/factories/Redemption__factory.js +123 -0
  278. package/export/typechain/factories/Reimbursable__factory.js +58 -0
  279. package/export/typechain/factories/ReimbursementPool__factory.js +350 -0
  280. package/export/typechain/factories/Rewards__factory.js +117 -0
  281. package/export/typechain/factories/SortitionPool__factory.js +610 -0
  282. package/export/typechain/factories/SortitionTree__factory.js +149 -0
  283. package/export/typechain/factories/TBTCVault__factory.js +480 -0
  284. package/export/typechain/factories/TBTC__factory.js +564 -0
  285. package/export/typechain/factories/TestERC20__factory.js +539 -0
  286. package/export/typechain/factories/TestERC721__factory.js +421 -0
  287. package/export/typechain/factories/TestEcdsaLib__factory.js +66 -0
  288. package/export/typechain/factories/TestRelay__factory.js +94 -0
  289. package/export/typechain/factories/TransparentUpgradeableProxy__factory.js +186 -0
  290. package/export/typechain/factories/VendingMachine__factory.js +549 -0
  291. package/export/typechain/factories/WalletRegistry__factory.js +1919 -0
  292. package/export/typechain/factories/Wallets__factory.js +143 -0
  293. package/export/typechain/index.js +132 -0
  294. package/export.json +15932 -503
  295. package/package.json +47 -26
  296. package/artifacts/solcInputs/7cc3eda3cb3ff2522d18b5e7b31ea228.json +0 -104
@@ -0,0 +1,1012 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ const hardhat_1 = require("hardhat");
27
+ const chai_1 = __importStar(require("chai"));
28
+ const smock_1 = require("@defi-wonderland/smock");
29
+ chai_1.default.use(smock_1.smock.matchers);
30
+ const { to1e18 } = hardhat_1.helpers.number;
31
+ const { createSnapshot, restoreSnapshot } = hardhat_1.helpers.snapshot;
32
+ const ZERO_ADDRESS = hardhat_1.ethers.constants.AddressZero;
33
+ const MAX_UINT256 = hardhat_1.ethers.constants.MaxUint256;
34
+ const fixture = async () => {
35
+ const [deployer, governance, bridge, thirdParty] = await hardhat_1.ethers.getSigners();
36
+ const Bank = await hardhat_1.ethers.getContractFactory("Bank");
37
+ const bank = await Bank.deploy();
38
+ await bank.deployed();
39
+ await bank.connect(deployer).updateBridge(bridge.address);
40
+ await bank.connect(deployer).transferOwnership(governance.address);
41
+ return {
42
+ deployer,
43
+ governance,
44
+ bridge,
45
+ thirdParty,
46
+ bank,
47
+ };
48
+ };
49
+ describe("Bank", () => {
50
+ // default Hardhat's networks blockchain, see https://hardhat.org/config/
51
+ const hardhatNetworkId = 31337;
52
+ let deployer;
53
+ let governance;
54
+ let bridge;
55
+ let thirdParty;
56
+ let bank;
57
+ before(async () => {
58
+ // eslint-disable-next-line @typescript-eslint/no-extra-semi
59
+ ;
60
+ ({ deployer, governance, bridge, thirdParty, bank } =
61
+ await hardhat_1.waffle.loadFixture(fixture));
62
+ });
63
+ describe("PERMIT_TYPEHASH", () => {
64
+ it("should be keccak256 of EIP2612 Permit message", async () => {
65
+ const expected = hardhat_1.ethers.utils.keccak256(hardhat_1.ethers.utils.toUtf8Bytes("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"));
66
+ (0, chai_1.expect)(await bank.PERMIT_TYPEHASH()).to.equal(expected);
67
+ // double-checking...
68
+ (0, chai_1.expect)(await bank.PERMIT_TYPEHASH()).to.equal("0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9");
69
+ });
70
+ });
71
+ describe("updateBridge", () => {
72
+ before(async () => {
73
+ await createSnapshot();
74
+ });
75
+ after(async () => {
76
+ await restoreSnapshot();
77
+ });
78
+ context("when called by a third party", () => {
79
+ it("should revert", async () => {
80
+ await (0, chai_1.expect)(bank.connect(thirdParty).updateBridge(thirdParty.address)).to.be.revertedWith("Ownable: caller is not the owner");
81
+ });
82
+ });
83
+ context("when called with 0-address bridge", () => {
84
+ it("should revert", async () => {
85
+ await (0, chai_1.expect)(bank.connect(governance).updateBridge(ZERO_ADDRESS)).to.be.revertedWith("Bridge address must not be 0x0");
86
+ });
87
+ });
88
+ context("when called by the governance", () => {
89
+ let tx;
90
+ before(async () => {
91
+ await createSnapshot();
92
+ tx = await bank.connect(governance).updateBridge(thirdParty.address);
93
+ });
94
+ after(async () => {
95
+ await restoreSnapshot();
96
+ });
97
+ it("should update the bridge", async () => {
98
+ (0, chai_1.expect)(await bank.bridge()).to.equal(thirdParty.address);
99
+ });
100
+ it("should emit the BridgeUpdated event", async () => {
101
+ await (0, chai_1.expect)(tx)
102
+ .to.emit(bank, "BridgeUpdated")
103
+ .withArgs(thirdParty.address);
104
+ });
105
+ });
106
+ });
107
+ describe("transferBalance", () => {
108
+ const initialBalance = to1e18(500);
109
+ let spender;
110
+ let recipient;
111
+ before(async () => {
112
+ await createSnapshot();
113
+ const accounts = await (0, hardhat_1.getUnnamedAccounts)();
114
+ spender = await hardhat_1.ethers.getSigner(accounts[0]);
115
+ // eslint-disable-next-line prefer-destructuring
116
+ recipient = accounts[1];
117
+ await bank
118
+ .connect(bridge)
119
+ .increaseBalance(spender.address, initialBalance);
120
+ });
121
+ after(async () => {
122
+ await restoreSnapshot();
123
+ });
124
+ context("when the recipient is the zero address", () => {
125
+ it("should revert", async () => {
126
+ await (0, chai_1.expect)(bank.connect(spender).transferBalance(ZERO_ADDRESS, initialBalance)).to.be.revertedWith("Can not transfer to the zero address");
127
+ });
128
+ });
129
+ context("when the recipient is the bank address", () => {
130
+ it("should revert", async () => {
131
+ await (0, chai_1.expect)(bank.connect(spender).transferBalance(bank.address, initialBalance)).to.be.revertedWith("Can not transfer to the Bank address");
132
+ });
133
+ });
134
+ context("when the spender has not enough balance", () => {
135
+ it("should revert", async () => {
136
+ await (0, chai_1.expect)(bank
137
+ .connect(spender)
138
+ .transferBalance(recipient, initialBalance.add(1))).to.be.revertedWith("Transfer amount exceeds balance");
139
+ });
140
+ });
141
+ context("when the spender transfers part of their balance", () => {
142
+ const amount = to1e18(21);
143
+ let tx;
144
+ before(async () => {
145
+ await createSnapshot();
146
+ tx = await bank.connect(spender).transferBalance(recipient, amount);
147
+ });
148
+ after(async () => {
149
+ await restoreSnapshot();
150
+ });
151
+ it("should transfer the requested amount", async () => {
152
+ (0, chai_1.expect)(await bank.balanceOf(spender.address)).to.equal(initialBalance.sub(amount));
153
+ (0, chai_1.expect)(await bank.balanceOf(recipient)).to.equal(amount);
154
+ });
155
+ it("should emit the BalanceTransferred event", async () => {
156
+ await (0, chai_1.expect)(tx)
157
+ .to.emit(bank, "BalanceTransferred")
158
+ .withArgs(spender.address, recipient, amount);
159
+ });
160
+ });
161
+ context("when the spender transfers part of their balance in two transactions", () => {
162
+ const amount1 = to1e18(21);
163
+ const amount2 = to1e18(12);
164
+ before(async () => {
165
+ await createSnapshot();
166
+ await bank.connect(spender).transferBalance(recipient, amount1);
167
+ await bank.connect(spender).transferBalance(recipient, amount2);
168
+ });
169
+ after(async () => {
170
+ await restoreSnapshot();
171
+ });
172
+ it("should transfer the requested amount", async () => {
173
+ (0, chai_1.expect)(await bank.balanceOf(spender.address)).to.equal(initialBalance.sub(amount1).sub(amount2));
174
+ (0, chai_1.expect)(await bank.balanceOf(recipient)).to.equal(amount1.add(amount2));
175
+ });
176
+ });
177
+ context("when the spender transfers their entire balance", () => {
178
+ const amount = initialBalance;
179
+ let tx;
180
+ before(async () => {
181
+ await createSnapshot();
182
+ tx = await bank.connect(spender).transferBalance(recipient, amount);
183
+ });
184
+ after(async () => {
185
+ await restoreSnapshot();
186
+ });
187
+ it("should transfer the entire balance", async () => {
188
+ (0, chai_1.expect)(await bank.balanceOf(spender.address)).to.equal(0);
189
+ (0, chai_1.expect)(await bank.balanceOf(recipient)).to.equal(amount);
190
+ });
191
+ it("should emit the BalanceTransferred event", async () => {
192
+ await (0, chai_1.expect)(tx)
193
+ .to.emit(bank, "BalanceTransferred")
194
+ .withArgs(spender.address, recipient, amount);
195
+ });
196
+ });
197
+ context("when the spender transfers 0 balance", () => {
198
+ const amount = 0;
199
+ let tx;
200
+ before(async () => {
201
+ await createSnapshot();
202
+ tx = await bank.connect(spender).transferBalance(recipient, amount);
203
+ });
204
+ after(async () => {
205
+ await restoreSnapshot();
206
+ });
207
+ it("should transfer no balance", async () => {
208
+ (0, chai_1.expect)(await bank.balanceOf(spender.address)).to.equal(initialBalance);
209
+ (0, chai_1.expect)(await bank.balanceOf(recipient)).to.equal(0);
210
+ });
211
+ it("should emit the BalanceTransferred event", async () => {
212
+ await (0, chai_1.expect)(tx)
213
+ .to.emit(bank, "BalanceTransferred")
214
+ .withArgs(spender.address, recipient, 0);
215
+ });
216
+ });
217
+ });
218
+ describe("approveBalanceAndCall", () => {
219
+ const amount = to1e18(11);
220
+ let owner;
221
+ let mockVault;
222
+ before(async () => {
223
+ const accounts = await (0, hardhat_1.getUnnamedAccounts)();
224
+ owner = await hardhat_1.ethers.getSigner(accounts[0]);
225
+ mockVault = await smock_1.smock.fake("IVault");
226
+ });
227
+ context("when the spender is the zero address", () => {
228
+ it("should revert", async () => {
229
+ await (0, chai_1.expect)(bank.connect(owner).approveBalanceAndCall(ZERO_ADDRESS, amount, [])).to.be.revertedWith("Can not approve to the zero address");
230
+ });
231
+ });
232
+ context("when the spender callback reverted", () => {
233
+ before(async () => {
234
+ await mockVault.receiveBalanceApproval.reverts();
235
+ });
236
+ after(async () => {
237
+ mockVault.receiveBalanceApproval.reset();
238
+ });
239
+ it("should revert", async () => {
240
+ await (0, chai_1.expect)(bank
241
+ .connect(owner)
242
+ .approveBalanceAndCall(mockVault.address, amount, [])).to.be.reverted;
243
+ });
244
+ });
245
+ context("when the spender had no approved balance before", () => {
246
+ let tx;
247
+ before(async () => {
248
+ await createSnapshot();
249
+ tx = await bank
250
+ .connect(owner)
251
+ .approveBalanceAndCall(mockVault.address, amount, "0x11");
252
+ });
253
+ after(async () => {
254
+ await restoreSnapshot();
255
+ mockVault.receiveBalanceApproval.reset();
256
+ });
257
+ it("should approve the requested amount", async () => {
258
+ (0, chai_1.expect)(await bank.allowance(owner.address, mockVault.address)).to.equal(amount);
259
+ });
260
+ it("should emit the BalanceApproved event", async () => {
261
+ await (0, chai_1.expect)(tx)
262
+ .to.emit(bank, "BalanceApproved")
263
+ .withArgs(owner.address, mockVault.address, amount);
264
+ });
265
+ it("should call receiveBalanceApproval", async () => {
266
+ (0, chai_1.expect)(mockVault.receiveBalanceApproval).to.have.been.calledOnceWith(owner.address, amount, "0x11");
267
+ });
268
+ });
269
+ context("when the spender had an approved balance before", () => {
270
+ before(async () => {
271
+ await createSnapshot();
272
+ await bank
273
+ .connect(owner)
274
+ .approveBalance(mockVault.address, to1e18(1337));
275
+ await bank
276
+ .connect(owner)
277
+ .approveBalanceAndCall(mockVault.address, amount, "0x02");
278
+ });
279
+ after(async () => {
280
+ await restoreSnapshot();
281
+ mockVault.receiveBalanceApproval.reset();
282
+ });
283
+ it("should replace the previous allowance", async () => {
284
+ (0, chai_1.expect)(await bank.allowance(owner.address, mockVault.address)).to.equal(amount);
285
+ });
286
+ it("should call receiveBalanceApproval", async () => {
287
+ (0, chai_1.expect)(mockVault.receiveBalanceApproval).to.have.been.calledOnceWith(owner.address, amount, "0x02");
288
+ });
289
+ });
290
+ });
291
+ describe("approveBalance", () => {
292
+ const amount = to1e18(10);
293
+ let owner;
294
+ let spender;
295
+ before(async () => {
296
+ const accounts = await (0, hardhat_1.getUnnamedAccounts)();
297
+ owner = await hardhat_1.ethers.getSigner(accounts[0]);
298
+ // eslint-disable-next-line prefer-destructuring
299
+ spender = accounts[1];
300
+ });
301
+ context("when the spender is the zero address", () => {
302
+ it("should revert", async () => {
303
+ await (0, chai_1.expect)(bank.connect(owner).approveBalance(ZERO_ADDRESS, amount)).to.be.revertedWith("Can not approve to the zero address");
304
+ });
305
+ });
306
+ context("when the spender had no approved balance before", () => {
307
+ let tx;
308
+ before(async () => {
309
+ await createSnapshot();
310
+ tx = await bank.connect(owner).approveBalance(spender, amount);
311
+ });
312
+ after(async () => {
313
+ await restoreSnapshot();
314
+ });
315
+ it("should approve the requested amount", async () => {
316
+ (0, chai_1.expect)(await bank.allowance(owner.address, spender)).to.equal(amount);
317
+ });
318
+ it("should emit the BalanceApproved event", async () => {
319
+ await (0, chai_1.expect)(tx)
320
+ .to.emit(bank, "BalanceApproved")
321
+ .withArgs(owner.address, spender, amount);
322
+ });
323
+ });
324
+ context("when the spender had an approved balance before", () => {
325
+ before(async () => {
326
+ await createSnapshot();
327
+ await bank.connect(owner).approveBalance(spender, to1e18(1337));
328
+ await bank.connect(owner).approveBalance(spender, amount);
329
+ });
330
+ after(async () => {
331
+ await restoreSnapshot();
332
+ });
333
+ it("should replace the previous allowance", async () => {
334
+ (0, chai_1.expect)(await bank.allowance(owner.address, spender)).to.equal(amount);
335
+ });
336
+ });
337
+ });
338
+ describe("increaseBalanceAllowance", () => {
339
+ const amount = to1e18(12);
340
+ let owner;
341
+ let spender;
342
+ before(async () => {
343
+ await createSnapshot();
344
+ const accounts = await (0, hardhat_1.getUnnamedAccounts)();
345
+ owner = await hardhat_1.ethers.getSigner(accounts[0]);
346
+ // eslint-disable-next-line prefer-destructuring
347
+ spender = accounts[1];
348
+ });
349
+ after(async () => {
350
+ await restoreSnapshot();
351
+ });
352
+ context("when the spender is the zero address", () => {
353
+ it("should revert", async () => {
354
+ await (0, chai_1.expect)(bank.connect(owner).increaseBalanceAllowance(ZERO_ADDRESS, amount)).to.be.revertedWith("Can not approve");
355
+ });
356
+ });
357
+ context("when the spender had no approved balance before", () => {
358
+ let tx;
359
+ before(async () => {
360
+ await createSnapshot();
361
+ tx = await bank.connect(owner).increaseBalanceAllowance(spender, amount);
362
+ });
363
+ after(async () => {
364
+ await restoreSnapshot();
365
+ });
366
+ it("should approve the requested amount", async () => {
367
+ (0, chai_1.expect)(await bank.allowance(owner.address, spender)).to.equal(amount);
368
+ });
369
+ it("should emit the BalanceApproved event", async () => {
370
+ await (0, chai_1.expect)(tx)
371
+ .to.emit(bank, "BalanceApproved")
372
+ .withArgs(owner.address, spender, amount);
373
+ });
374
+ });
375
+ context("when the spender had an approved balance before", () => {
376
+ before(async () => {
377
+ await createSnapshot();
378
+ await bank.connect(owner).approveBalance(spender, to1e18(1337));
379
+ await bank.connect(owner).increaseBalanceAllowance(spender, amount);
380
+ });
381
+ after(async () => {
382
+ await restoreSnapshot();
383
+ });
384
+ it("should increase the previous allowance", async () => {
385
+ (0, chai_1.expect)(await bank.allowance(owner.address, spender)).to.equal(to1e18(1337).add(amount));
386
+ });
387
+ });
388
+ context("when the spender has a maximum allowance", () => {
389
+ before(async () => {
390
+ await createSnapshot();
391
+ await bank.connect(owner).approveBalance(spender, MAX_UINT256);
392
+ });
393
+ after(async () => {
394
+ await restoreSnapshot();
395
+ });
396
+ it("should revert", async () => {
397
+ await (0, chai_1.expect)(bank.connect(owner).increaseBalanceAllowance(spender, to1e18(1))).to.be.reverted;
398
+ });
399
+ });
400
+ });
401
+ describe("decreaseBalanceAllowance", () => {
402
+ const approvedAmount = to1e18(99);
403
+ let owner;
404
+ let spender;
405
+ before(async () => {
406
+ await createSnapshot();
407
+ const accounts = await (0, hardhat_1.getUnnamedAccounts)();
408
+ owner = await hardhat_1.ethers.getSigner(accounts[0]);
409
+ // eslint-disable-next-line prefer-destructuring
410
+ spender = accounts[1];
411
+ });
412
+ after(async () => {
413
+ await restoreSnapshot();
414
+ });
415
+ context("when the spender is the zero address", () => {
416
+ it("should revert", async () => {
417
+ await (0, chai_1.expect)(bank.connect(owner).decreaseBalanceAllowance(ZERO_ADDRESS, to1e18(1))).to.be.revertedWith("Can not decrease balance allowance below zero");
418
+ });
419
+ });
420
+ context("when the spender had no approved balance before", () => {
421
+ it("should revert", async () => {
422
+ await (0, chai_1.expect)(bank.connect(owner).decreaseBalanceAllowance(spender, to1e18(1))).to.be.revertedWith("Can not decrease balance allowance below zero");
423
+ });
424
+ });
425
+ context("when the spender had an approved balance before", () => {
426
+ const decreaseBy = to1e18(3);
427
+ before(async () => {
428
+ await createSnapshot();
429
+ await bank.connect(owner).approveBalance(spender, approvedAmount);
430
+ await bank.connect(owner).decreaseBalanceAllowance(spender, decreaseBy);
431
+ });
432
+ after(async () => {
433
+ await restoreSnapshot();
434
+ });
435
+ it("should decrease the previous allowance", async () => {
436
+ (0, chai_1.expect)(await bank.allowance(owner.address, spender)).to.equal(approvedAmount.sub(decreaseBy));
437
+ });
438
+ });
439
+ });
440
+ describe("transferBalanceFrom", () => {
441
+ const initialBalance = to1e18(500);
442
+ const approvedBalance = to1e18(45);
443
+ let owner;
444
+ let spender;
445
+ let recipient;
446
+ before(async () => {
447
+ await createSnapshot();
448
+ const accounts = await (0, hardhat_1.getUnnamedAccounts)();
449
+ owner = await hardhat_1.ethers.getSigner(accounts[0]);
450
+ spender = await hardhat_1.ethers.getSigner(accounts[1]);
451
+ // eslint-disable-next-line prefer-destructuring
452
+ recipient = accounts[2];
453
+ await bank.connect(bridge).increaseBalance(owner.address, initialBalance);
454
+ await bank.connect(owner).approveBalance(spender.address, approvedBalance);
455
+ });
456
+ after(async () => {
457
+ await restoreSnapshot();
458
+ });
459
+ context("when the recipient is the zero address", () => {
460
+ it("should revert", async () => {
461
+ await (0, chai_1.expect)(bank
462
+ .connect(spender)
463
+ .transferBalanceFrom(owner.address, ZERO_ADDRESS, approvedBalance)).to.be.revertedWith("Can not transfer to the zero address");
464
+ });
465
+ });
466
+ context("when the recipient is the bank address", () => {
467
+ it("should revert", async () => {
468
+ await (0, chai_1.expect)(bank
469
+ .connect(spender)
470
+ .transferBalanceFrom(owner.address, bank.address, approvedBalance)).to.be.revertedWith("Can not transfer to the Bank address");
471
+ });
472
+ });
473
+ context("when the spender has not enough balance approved", () => {
474
+ it("should revert", async () => {
475
+ await (0, chai_1.expect)(bank
476
+ .connect(spender)
477
+ .transferBalanceFrom(owner.address, recipient, approvedBalance.add(1))).to.be.revertedWith("Transfer amount exceeds allowance");
478
+ });
479
+ });
480
+ context("when the owner has not enough balance", () => {
481
+ const amount = initialBalance.add(1);
482
+ before(async () => {
483
+ await createSnapshot();
484
+ await bank.connect(owner).approveBalance(spender.address, amount);
485
+ });
486
+ after(async () => {
487
+ await restoreSnapshot();
488
+ });
489
+ it("should revert", async () => {
490
+ await (0, chai_1.expect)(bank
491
+ .connect(spender)
492
+ .transferBalanceFrom(owner.address, recipient, amount)).to.be.revertedWith("Transfer amount exceeds balance");
493
+ });
494
+ });
495
+ context("when the spender transfers part of the approved balance", () => {
496
+ const amount = to1e18(2);
497
+ let tx;
498
+ before(async () => {
499
+ await createSnapshot();
500
+ tx = await bank
501
+ .connect(spender)
502
+ .transferBalanceFrom(owner.address, recipient, amount);
503
+ });
504
+ after(async () => {
505
+ await restoreSnapshot();
506
+ });
507
+ it("should transfer the requested amount", async () => {
508
+ (0, chai_1.expect)(await bank.balanceOf(owner.address)).to.equal(initialBalance.sub(amount));
509
+ (0, chai_1.expect)(await bank.balanceOf(recipient)).to.equal(amount);
510
+ });
511
+ it("should emit the BalanceTransferred event", async () => {
512
+ await (0, chai_1.expect)(tx)
513
+ .to.emit(bank, "BalanceTransferred")
514
+ .withArgs(owner.address, recipient, amount);
515
+ });
516
+ it("should reduce the spender allowance", async () => {
517
+ (0, chai_1.expect)(await bank.allowance(owner.address, spender.address)).to.equal(approvedBalance.sub(amount));
518
+ });
519
+ });
520
+ context("when the spender transfers part of the approved balance in two transactions", () => {
521
+ const amount1 = to1e18(1);
522
+ const amount2 = to1e18(3);
523
+ let tx1;
524
+ let tx2;
525
+ before(async () => {
526
+ await createSnapshot();
527
+ tx1 = await bank
528
+ .connect(spender)
529
+ .transferBalanceFrom(owner.address, recipient, amount1);
530
+ tx2 = await bank
531
+ .connect(spender)
532
+ .transferBalanceFrom(owner.address, recipient, amount2);
533
+ });
534
+ after(async () => {
535
+ await restoreSnapshot();
536
+ });
537
+ it("should transfer the requested amount", async () => {
538
+ (0, chai_1.expect)(await bank.balanceOf(owner.address)).to.equal(initialBalance.sub(amount1).sub(amount2));
539
+ (0, chai_1.expect)(await bank.balanceOf(recipient)).to.equal(amount1.add(amount2));
540
+ });
541
+ it("should emit BalanceTransferred events", async () => {
542
+ await (0, chai_1.expect)(tx1)
543
+ .to.emit(bank, "BalanceTransferred")
544
+ .withArgs(owner.address, recipient, amount1);
545
+ await (0, chai_1.expect)(tx2)
546
+ .to.emit(bank, "BalanceTransferred")
547
+ .withArgs(owner.address, recipient, amount2);
548
+ });
549
+ it("should reduce the spender allowance", async () => {
550
+ (0, chai_1.expect)(await bank.allowance(owner.address, spender.address)).to.equal(approvedBalance.sub(amount1).sub(amount2));
551
+ });
552
+ });
553
+ context("when the spender transfers the entire approved balance", async () => {
554
+ const amount = approvedBalance;
555
+ before(async () => {
556
+ await createSnapshot();
557
+ await bank
558
+ .connect(spender)
559
+ .transferBalanceFrom(owner.address, recipient, amount);
560
+ });
561
+ after(async () => {
562
+ await restoreSnapshot();
563
+ });
564
+ it("should transfer the requested amount", async () => {
565
+ (0, chai_1.expect)(await bank.balanceOf(owner.address)).to.equal(initialBalance.sub(amount));
566
+ (0, chai_1.expect)(await bank.balanceOf(recipient)).to.equal(amount);
567
+ });
568
+ it("should reduce the spender allowance to zero", async () => {
569
+ (0, chai_1.expect)(await bank.allowance(owner.address, spender.address)).to.equal(0);
570
+ });
571
+ });
572
+ context("when the spender transfers the entire balance", async () => {
573
+ const amount = initialBalance;
574
+ before(async () => {
575
+ await createSnapshot();
576
+ await bank.connect(owner).approveBalance(spender.address, amount);
577
+ await bank
578
+ .connect(spender)
579
+ .transferBalanceFrom(owner.address, recipient, amount);
580
+ });
581
+ after(async () => {
582
+ await restoreSnapshot();
583
+ });
584
+ it("should transfer the requested amount", async () => {
585
+ (0, chai_1.expect)(await bank.balanceOf(owner.address)).to.equal(0);
586
+ (0, chai_1.expect)(await bank.balanceOf(recipient)).to.equal(amount);
587
+ });
588
+ it("should reduce the spender allowance to zero", async () => {
589
+ (0, chai_1.expect)(await bank.allowance(owner.address, spender.address)).to.equal(0);
590
+ });
591
+ });
592
+ context("when given the maximum allowance", () => {
593
+ const allowance = MAX_UINT256;
594
+ const amount = to1e18(21);
595
+ before(async () => {
596
+ await createSnapshot();
597
+ await bank.connect(owner).approveBalance(spender.address, allowance);
598
+ await bank
599
+ .connect(spender)
600
+ .transferBalanceFrom(owner.address, recipient, amount);
601
+ });
602
+ after(async () => {
603
+ await restoreSnapshot();
604
+ });
605
+ it("should not reduce the spender allowance", async () => {
606
+ (0, chai_1.expect)(await bank.allowance(owner.address, spender.address)).to.equal(allowance);
607
+ });
608
+ });
609
+ });
610
+ describe("permit", () => {
611
+ const initialBalance = to1e18(1231);
612
+ const permittedBalance = to1e18(45);
613
+ let owner;
614
+ let spender;
615
+ let yesterday;
616
+ let tomorrow;
617
+ before(async () => {
618
+ await createSnapshot();
619
+ owner = hardhat_1.ethers.Wallet.createRandom();
620
+ await bank.connect(bridge).increaseBalance(owner.address, initialBalance);
621
+ const accounts = await (0, hardhat_1.getUnnamedAccounts)();
622
+ // eslint-disable-next-line prefer-destructuring
623
+ spender = accounts[1];
624
+ const lastBlockTimestamp = await hardhat_1.helpers.time.lastBlockTime();
625
+ yesterday = lastBlockTimestamp - 86400; // -1 day
626
+ tomorrow = lastBlockTimestamp + 86400; // +1 day
627
+ });
628
+ after(async () => {
629
+ await restoreSnapshot();
630
+ });
631
+ const getApproval = async (amount, spenderAddress, deadline) => {
632
+ // We use ethers.utils.SigningKey for a Wallet instead of
633
+ // Signer.signMessage to do not add '\x19Ethereum Signed Message:\n'
634
+ // prefix to the signed message. The '\x19` protection (see EIP191 for
635
+ // more details on '\x19' rationale and format) is already included in
636
+ // EIP2612 permit signed message and '\x19Ethereum Signed Message:\n'
637
+ // should not be used there.
638
+ const signingKey = new hardhat_1.ethers.utils.SigningKey(owner.privateKey);
639
+ const domainSeparator = await bank.DOMAIN_SEPARATOR();
640
+ const permitTypehash = await bank.PERMIT_TYPEHASH();
641
+ const nonce = await bank.nonce(owner.address);
642
+ const approvalDigest = hardhat_1.ethers.utils.keccak256(hardhat_1.ethers.utils.solidityPack(["bytes1", "bytes1", "bytes32", "bytes32"], [
643
+ "0x19",
644
+ "0x01",
645
+ domainSeparator,
646
+ hardhat_1.ethers.utils.keccak256(hardhat_1.ethers.utils.defaultAbiCoder.encode([
647
+ "bytes32",
648
+ "address",
649
+ "address",
650
+ "uint256",
651
+ "uint256",
652
+ "uint256",
653
+ ], [
654
+ permitTypehash,
655
+ owner.address,
656
+ spenderAddress,
657
+ amount,
658
+ nonce,
659
+ deadline,
660
+ ])),
661
+ ]));
662
+ return hardhat_1.ethers.utils.splitSignature(signingKey.signDigest(approvalDigest));
663
+ };
664
+ context("when permission expired", () => {
665
+ it("should revert", async () => {
666
+ const deadline = yesterday;
667
+ const signature = await getApproval(permittedBalance, spender, deadline);
668
+ await (0, chai_1.expect)(bank
669
+ .connect(thirdParty)
670
+ .permit(owner.address, spender, permittedBalance, deadline, signature.v, signature.r, signature.s)).to.be.revertedWith("Permission expired");
671
+ });
672
+ });
673
+ context("when permission has an invalid signature", () => {
674
+ context("when owner does not match the permitting one", () => {
675
+ it("should revert", async () => {
676
+ const deadline = tomorrow;
677
+ const signature = await getApproval(permittedBalance, spender, deadline);
678
+ await (0, chai_1.expect)(bank.connect(thirdParty).permit(thirdParty.address, // does not match the signature
679
+ spender, permittedBalance, deadline, signature.v, signature.r, signature.s)).to.be.revertedWith("Invalid signature");
680
+ });
681
+ });
682
+ context("when spender does not match the signature", () => {
683
+ it("should revert", async () => {
684
+ const deadline = tomorrow;
685
+ const signature = await getApproval(permittedBalance, spender, deadline);
686
+ await (0, chai_1.expect)(bank.connect(thirdParty).permit(owner.address, thirdParty.address, // does not match the signature
687
+ permittedBalance, deadline, signature.v, signature.r, signature.s)).to.be.revertedWith("Invalid signature");
688
+ });
689
+ });
690
+ context("when permitted balance does not match the signature", () => {
691
+ it("should revert", async () => {
692
+ const deadline = tomorrow;
693
+ const signature = await getApproval(permittedBalance, spender, deadline);
694
+ await (0, chai_1.expect)(bank.connect(thirdParty).permit(owner.address, spender, permittedBalance.add(1), // does not match the signature
695
+ deadline, signature.v, signature.r, signature.s)).to.be.revertedWith("Invalid signature");
696
+ });
697
+ });
698
+ context("when permitted deadline does not match the signature", () => {
699
+ it("should revert", async () => {
700
+ const deadline = tomorrow;
701
+ const signature = await getApproval(permittedBalance, spender, deadline);
702
+ await (0, chai_1.expect)(bank.connect(thirdParty).permit(owner.address, spender, permittedBalance, deadline + 1, // does not match the signature
703
+ signature.v, signature.r, signature.s)).to.be.revertedWith("Invalid signature");
704
+ });
705
+ });
706
+ });
707
+ context("when the spender is the zero address", () => {
708
+ it("should revert", async () => {
709
+ const deadline = tomorrow;
710
+ const signature = await getApproval(permittedBalance, ZERO_ADDRESS, deadline);
711
+ await (0, chai_1.expect)(bank
712
+ .connect(thirdParty)
713
+ .permit(owner.address, ZERO_ADDRESS, permittedBalance, deadline, signature.v, signature.r, signature.s)).to.be.revertedWith("Can not approve to the zero address");
714
+ });
715
+ });
716
+ context("when the spender had no permitted balance before", () => {
717
+ let tx;
718
+ before(async () => {
719
+ await createSnapshot();
720
+ const deadline = tomorrow;
721
+ const signature = await getApproval(permittedBalance, spender, deadline);
722
+ tx = await bank
723
+ .connect(thirdParty)
724
+ .permit(owner.address, spender, permittedBalance, deadline, signature.v, signature.r, signature.s);
725
+ });
726
+ after(async () => {
727
+ await restoreSnapshot();
728
+ });
729
+ it("should approve the requested amount", async () => {
730
+ (0, chai_1.expect)(await bank.allowance(owner.address, spender)).to.equal(permittedBalance);
731
+ });
732
+ it("should emit the BalanceApproved event", async () => {
733
+ await (0, chai_1.expect)(tx)
734
+ .to.emit(bank, "BalanceApproved")
735
+ .withArgs(owner.address, spender, permittedBalance);
736
+ });
737
+ it("should increment the nonce for the permitting owner", async () => {
738
+ (0, chai_1.expect)(await bank.nonce(owner.address)).to.equal(1);
739
+ (0, chai_1.expect)(await bank.nonce(spender)).to.equal(0);
740
+ });
741
+ });
742
+ context("when the spender had a permitted balance before", () => {
743
+ let tx;
744
+ before(async () => {
745
+ await createSnapshot();
746
+ const deadline = tomorrow;
747
+ let signature = await getApproval(to1e18(1337), spender, deadline);
748
+ await bank
749
+ .connect(thirdParty)
750
+ .permit(owner.address, spender, to1e18(1337), deadline, signature.v, signature.r, signature.s);
751
+ signature = await getApproval(permittedBalance, spender, deadline);
752
+ tx = await bank
753
+ .connect(thirdParty)
754
+ .permit(owner.address, spender, permittedBalance, deadline, signature.v, signature.r, signature.s);
755
+ });
756
+ after(async () => {
757
+ await restoreSnapshot();
758
+ });
759
+ it("should replace the previous approval", async () => {
760
+ (0, chai_1.expect)(await bank.allowance(owner.address, spender)).to.equal(permittedBalance);
761
+ });
762
+ it("should emit the BalanceApproved event", async () => {
763
+ await (0, chai_1.expect)(tx)
764
+ .to.emit(bank, "BalanceApproved")
765
+ .withArgs(owner.address, spender, permittedBalance);
766
+ });
767
+ it("should increment the nonce for the permitting owner", async () => {
768
+ (0, chai_1.expect)(await bank.nonce(owner.address)).to.equal(2);
769
+ (0, chai_1.expect)(await bank.nonce(spender)).to.equal(0);
770
+ });
771
+ });
772
+ context("when given never expiring permit", () => {
773
+ const deadline = MAX_UINT256;
774
+ let signature;
775
+ before(async () => {
776
+ await createSnapshot();
777
+ signature = await getApproval(permittedBalance, spender, deadline);
778
+ });
779
+ after(async () => {
780
+ await restoreSnapshot();
781
+ });
782
+ it("should be accepted at any moment", async () => {
783
+ await hardhat_1.helpers.time.increaseTime(63113904); // +2 years
784
+ await bank
785
+ .connect(thirdParty)
786
+ .permit(owner.address, spender, permittedBalance, deadline, signature.v, signature.r, signature.s);
787
+ (0, chai_1.expect)(await bank.allowance(owner.address, spender)).to.equal(permittedBalance);
788
+ });
789
+ });
790
+ });
791
+ describe("increaseBalance", () => {
792
+ const amount = to1e18(10);
793
+ let recipient;
794
+ before(async () => {
795
+ await createSnapshot();
796
+ recipient = thirdParty.address;
797
+ });
798
+ after(async () => {
799
+ await restoreSnapshot();
800
+ });
801
+ context("when called by a third party", () => {
802
+ it("should revert", async () => {
803
+ await (0, chai_1.expect)(bank.connect(thirdParty).increaseBalance(recipient, amount)).to.be.revertedWith("Caller is not the bridge");
804
+ });
805
+ });
806
+ context("when called by the bridge", () => {
807
+ context("when increasing balance for the Bank", () => {
808
+ it("should revert", async () => {
809
+ await (0, chai_1.expect)(bank.connect(bridge).increaseBalance(bank.address, amount)).to.be.revertedWith("Can not increase balance for Bank");
810
+ });
811
+ });
812
+ context("when called for a valid recipient", () => {
813
+ let tx;
814
+ before(async () => {
815
+ await createSnapshot();
816
+ tx = await bank.connect(bridge).increaseBalance(recipient, amount);
817
+ });
818
+ after(async () => {
819
+ await restoreSnapshot();
820
+ });
821
+ it("should increase recipient's balance", async () => {
822
+ (0, chai_1.expect)(await bank.balanceOf(recipient)).to.equal(amount);
823
+ });
824
+ it("should emit the BalanceIncreased event", async () => {
825
+ await (0, chai_1.expect)(tx)
826
+ .to.emit(bank, "BalanceIncreased")
827
+ .withArgs(recipient, amount);
828
+ });
829
+ });
830
+ });
831
+ });
832
+ describe("increaseBalances", () => {
833
+ const amount1 = to1e18(12);
834
+ const amount2 = to1e18(15);
835
+ const amount3 = to1e18(17);
836
+ let recipient1;
837
+ let recipient2;
838
+ let recipient3;
839
+ before(async () => {
840
+ await createSnapshot();
841
+ [recipient1, recipient2, recipient3] = await (0, hardhat_1.getUnnamedAccounts)();
842
+ });
843
+ after(async () => {
844
+ await restoreSnapshot();
845
+ });
846
+ context("when called by a third party", () => {
847
+ it("should revert", async () => {
848
+ await (0, chai_1.expect)(bank
849
+ .connect(thirdParty)
850
+ .increaseBalances([recipient1, recipient2, recipient3], [amount1, amount2, amount3])).to.be.revertedWith("Caller is not the bridge");
851
+ });
852
+ });
853
+ context("when called by the bridge", () => {
854
+ context("when increasing balance for the bank", () => {
855
+ it("should revert", async () => {
856
+ await (0, chai_1.expect)(bank
857
+ .connect(bridge)
858
+ .increaseBalances([recipient1, bank.address, recipient3], [amount1, amount2, amount3])).to.be.revertedWith("Can not increase balance for Bank");
859
+ });
860
+ });
861
+ context("when there is more recipients than amounts", () => {
862
+ it("should revert", async () => {
863
+ await (0, chai_1.expect)(bank
864
+ .connect(bridge)
865
+ .increaseBalances([recipient1, recipient2], [amount1])).to.be.revertedWith("Arrays must have the same length");
866
+ });
867
+ });
868
+ context("when there is more amounts than recipients", () => {
869
+ it("should revert", async () => {
870
+ await (0, chai_1.expect)(bank
871
+ .connect(bridge)
872
+ .increaseBalances([recipient1, recipient2], [amount1, amount2, amount3])).to.be.revertedWith("Arrays must have the same length");
873
+ });
874
+ });
875
+ context("when called for a valid recipient", () => {
876
+ let tx;
877
+ before(async () => {
878
+ await createSnapshot();
879
+ tx = await bank
880
+ .connect(bridge)
881
+ .increaseBalances([recipient1, recipient2, recipient3], [amount1, amount2, amount3]);
882
+ });
883
+ after(async () => {
884
+ await restoreSnapshot();
885
+ });
886
+ it("should increase recipients' balances", async () => {
887
+ (0, chai_1.expect)(await bank.balanceOf(recipient1)).to.equal(amount1);
888
+ (0, chai_1.expect)(await bank.balanceOf(recipient2)).to.equal(amount2);
889
+ (0, chai_1.expect)(await bank.balanceOf(recipient3)).to.equal(amount3);
890
+ });
891
+ it("should emit BalanceIncreased events", async () => {
892
+ await (0, chai_1.expect)(tx)
893
+ .to.emit(bank, "BalanceIncreased")
894
+ .withArgs(recipient1, amount1);
895
+ await (0, chai_1.expect)(tx)
896
+ .to.emit(bank, "BalanceIncreased")
897
+ .withArgs(recipient2, amount2);
898
+ await (0, chai_1.expect)(tx)
899
+ .to.emit(bank, "BalanceIncreased")
900
+ .withArgs(recipient3, amount3);
901
+ });
902
+ });
903
+ });
904
+ });
905
+ describe("increaseBalanceAndCall", () => {
906
+ const depositor1 = "0x30c371E0651B2Ff6062158ca1D95b07C7531c719";
907
+ const depositor2 = "0xb3464806d680722dBc678996F1670D19A42eA3e9";
908
+ const depositedAmount1 = to1e18(19);
909
+ const depositedAmount2 = to1e18(11);
910
+ const totalDepositedAmount = to1e18(30); // 19 + 11
911
+ let vault;
912
+ let tbtc;
913
+ before(async () => {
914
+ await createSnapshot();
915
+ const TBTC = await hardhat_1.ethers.getContractFactory("TBTC");
916
+ tbtc = await TBTC.deploy();
917
+ await tbtc.deployed();
918
+ const Vault = await hardhat_1.ethers.getContractFactory("TBTCVault");
919
+ vault = await Vault.deploy(bank.address, tbtc.address);
920
+ await vault.deployed();
921
+ await tbtc.connect(deployer).transferOwnership(vault.address);
922
+ });
923
+ after(async () => {
924
+ await restoreSnapshot();
925
+ });
926
+ context("when called by a third party", () => {
927
+ it("should revert", async () => {
928
+ await (0, chai_1.expect)(bank
929
+ .connect(thirdParty)
930
+ .increaseBalanceAndCall(vault.address, [depositor1, depositor2], [depositedAmount1, depositedAmount2])).to.be.revertedWith("Caller is not the bridge");
931
+ });
932
+ });
933
+ context("when called by the bridge", () => {
934
+ let tx;
935
+ before(async () => {
936
+ await createSnapshot();
937
+ tx = await bank
938
+ .connect(bridge)
939
+ .increaseBalanceAndCall(vault.address, [depositor1, depositor2], [depositedAmount1, depositedAmount2]);
940
+ });
941
+ after(async () => {
942
+ await restoreSnapshot();
943
+ });
944
+ context("when depositors array has greater length than deposited amounts array", () => {
945
+ it("should revert", async () => {
946
+ await (0, chai_1.expect)(bank
947
+ .connect(bridge)
948
+ .increaseBalanceAndCall(vault.address, [depositor1, depositor2], [depositedAmount1])).to.be.revertedWith("Arrays must have the same length");
949
+ });
950
+ });
951
+ context("when deposited amounts array has greater length than depositors array", () => {
952
+ it("should revert", async () => {
953
+ await (0, chai_1.expect)(bank
954
+ .connect(bridge)
955
+ .increaseBalanceAndCall(vault.address, [depositor1], [depositedAmount1, depositedAmount2])).to.be.revertedWith("Arrays must have the same length");
956
+ });
957
+ });
958
+ it("should increase vault's balance", async () => {
959
+ (0, chai_1.expect)(await bank.balanceOf(vault.address)).to.equal(totalDepositedAmount);
960
+ });
961
+ it("should emit BalanceIncreased event", async () => {
962
+ await (0, chai_1.expect)(tx)
963
+ .to.emit(bank, "BalanceIncreased")
964
+ .withArgs(vault.address, totalDepositedAmount);
965
+ });
966
+ it("should call the vault", async () => {
967
+ (0, chai_1.expect)(await tbtc.balanceOf(depositor1)).to.equal(depositedAmount1);
968
+ (0, chai_1.expect)(await tbtc.balanceOf(depositor2)).to.equal(depositedAmount2);
969
+ (0, chai_1.expect)(await tbtc.totalSupply()).to.equal(totalDepositedAmount);
970
+ });
971
+ });
972
+ });
973
+ describe("decreaseBalance", () => {
974
+ const initialBalance = to1e18(21);
975
+ const amount = to1e18(10);
976
+ let tx;
977
+ before(async () => {
978
+ await createSnapshot();
979
+ // first increase so that there is something to decrease from
980
+ await bank
981
+ .connect(bridge)
982
+ .increaseBalance(thirdParty.address, initialBalance);
983
+ tx = await bank.connect(thirdParty).decreaseBalance(amount);
984
+ });
985
+ after(async () => {
986
+ await restoreSnapshot();
987
+ });
988
+ it("should decrease caller's balance", async () => {
989
+ (0, chai_1.expect)(await bank.balanceOf(thirdParty.address)).to.equal(initialBalance.sub(amount));
990
+ });
991
+ it("should emit the BalanceDecreased event", async () => {
992
+ await (0, chai_1.expect)(tx)
993
+ .to.emit(bank, "BalanceDecreased")
994
+ .withArgs(thirdParty.address, amount);
995
+ });
996
+ });
997
+ describe("DOMAIN_SEPARATOR", () => {
998
+ it("should be keccak256 of EIP712 domain struct", async () => {
999
+ const { keccak256 } = hardhat_1.ethers.utils;
1000
+ const { defaultAbiCoder } = hardhat_1.ethers.utils;
1001
+ const { toUtf8Bytes } = hardhat_1.ethers.utils;
1002
+ const expected = keccak256(defaultAbiCoder.encode(["bytes32", "bytes32", "bytes32", "uint256", "address"], [
1003
+ keccak256(toUtf8Bytes("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")),
1004
+ keccak256(toUtf8Bytes("TBTC Bank")),
1005
+ keccak256(toUtf8Bytes("1")),
1006
+ hardhatNetworkId,
1007
+ bank.address,
1008
+ ]));
1009
+ (0, chai_1.expect)(await bank.DOMAIN_SEPARATOR()).to.equal(expected);
1010
+ });
1011
+ });
1012
+ });