@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,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const hardhat_1 = require("hardhat");
4
+ const smock_1 = require("@defi-wonderland/smock");
5
+ /**
6
+ * Common fixture for tests suites targeting the Bridge contract.
7
+ */
8
+ async function bridgeFixture() {
9
+ await hardhat_1.deployments.fixture();
10
+ const { deployer, governance, treasury } = await hardhat_1.helpers.signers.getNamedSigners();
11
+ const [thirdParty] = await hardhat_1.helpers.signers.getUnnamedSigners();
12
+ const tbtc = await hardhat_1.helpers.contracts.getContract("TBTC");
13
+ const vendingMachine = await hardhat_1.helpers.contracts.getContract("VendingMachine");
14
+ const tbtcVault = await hardhat_1.helpers.contracts.getContract("TBTCVault");
15
+ const bank = await hardhat_1.helpers.contracts.getContract("Bank");
16
+ const bridge = await hardhat_1.helpers.contracts.getContract("Bridge");
17
+ const walletRegistry = await smock_1.smock.fake("IWalletRegistry", {
18
+ address: await (await bridge.contractReferences()).ecdsaWalletRegistry,
19
+ });
20
+ // Fund the `walletRegistry` account so it's possible to mock sending requests
21
+ // from it.
22
+ await deployer.sendTransaction({
23
+ to: walletRegistry.address,
24
+ value: hardhat_1.ethers.utils.parseEther("1"),
25
+ });
26
+ const relay = await smock_1.smock.fake("TestRelay", {
27
+ address: await (await bridge.contractReferences()).relay,
28
+ });
29
+ await bank.connect(governance).updateBridge(bridge.address);
30
+ const BridgeFactory = await hardhat_1.ethers.getContractFactory("BridgeStub", {
31
+ libraries: {
32
+ Deposit: (await hardhat_1.helpers.contracts.getContract("Deposit")).address,
33
+ DepositSweep: (await hardhat_1.helpers.contracts.getContract("DepositSweep")).address,
34
+ Redemption: (await hardhat_1.helpers.contracts.getContract("Redemption")).address,
35
+ Wallets: (await hardhat_1.helpers.contracts.getContract("Wallets")).address,
36
+ Fraud: (await hardhat_1.helpers.contracts.getContract("Fraud")).address,
37
+ MovingFunds: (await hardhat_1.helpers.contracts.getContract("MovingFunds")).address,
38
+ },
39
+ });
40
+ return {
41
+ governance,
42
+ thirdParty,
43
+ treasury,
44
+ tbtc,
45
+ vendingMachine,
46
+ tbtcVault,
47
+ bank,
48
+ relay,
49
+ walletRegistry,
50
+ bridge,
51
+ BridgeFactory,
52
+ };
53
+ }
54
+ exports.default = bridgeFixture;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.movedFundsSweepRequestState = exports.ecdsaDkgState = exports.walletState = exports.constants = void 0;
4
+ const contract_test_helpers_1 = require("../helpers/contract-test-helpers");
5
+ exports.constants = {
6
+ unmintFee: (0, contract_test_helpers_1.to1ePrecision)(1, 15),
7
+ depositDustThreshold: 1000000,
8
+ depositTreasuryFeeDivisor: 2000,
9
+ depositTxMaxFee: 10000,
10
+ redemptionDustThreshold: 1000000,
11
+ redemptionTreasuryFeeDivisor: 2000,
12
+ redemptionTxMaxFee: 10000,
13
+ redemptionTimeout: 172800,
14
+ redemptionTimeoutSlashingAmount: (0, contract_test_helpers_1.to1ePrecision)(10000, 18),
15
+ redemptionTimeoutNotifierRewardMultiplier: 100,
16
+ movingFundsTxMaxTotalFee: 10000,
17
+ movingFundsDustThreshold: 20000,
18
+ movingFundsTimeoutResetDelay: 518400,
19
+ movingFundsTimeout: 604800,
20
+ movingFundsTimeoutSlashingAmount: (0, contract_test_helpers_1.to1ePrecision)(10000, 18),
21
+ movingFundsTimeoutNotifierRewardMultiplier: 100,
22
+ movedFundsSweepTxMaxTotalFee: 10000,
23
+ movedFundsSweepTimeout: 604800,
24
+ movedFundsSweepTimeoutSlashingAmount: (0, contract_test_helpers_1.to1ePrecision)(10000, 18),
25
+ movedFundsSweepTimeoutNotifierRewardMultiplier: 100,
26
+ walletCreationPeriod: 604800,
27
+ walletCreationMinBtcBalance: (0, contract_test_helpers_1.to1ePrecision)(1, 8),
28
+ walletCreationMaxBtcBalance: (0, contract_test_helpers_1.to1ePrecision)(100, 8),
29
+ walletClosureMinBtcBalance: (0, contract_test_helpers_1.to1ePrecision)(5, 7),
30
+ walletMaxAge: 8 * 604800,
31
+ walletMaxBtcTransfer: (0, contract_test_helpers_1.to1ePrecision)(10, 8),
32
+ walletClosingPeriod: 3456000,
33
+ fraudChallengeDepositAmount: (0, contract_test_helpers_1.to1ePrecision)(2, 18),
34
+ fraudChallengeDefeatTimeout: 604800,
35
+ fraudSlashingAmount: (0, contract_test_helpers_1.to1ePrecision)(10000, 18),
36
+ fraudNotifierRewardMultiplier: 100, // 100%
37
+ };
38
+ exports.walletState = {
39
+ Unknown: 0,
40
+ Live: 1,
41
+ MovingFunds: 2,
42
+ Closing: 3,
43
+ Closed: 4,
44
+ Terminated: 5,
45
+ };
46
+ exports.ecdsaDkgState = {
47
+ IDLE: 0,
48
+ AWAITING_SEED: 1,
49
+ AWAITING_RESULT: 2,
50
+ CHALLENGE: 3,
51
+ };
52
+ exports.movedFundsSweepRequestState = {
53
+ Unknown: 0,
54
+ Pending: 1,
55
+ Processed: 2,
56
+ TimedOut: 3,
57
+ };
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getBlockTime = exports.to1e18 = exports.to1ePrecision = void 0;
4
+ const hardhat_1 = require("hardhat");
5
+ function to1ePrecision(n, precision) {
6
+ const decimalMultiplier = hardhat_1.ethers.BigNumber.from(10).pow(precision);
7
+ return hardhat_1.ethers.BigNumber.from(n).mul(decimalMultiplier);
8
+ }
9
+ exports.to1ePrecision = to1ePrecision;
10
+ function to1e18(n) {
11
+ const decimalMultiplier = hardhat_1.ethers.BigNumber.from(10).pow(18);
12
+ return hardhat_1.ethers.BigNumber.from(n).mul(decimalMultiplier);
13
+ }
14
+ exports.to1e18 = to1e18;
15
+ async function getBlockTime(blockNumber) {
16
+ return (await hardhat_1.ethers.provider.getBlock(blockNumber)).timestamp;
17
+ }
18
+ exports.getBlockTime = getBlockTime;
@@ -0,0 +1,279 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /* eslint-disable no-await-in-loop */
4
+ /* eslint-disable @typescript-eslint/no-extra-semi */
5
+ const hardhat_1 = require("hardhat");
6
+ const chai_1 = require("chai");
7
+ const ecdsa_wallet_registry_1 = require("./utils/ecdsa-wallet-registry");
8
+ const random_beacon_1 = require("./utils/random-beacon");
9
+ const gas_1 = require("./utils/gas");
10
+ const fixture_1 = require("./utils/fixture");
11
+ const fraud_1 = require("../data/fraud");
12
+ const fixtures_1 = require("../fixtures");
13
+ const deposit_sweep_1 = require("../data/deposit-sweep");
14
+ const { increaseTime } = hardhat_1.helpers.time;
15
+ const { createSnapshot, restoreSnapshot } = hardhat_1.helpers.snapshot;
16
+ const describeFn = process.env.NODE_ENV === "integration-test" ? describe : describe.skip;
17
+ describeFn("Integration Test - Slashing", async () => {
18
+ let tbtc;
19
+ let bridge;
20
+ let tbtcVault;
21
+ let staking;
22
+ let walletRegistry;
23
+ let randomBeacon;
24
+ let relay;
25
+ let deployer;
26
+ let governance;
27
+ let thirdParty;
28
+ const dkgResultChallengePeriodLength = 10;
29
+ before(async () => {
30
+ ;
31
+ ({
32
+ deployer,
33
+ governance,
34
+ tbtc,
35
+ bridge,
36
+ tbtcVault,
37
+ staking,
38
+ walletRegistry,
39
+ relay,
40
+ randomBeacon,
41
+ } = await hardhat_1.waffle.loadFixture(fixture_1.fixture));
42
+ [thirdParty] = await hardhat_1.helpers.signers.getUnnamedSigners();
43
+ // Update only the parameters that are crucial for this test.
44
+ await (0, ecdsa_wallet_registry_1.updateWalletRegistryDkgResultChallengePeriodLength)(walletRegistry, governance, dkgResultChallengePeriodLength);
45
+ });
46
+ describe("notifyFraudChallengeDefeatTimeout", async () => {
47
+ before(async () => {
48
+ await createSnapshot();
49
+ });
50
+ after(async () => {
51
+ await restoreSnapshot();
52
+ });
53
+ describe("when wallet is created", async () => {
54
+ const { publicKey: walletPublicKey, ecdsaWalletID, pubKeyHash160: walletPubKeyHash160, } = fraud_1.wallet;
55
+ let walletMembers;
56
+ before("create a wallet", async () => {
57
+ (0, chai_1.expect)(await bridge.activeWalletPubKeyHash()).to.be.equal(hardhat_1.ethers.constants.AddressZero);
58
+ const requestNewWalletTx = await bridge.requestNewWallet(deposit_sweep_1.NO_MAIN_UTXO);
59
+ await (0, random_beacon_1.produceRelayEntry)(walletRegistry, randomBeacon);
60
+ ({ walletMembers } = await (0, ecdsa_wallet_registry_1.performEcdsaDkg)(walletRegistry, walletPublicKey, requestNewWalletTx.blockNumber));
61
+ });
62
+ describe("when a fraud is reported", async () => {
63
+ const fraudulentBtcTx = fraud_1.nonWitnessSignSingleInputTx;
64
+ let notifyFraudChallengeDefeatTimeoutTx;
65
+ before(async () => {
66
+ const { fraudChallengeDepositAmount, fraudChallengeDefeatTimeout } = await bridge.fraudParameters();
67
+ await bridge
68
+ .connect(thirdParty)
69
+ .submitFraudChallenge(walletPublicKey, fraudulentBtcTx.preimageSha256, fraudulentBtcTx.signature, {
70
+ value: fraudChallengeDepositAmount,
71
+ });
72
+ await increaseTime(fraudChallengeDefeatTimeout);
73
+ notifyFraudChallengeDefeatTimeoutTx = await bridge
74
+ .connect(thirdParty)
75
+ .notifyFraudChallengeDefeatTimeout(walletPublicKey, walletMembers.getIds(), fraudulentBtcTx.preimageSha256);
76
+ });
77
+ it("should slash wallet members", async () => {
78
+ const { fraudSlashingAmount: amountToSlash } = await bridge.fraudParameters();
79
+ (0, chai_1.expect)(await staking.getSlashingQueueLength()).to.equal(walletMembers.length);
80
+ for (let i = 0; i < walletMembers.length; i++) {
81
+ const slashing = await staking.slashingQueue(i);
82
+ (0, chai_1.expect)(slashing.amount).to.equal(amountToSlash, `unexpected slashing amount for ${i}`);
83
+ (0, chai_1.expect)(slashing.stakingProvider).to.equal(walletMembers[i].stakingProvider, `unexpected staking provider for ${i}`);
84
+ }
85
+ });
86
+ it("should close the wallet in the wallet registry", async () => {
87
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
88
+ (0, chai_1.expect)(await walletRegistry.isWalletRegistered(ecdsaWalletID)).to.be
89
+ .false;
90
+ });
91
+ it("should terminate the wallet in the bridge", async () => {
92
+ const storedWallet = await bridge.wallets(walletPubKeyHash160);
93
+ (0, chai_1.expect)(storedWallet.state).to.be.equal(fixtures_1.walletState.Terminated);
94
+ });
95
+ it("should consume around 3 100 000 gas for Bridge.notifyMovingFundsTimeoutTx transaction", async () => {
96
+ await (0, gas_1.assertGasUsed)(notifyFraudChallengeDefeatTimeoutTx, 3150000, 100000);
97
+ });
98
+ });
99
+ });
100
+ });
101
+ describe("notifyRedemptionTimeout", async () => {
102
+ before(async () => {
103
+ await createSnapshot();
104
+ });
105
+ after(async () => {
106
+ await restoreSnapshot();
107
+ });
108
+ describe("when wallet is created", async () => {
109
+ const deposit = deposit_sweep_1.SingleP2SHDeposit.deposits[0];
110
+ const { walletPubKeyHash: walletPubKeyHash160 } = deposit.reveal;
111
+ const { walletPublicKey, walletID: ecdsaWalletID } = deposit.ecdsaWallet;
112
+ let walletMembers;
113
+ let redeemerOutputScript;
114
+ before(async () => {
115
+ const requestNewWalletTx = await bridge.requestNewWallet(deposit_sweep_1.NO_MAIN_UTXO);
116
+ await (0, random_beacon_1.produceRelayEntry)(walletRegistry, randomBeacon);
117
+ ({ walletMembers } = await (0, ecdsa_wallet_registry_1.performEcdsaDkg)(walletRegistry, walletPublicKey, requestNewWalletTx.blockNumber));
118
+ const { fundingTx, reveal } = deposit_sweep_1.SingleP2SHDeposit.deposits[0];
119
+ reveal.vault = tbtcVault.address;
120
+ // We use a deposit funding bitcoin transaction with a very low amount,
121
+ // so we need to update the dust and redemption thresholds to be below it.
122
+ await updateDepositDustThreshold(10000); // 0.0001 BTC
123
+ await updateRedemptionDustThreshold(2000); // 0.00002 BTC
124
+ // Reveal and sweep the deposit to set up a positive Bank balance for
125
+ // the redeemer, to be able to request a redemption.
126
+ await bridge.revealDeposit(fundingTx, reveal);
127
+ relay.getCurrentEpochDifficulty.returns(deposit_sweep_1.SingleP2SHDeposit.chainDifficulty);
128
+ relay.getPrevEpochDifficulty.returns(deposit_sweep_1.SingleP2SHDeposit.chainDifficulty);
129
+ await bridge.submitDepositSweepProof(deposit_sweep_1.SingleP2SHDeposit.sweepTx, deposit_sweep_1.SingleP2SHDeposit.sweepProof, deposit_sweep_1.SingleP2SHDeposit.mainUtxo, tbtcVault.address);
130
+ const newMainUtxo = {
131
+ txHash: deposit_sweep_1.SingleP2SHDeposit.sweepTx.hash,
132
+ txOutputIndex: 0,
133
+ txOutputValue: 18500, // Value obtained from SingleP2SHDeposit.sweepTx.outputVector
134
+ };
135
+ // Request redemption
136
+ const redeemer = await hardhat_1.helpers.account.impersonateAccount(deposit.reveal.depositor, { from: deployer });
137
+ const redemptionAmount = 3000;
138
+ redeemerOutputScript =
139
+ "0x17a91486884e6be1525dab5ae0b451bd2c72cee67dcf4187";
140
+ // Request redemption via TBTC Vault.
141
+ await tbtc
142
+ .connect(redeemer)
143
+ .approveAndCall(tbtcVault.address, redemptionAmount, hardhat_1.ethers.utils.defaultAbiCoder.encode(["address", "bytes20", "bytes32", "uint32", "uint64", "bytes"], [
144
+ redeemer.address,
145
+ walletPubKeyHash160,
146
+ newMainUtxo.txHash,
147
+ newMainUtxo.txOutputIndex,
148
+ newMainUtxo.txOutputValue,
149
+ redeemerOutputScript,
150
+ ]));
151
+ // Confirm the wallet is still in Live state.
152
+ (0, chai_1.expect)((await await bridge.wallets(walletPubKeyHash160)).state).to.be.equal(fixtures_1.walletState.Live);
153
+ });
154
+ describe("when a redemption timeout is reported", async () => {
155
+ let notifyRedemptionTimeoutTx;
156
+ before(async () => {
157
+ const { redemptionTimeout } = await bridge.redemptionParameters();
158
+ await hardhat_1.helpers.time.increaseTime(redemptionTimeout);
159
+ notifyRedemptionTimeoutTx = await bridge
160
+ .connect(thirdParty)
161
+ .notifyRedemptionTimeout(walletPubKeyHash160, walletMembers.getIds(), redeemerOutputScript);
162
+ });
163
+ it("should slash wallet members", async () => {
164
+ const { redemptionTimeoutSlashingAmount: amountToSlash } = await bridge.redemptionParameters();
165
+ (0, chai_1.expect)(await staking.getSlashingQueueLength()).to.equal(walletMembers.length);
166
+ for (let i = 0; i < walletMembers.length; i++) {
167
+ const slashing = await staking.slashingQueue(i);
168
+ (0, chai_1.expect)(slashing.amount).to.equal(amountToSlash, `unexpected slashing amount for ${i}`);
169
+ (0, chai_1.expect)(slashing.stakingProvider).to.equal(walletMembers[i].stakingProvider, `unexpected staking provider for ${i}`);
170
+ }
171
+ });
172
+ it("should not close the wallet in the wallet registry", async () => {
173
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
174
+ (0, chai_1.expect)(await walletRegistry.isWalletRegistered(ecdsaWalletID)).to.be
175
+ .true;
176
+ });
177
+ // Since the wallet's balance was above 0, it switched to MovingFunds state.
178
+ it("should transition the wallet in the bridge to the MovingFunds state", async () => {
179
+ const storedWallet = await bridge.wallets(walletPubKeyHash160);
180
+ (0, chai_1.expect)(storedWallet.state).to.be.equal(fixtures_1.walletState.MovingFunds);
181
+ });
182
+ it("should consume around 3 150 000 gas for Bridge.notifyRedemptionTimeout transaction", async () => {
183
+ await (0, gas_1.assertGasUsed)(notifyRedemptionTimeoutTx, 3150000, 100000);
184
+ });
185
+ });
186
+ });
187
+ });
188
+ describe("notifyMovingFundsTimeout", async () => {
189
+ before(async () => {
190
+ await createSnapshot();
191
+ });
192
+ after(async () => {
193
+ await restoreSnapshot();
194
+ });
195
+ describe("when wallet is created", async () => {
196
+ const deposit = deposit_sweep_1.SingleP2SHDeposit.deposits[0];
197
+ const walletPubKeyHash160 = deposit.reveal.walletPubKeyHash;
198
+ const { walletPublicKey, walletID: ecdsaWalletID } = deposit.ecdsaWallet;
199
+ let walletMembers;
200
+ before(async () => {
201
+ const requestNewWalletTx = await bridge.requestNewWallet(deposit_sweep_1.NO_MAIN_UTXO);
202
+ await (0, random_beacon_1.produceRelayEntry)(walletRegistry, randomBeacon);
203
+ ({ walletMembers } = await (0, ecdsa_wallet_registry_1.performEcdsaDkg)(walletRegistry, walletPublicKey, requestNewWalletTx.blockNumber));
204
+ const { fundingTx, reveal } = deposit_sweep_1.SingleP2SHDeposit.deposits[0];
205
+ reveal.vault = tbtcVault.address;
206
+ // We use a deposit funding bitcoin transaction with a very low amount,
207
+ // so we need to update the dust threshold to be below it.
208
+ await updateDepositDustThreshold(10000); // 0.0001 BTC)
209
+ // Reveal and sweep the deposit to set up a main UTXO for the wallet,
210
+ // so when operator inactivity is reported the wallet is transferred to
211
+ // the MovingFunds instead of the Closing state.
212
+ await bridge.revealDeposit(fundingTx, reveal);
213
+ relay.getCurrentEpochDifficulty.returns(deposit_sweep_1.SingleP2SHDeposit.chainDifficulty);
214
+ relay.getPrevEpochDifficulty.returns(deposit_sweep_1.SingleP2SHDeposit.chainDifficulty);
215
+ await bridge.submitDepositSweepProof(deposit_sweep_1.SingleP2SHDeposit.sweepTx, deposit_sweep_1.SingleP2SHDeposit.sweepProof, deposit_sweep_1.SingleP2SHDeposit.mainUtxo, tbtcVault.address);
216
+ // Switch the wallet to moving funds state by reporting wallet members
217
+ // inactivity.
218
+ const nonce = 0;
219
+ const walletMembersIDs = walletMembers.getIds();
220
+ const inactiveMembersIndices = [26, 40, 63, 78, 89];
221
+ const claim = await (0, ecdsa_wallet_registry_1.produceOperatorInactivityClaim)(ecdsaWalletID, walletMembers, nonce, walletPublicKey, true, inactiveMembersIndices, walletMembers.length / 2 + 1);
222
+ await walletRegistry
223
+ .connect(walletMembers[0].signer)
224
+ .notifyOperatorInactivity(claim, nonce, walletMembersIDs);
225
+ });
226
+ describe("when moving funds timeout is reported", async () => {
227
+ let notifyMovingFundsTimeoutTx;
228
+ before(async () => {
229
+ (0, chai_1.expect)(await (await bridge.wallets(walletPubKeyHash160)).state).to.be.equal(fixtures_1.walletState.MovingFunds);
230
+ const { movingFundsTimeout } = await bridge.movingFundsParameters();
231
+ await hardhat_1.helpers.time.increaseTime(movingFundsTimeout);
232
+ notifyMovingFundsTimeoutTx = await bridge
233
+ .connect(thirdParty)
234
+ .notifyMovingFundsTimeout(walletPubKeyHash160, walletMembers.getIds());
235
+ });
236
+ it("should slash wallet members", async () => {
237
+ const { movingFundsTimeoutSlashingAmount: amountToSlash } = await bridge.movingFundsParameters();
238
+ (0, chai_1.expect)(await staking.getSlashingQueueLength()).to.equal(walletMembers.length);
239
+ for (let i = 0; i < walletMembers.length; i++) {
240
+ const slashing = await staking.slashingQueue(i);
241
+ (0, chai_1.expect)(slashing.amount).to.equal(amountToSlash, `unexpected slashing amount for ${i}`);
242
+ (0, chai_1.expect)(slashing.stakingProvider).to.equal(walletMembers[i].stakingProvider, `unexpected staking provider for ${i}`);
243
+ }
244
+ });
245
+ it("should close the wallet in the wallet registry", async () => {
246
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
247
+ (0, chai_1.expect)(await walletRegistry.isWalletRegistered(ecdsaWalletID)).to.be
248
+ .false;
249
+ });
250
+ it("should terminate the wallet in the bridge", async () => {
251
+ const storedWallet = await bridge.wallets(walletPubKeyHash160);
252
+ (0, chai_1.expect)(storedWallet.state).to.be.equal(fixtures_1.walletState.Terminated);
253
+ });
254
+ it("should consume around 3 100 000 gas for Bridge.notifyMovingFundsTimeoutTx transaction", async () => {
255
+ await (0, gas_1.assertGasUsed)(notifyMovingFundsTimeoutTx, 3100000, 50000);
256
+ });
257
+ });
258
+ });
259
+ });
260
+ async function updateDepositDustThreshold(newDepositDustThreshold) {
261
+ const currentDepositParameters = await bridge.depositParameters();
262
+ await bridge
263
+ .connect(governance)
264
+ .updateDepositParameters(newDepositDustThreshold, currentDepositParameters.depositTreasuryFeeDivisor, currentDepositParameters.depositTxMaxFee);
265
+ }
266
+ async function updateRedemptionDustThreshold(newRedemptionDustThreshold) {
267
+ // Redemption dust threshold has to be greater than moving funds dust threshold,
268
+ // so first we need to align the moving funds dust threshold.
269
+ const newMovingFundsDustThreshold = newRedemptionDustThreshold - 1;
270
+ const currentMovingFundsParameters = await bridge.movingFundsParameters();
271
+ await bridge
272
+ .connect(governance)
273
+ .updateMovingFundsParameters(currentMovingFundsParameters.movingFundsTxMaxTotalFee, newMovingFundsDustThreshold, currentMovingFundsParameters.movingFundsTimeoutResetDelay, currentMovingFundsParameters.movingFundsTimeout, currentMovingFundsParameters.movingFundsTimeoutSlashingAmount, currentMovingFundsParameters.movingFundsTimeoutNotifierRewardMultiplier, currentMovingFundsParameters.movedFundsSweepTxMaxTotalFee, currentMovingFundsParameters.movedFundsSweepTimeout, currentMovingFundsParameters.movedFundsSweepTimeoutSlashingAmount, currentMovingFundsParameters.movedFundsSweepTimeoutNotifierRewardMultiplier);
274
+ const currentRedemptionParameters = await bridge.redemptionParameters();
275
+ await bridge
276
+ .connect(governance)
277
+ .updateRedemptionParameters(newRedemptionDustThreshold, currentRedemptionParameters.redemptionTreasuryFeeDivisor, currentRedemptionParameters.redemptionTxMaxFee, currentRedemptionParameters.redemptionTimeout, currentRedemptionParameters.redemptionTimeoutSlashingAmount, currentRedemptionParameters.redemptionTimeoutNotifierRewardMultiplier);
278
+ }
279
+ });
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /* eslint-disable @typescript-eslint/no-extra-semi */
4
+ const hardhat_1 = require("hardhat");
5
+ const chai_1 = require("chai");
6
+ const ecdsa_wallet_registry_1 = require("./utils/ecdsa-wallet-registry");
7
+ const ecdsa_1 = require("../data/ecdsa");
8
+ const random_beacon_1 = require("./utils/random-beacon");
9
+ const gas_1 = require("./utils/gas");
10
+ const fixture_1 = require("./utils/fixture");
11
+ const fixtures_1 = require("../fixtures");
12
+ const NO_MAIN_UTXO = {
13
+ txHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
14
+ txOutputIndex: 0,
15
+ txOutputValue: 0,
16
+ };
17
+ const describeFn = process.env.NODE_ENV === "integration-test" ? describe : describe.skip;
18
+ describeFn("Integration Test - Wallet Creation", async () => {
19
+ let bridge;
20
+ let walletRegistry;
21
+ let randomBeacon;
22
+ let governance;
23
+ const dkgResultChallengePeriodLength = 10;
24
+ // TODO: Generate a random public key
25
+ const walletPublicKey = ecdsa_1.ecdsaWalletTestData.publicKey;
26
+ const { walletID } = ecdsa_1.ecdsaWalletTestData;
27
+ const walletPubKeyHash = ecdsa_1.ecdsaWalletTestData.pubKeyHash160;
28
+ before(async () => {
29
+ ;
30
+ ({ governance, bridge, walletRegistry, randomBeacon } =
31
+ await hardhat_1.waffle.loadFixture(fixture_1.fixture));
32
+ // Update only the parameters that are crucial for this test.
33
+ await (0, ecdsa_wallet_registry_1.updateWalletRegistryDkgResultChallengePeriodLength)(walletRegistry, governance, dkgResultChallengePeriodLength);
34
+ });
35
+ describe("new wallet creation (happy path)", async () => {
36
+ let requestNewWalletTx;
37
+ let walletRegistrationTx;
38
+ before(async () => {
39
+ (0, chai_1.expect)(await bridge.activeWalletPubKeyHash()).to.be.equal(hardhat_1.ethers.constants.AddressZero);
40
+ requestNewWalletTx = await bridge.requestNewWallet(NO_MAIN_UTXO);
41
+ const startBlock = requestNewWalletTx.blockNumber;
42
+ await (0, random_beacon_1.produceRelayEntry)(walletRegistry, randomBeacon);
43
+ ({ approveDkgResultTx: walletRegistrationTx } = await (0, ecdsa_wallet_registry_1.performEcdsaDkg)(walletRegistry, walletPublicKey, startBlock));
44
+ await walletRegistrationTx.wait();
45
+ });
46
+ it("should register a new wallet in the WalletRegistry", async () => {
47
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
48
+ (0, chai_1.expect)(await walletRegistry.isWalletRegistered(walletID)).to.be.true;
49
+ });
50
+ it("should register a new wallet details in the Bridge", async () => {
51
+ const storedWallet = await bridge.wallets(walletPubKeyHash);
52
+ (0, chai_1.expect)(storedWallet.ecdsaWalletID).to.be.equal(ecdsa_1.ecdsaWalletTestData.walletID);
53
+ (0, chai_1.expect)(storedWallet.state).to.be.equal(fixtures_1.walletState.Live);
54
+ (0, chai_1.expect)(storedWallet.createdAt).to.be.equal((await hardhat_1.ethers.provider.getBlock((await walletRegistrationTx.wait()).blockNumber)).timestamp);
55
+ });
56
+ it("should register a new wallet as active in the Bridge", async () => {
57
+ (0, chai_1.expect)(await bridge.activeWalletPubKeyHash()).to.be.equal(walletPubKeyHash);
58
+ });
59
+ it("should consume around 93 000 gas for Bridge.requestNewWallet transaction", async () => {
60
+ await (0, gas_1.assertGasUsed)(requestNewWalletTx, 93000);
61
+ });
62
+ it("should consume around 339 000 gas for WalletRegistry.approveDkgResult transaction", async () => {
63
+ await (0, gas_1.assertGasUsed)(walletRegistrationTx, 339000);
64
+ });
65
+ });
66
+ });
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ // TODO: Utils in this file are pulled from @keep-network/ecdsa test utils.
3
+ // We should consider exposing them in @keep-network/ecdsa for an external usage.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.Operators = exports.produceOperatorInactivityClaim = exports.updateWalletRegistryDkgResultChallengePeriodLength = exports.performEcdsaDkg = exports.registerOperator = void 0;
6
+ /* eslint-disable no-await-in-loop */
7
+ const hardhat_1 = require("hardhat");
8
+ async function registerOperator(walletRegistry, sortitionPool, stakingProvider, operator) {
9
+ await walletRegistry
10
+ .connect(stakingProvider)
11
+ .registerOperator(await operator.getAddress());
12
+ await walletRegistry.connect(operator).joinSortitionPool();
13
+ const operatorID = await sortitionPool.getOperatorID(await operator.getAddress());
14
+ return operatorID;
15
+ }
16
+ exports.registerOperator = registerOperator;
17
+ async function performEcdsaDkg(walletRegistry, groupPublicKey, startBlock) {
18
+ const { signers: walletMembers, dkgResult, submitter, submitDkgResultTx: dkgResultSubmissionTx, } = await signAndSubmitDkgResult(walletRegistry, groupPublicKey, startBlock);
19
+ await hardhat_1.helpers.time.mineBlocksTo(dkgResultSubmissionTx.blockNumber +
20
+ (await walletRegistry.dkgParameters()).resultChallengePeriodLength.toNumber());
21
+ const approveDkgResultTx = await walletRegistry
22
+ .connect(submitter)
23
+ .approveDkgResult(dkgResult);
24
+ return { approveDkgResultTx, walletMembers };
25
+ }
26
+ exports.performEcdsaDkg = performEcdsaDkg;
27
+ async function updateWalletRegistryDkgResultChallengePeriodLength(walletRegistry, governance, dkgResultChallengePeriodLength) {
28
+ const walletRegistryGovernance = await hardhat_1.ethers.getContractAt((await hardhat_1.deployments.getArtifact("WalletRegistryGovernance")).abi, await walletRegistry.governance());
29
+ await walletRegistryGovernance
30
+ .connect(governance)
31
+ .beginDkgResultChallengePeriodLengthUpdate(dkgResultChallengePeriodLength);
32
+ await hardhat_1.helpers.time.increaseTime(await walletRegistryGovernance.governanceDelay());
33
+ await walletRegistryGovernance
34
+ .connect(governance)
35
+ .finalizeDkgResultChallengePeriodLengthUpdate();
36
+ }
37
+ exports.updateWalletRegistryDkgResultChallengePeriodLength = updateWalletRegistryDkgResultChallengePeriodLength;
38
+ async function selectGroup(walletRegistry) {
39
+ const sortitionPool = (await hardhat_1.ethers.getContractAt("SortitionPool", await walletRegistry.sortitionPool()));
40
+ const identifiers = await walletRegistry.selectGroup();
41
+ const addresses = await sortitionPool.getIDOperators(identifiers);
42
+ return new Operators(...(await Promise.all(identifiers.map(async (identifier, i) => ({
43
+ id: identifier,
44
+ signer: await hardhat_1.ethers.getSigner(addresses[i]),
45
+ stakingProvider: await walletRegistry.operatorToStakingProvider(addresses[i]),
46
+ })))));
47
+ }
48
+ async function produceOperatorInactivityClaim(walletID, signers, nonce, groupPubKey, heartbeatFailed, inactiveMembersIndices, numberOfSignatures) {
49
+ const messageHash = hardhat_1.ethers.utils.solidityKeccak256(["uint256", "bytes", "uint8[]", "bool"], [nonce, groupPubKey, inactiveMembersIndices, heartbeatFailed]);
50
+ const signingMembersIndices = [];
51
+ const signatures = [];
52
+ for (let i = 0; i < signers.length; i++) {
53
+ if (signatures.length === numberOfSignatures) {
54
+ // eslint-disable-next-line no-continue
55
+ continue;
56
+ }
57
+ const signerIndex = i + 1;
58
+ signingMembersIndices.push(signerIndex);
59
+ const signature = await signers[i].signer.signMessage(hardhat_1.ethers.utils.arrayify(messageHash));
60
+ signatures.push(signature);
61
+ }
62
+ return {
63
+ walletID,
64
+ inactiveMembersIndices,
65
+ heartbeatFailed,
66
+ signatures: hardhat_1.ethers.utils.hexConcat(signatures),
67
+ signingMembersIndices,
68
+ };
69
+ }
70
+ exports.produceOperatorInactivityClaim = produceOperatorInactivityClaim;
71
+ class Operators extends Array {
72
+ getIds() {
73
+ return this.map((operator) => operator.id);
74
+ }
75
+ getSigners() {
76
+ return this.map((operator) => operator.signer);
77
+ }
78
+ }
79
+ exports.Operators = Operators;
80
+ const noMisbehaved = [];
81
+ async function signAndSubmitDkgResult(walletRegistry, groupPublicKey, startBlock, misbehavedIndices = noMisbehaved) {
82
+ const signers = await selectGroup(walletRegistry);
83
+ const submitterIndex = 1;
84
+ const { dkgResult } = await signDkgResult(signers, groupPublicKey, misbehavedIndices, startBlock, submitterIndex);
85
+ const submitter = signers[submitterIndex - 1].signer;
86
+ const submitDkgResultTx = await walletRegistry
87
+ .connect(submitter)
88
+ .submitDkgResult(dkgResult);
89
+ return {
90
+ signers,
91
+ dkgResult,
92
+ submitter,
93
+ submitDkgResultTx,
94
+ };
95
+ }
96
+ async function signDkgResult(signers, groupPublicKey, misbehavedMembersIndices, startBlock, submitterIndex) {
97
+ const numberOfSignatures = signers.length / 2 + 1;
98
+ const resultHash = hardhat_1.ethers.utils.solidityKeccak256(["bytes", "uint8[]", "uint256"], [groupPublicKey, misbehavedMembersIndices, startBlock]);
99
+ const members = [];
100
+ const signingMembersIndices = [];
101
+ const signatures = [];
102
+ for (let i = 0; i < signers.length; i++) {
103
+ const { id, signer: ethersSigner } = signers[i];
104
+ members.push(id);
105
+ if (signatures.length === numberOfSignatures) {
106
+ // eslint-disable-next-line no-continue
107
+ continue;
108
+ }
109
+ const signerIndex = i + 1;
110
+ signingMembersIndices.push(signerIndex);
111
+ const signature = await ethersSigner.signMessage(hardhat_1.ethers.utils.arrayify(resultHash));
112
+ signatures.push(signature);
113
+ }
114
+ const signaturesBytes = hardhat_1.ethers.utils.hexConcat(signatures);
115
+ const dkgResult = {
116
+ submitterMemberIndex: submitterIndex,
117
+ groupPubKey: groupPublicKey,
118
+ misbehavedMembersIndices,
119
+ signatures: signaturesBytes,
120
+ signingMembersIndices,
121
+ members,
122
+ membersHash: hashDKGMembers(members, misbehavedMembersIndices),
123
+ };
124
+ return { dkgResult, signingMembersIndices, signaturesBytes };
125
+ }
126
+ function hashDKGMembers(members, misbehavedMembersIndices) {
127
+ if (misbehavedMembersIndices && misbehavedMembersIndices.length > 0) {
128
+ const activeDkgMembers = [...members];
129
+ for (let i = 0; i < misbehavedMembersIndices.length; i++) {
130
+ if (misbehavedMembersIndices[i] !== 0) {
131
+ activeDkgMembers.splice(misbehavedMembersIndices[i] - i - 1, 1);
132
+ }
133
+ }
134
+ return hardhat_1.ethers.utils.keccak256(hardhat_1.ethers.utils.defaultAbiCoder.encode(["uint32[]"], [activeDkgMembers]));
135
+ }
136
+ return hardhat_1.ethers.utils.keccak256(hardhat_1.ethers.utils.defaultAbiCoder.encode(["uint32[]"], [members]));
137
+ }