@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.
- package/README.adoc +12 -0
- package/artifacts/.chainId +1 -1
- package/artifacts/Bank.json +807 -0
- package/artifacts/Bridge.json +2300 -0
- package/artifacts/Deposit.json +117 -0
- package/artifacts/DepositSweep.json +77 -0
- package/artifacts/EcdsaDkgValidator.json +532 -0
- package/artifacts/EcdsaInactivity.json +156 -0
- package/artifacts/EcdsaSortitionPool.json +1004 -0
- package/artifacts/Fraud.json +164 -0
- package/artifacts/KeepRegistry.json +99 -0
- package/artifacts/KeepStake.json +286 -0
- package/artifacts/KeepToken.json +711 -0
- package/artifacts/KeepTokenStaking.json +483 -0
- package/artifacts/MovingFunds.json +249 -0
- package/artifacts/NuCypherStakingEscrow.json +256 -0
- package/artifacts/NuCypherToken.json +711 -0
- package/artifacts/RandomBeaconStub.json +141 -0
- package/artifacts/Redemption.json +174 -0
- package/artifacts/ReimbursementPool.json +509 -0
- package/artifacts/Relay.json +123 -0
- package/artifacts/T.json +1148 -0
- package/artifacts/TBTC.json +36 -35
- package/artifacts/TBTCToken.json +738 -0
- package/artifacts/TBTCVault.json +691 -0
- package/artifacts/TokenStaking.json +2288 -0
- package/artifacts/TokenholderGovernor.json +1795 -0
- package/artifacts/TokenholderTimelock.json +1058 -0
- package/artifacts/VendingMachine.json +34 -33
- package/artifacts/VendingMachineKeep.json +400 -0
- package/artifacts/VendingMachineNuCypher.json +400 -0
- package/artifacts/WalletRegistry.json +1843 -0
- package/artifacts/WalletRegistryGovernance.json +2754 -0
- package/artifacts/Wallets.json +186 -0
- package/artifacts/solcInputs/5e62cff1ead0900b07facca4b559e818.json +314 -0
- package/build/contracts/GovernanceUtils.sol/GovernanceUtils.dbg.json +1 -1
- package/build/contracts/GovernanceUtils.sol/GovernanceUtils.json +2 -2
- package/build/contracts/bank/Bank.sol/Bank.dbg.json +4 -0
- package/build/contracts/bank/Bank.sol/Bank.json +542 -0
- package/build/contracts/bank/IReceiveBalanceApproval.sol/IReceiveBalanceApproval.dbg.json +4 -0
- package/build/contracts/bank/IReceiveBalanceApproval.sol/IReceiveBalanceApproval.json +34 -0
- package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.dbg.json +4 -0
- package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.json +10 -0
- package/build/contracts/bridge/Bridge.sol/Bridge.dbg.json +4 -0
- package/build/contracts/bridge/Bridge.sol/Bridge.json +2686 -0
- package/build/contracts/bridge/BridgeState.sol/BridgeState.dbg.json +4 -0
- package/build/contracts/bridge/BridgeState.sol/BridgeState.json +226 -0
- package/build/contracts/bridge/Deposit.sol/Deposit.dbg.json +4 -0
- package/build/contracts/bridge/Deposit.sol/Deposit.json +72 -0
- package/build/contracts/bridge/DepositSweep.sol/DepositSweep.dbg.json +4 -0
- package/build/contracts/bridge/DepositSweep.sol/DepositSweep.json +30 -0
- package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.dbg.json +4 -0
- package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.json +10 -0
- package/build/contracts/bridge/Fraud.sol/Fraud.dbg.json +4 -0
- package/build/contracts/bridge/Fraud.sol/Fraud.json +86 -0
- package/build/contracts/bridge/Heartbeat.sol/Heartbeat.dbg.json +4 -0
- package/build/contracts/bridge/Heartbeat.sol/Heartbeat.json +10 -0
- package/build/contracts/bridge/IRelay.sol/IRelay.dbg.json +4 -0
- package/build/contracts/bridge/IRelay.sol/IRelay.json +37 -0
- package/build/contracts/bridge/MovingFunds.sol/MovingFunds.dbg.json +4 -0
- package/build/contracts/bridge/MovingFunds.sol/MovingFunds.json +138 -0
- package/build/contracts/bridge/Redemption.sol/OutboundTx.dbg.json +4 -0
- package/build/contracts/bridge/Redemption.sol/OutboundTx.json +10 -0
- package/build/contracts/bridge/Redemption.sol/Redemption.dbg.json +4 -0
- package/build/contracts/bridge/Redemption.sol/Redemption.json +92 -0
- package/build/contracts/bridge/VendingMachine.sol/VendingMachine.dbg.json +1 -1
- package/build/contracts/bridge/VendingMachine.sol/VendingMachine.json +2 -2
- package/build/contracts/bridge/Wallets.sol/Wallets.dbg.json +4 -0
- package/build/contracts/bridge/Wallets.sol/Wallets.json +112 -0
- package/build/contracts/token/TBTC.sol/TBTC.dbg.json +1 -1
- package/build/contracts/token/TBTC.sol/TBTC.json +4 -4
- package/build/contracts/vault/DonationVault.sol/DonationVault.dbg.json +4 -0
- package/build/contracts/vault/DonationVault.sol/DonationVault.json +108 -0
- package/build/contracts/vault/IVault.sol/IVault.dbg.json +4 -0
- package/build/contracts/vault/IVault.sol/IVault.json +52 -0
- package/build/contracts/vault/TBTCVault.sol/TBTCVault.dbg.json +4 -0
- package/build/contracts/vault/TBTCVault.sol/TBTCVault.json +449 -0
- package/contracts/GovernanceUtils.sol +4 -4
- package/contracts/bank/Bank.sol +436 -0
- package/contracts/bank/IReceiveBalanceApproval.sol +45 -0
- package/contracts/bridge/BitcoinTx.sol +326 -0
- package/contracts/bridge/Bridge.sol +1793 -0
- package/contracts/bridge/BridgeState.sol +739 -0
- package/contracts/bridge/Deposit.sol +269 -0
- package/contracts/bridge/DepositSweep.sol +574 -0
- package/contracts/bridge/EcdsaLib.sol +45 -0
- package/contracts/bridge/Fraud.sol +579 -0
- package/contracts/bridge/Heartbeat.sol +112 -0
- package/contracts/bridge/IRelay.sol +28 -0
- package/contracts/bridge/MovingFunds.sol +1077 -0
- package/contracts/bridge/Redemption.sol +1020 -0
- package/contracts/bridge/VendingMachine.sol +2 -2
- package/contracts/bridge/Wallets.sol +719 -0
- package/contracts/hardhat-dependency-compiler/.hardhat-dependency-compiler +1 -0
- package/contracts/hardhat-dependency-compiler/@keep-network/ecdsa/contracts/WalletRegistry.sol +3 -0
- package/contracts/hardhat-dependency-compiler/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol +3 -0
- package/contracts/hardhat-dependency-compiler/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol +3 -0
- package/contracts/token/TBTC.sol +1 -1
- package/contracts/vault/DonationVault.sol +125 -0
- package/contracts/vault/IVault.sol +44 -0
- package/contracts/vault/TBTCVault.sol +305 -0
- package/deploy/00_resolve_relay.ts +28 -0
- package/deploy/00_resolve_tbtc_v1_token.ts +1 -1
- package/deploy/01_deploy_tbtc_v2_token.ts +8 -1
- package/deploy/02_deploy_vending_machine.ts +7 -0
- package/deploy/{03_transfer_roles.ts → 03_transfer_vending_machine_roles.ts} +1 -1
- package/deploy/04_deploy_bank.ts +27 -0
- package/deploy/05_deploy_bridge.ts +80 -0
- package/deploy/06_deploy_tbtc_vault.ts +30 -0
- package/deploy/07_bank_update_bridge.ts +19 -0
- package/deploy/08_transfer_bank_ownership.ts +15 -0
- package/deploy/09_transfer_tbtc_vault_ownership.ts +15 -0
- package/deploy/10_transfer_bridge_governance.ts +20 -0
- package/deploy/11_initialize_wallet_owner.ts +18 -0
- package/deploy/11_transfer_proxy_admin_ownership.ts +30 -0
- package/deploy/12_deploy_proxy_admin_with_deputy.ts +33 -0
- package/export/deploy/00_resolve_relay.js +24 -0
- package/export/deploy/00_resolve_tbtc_v1_token.js +24 -0
- package/export/deploy/01_deploy_tbtc_v2_token.js +19 -0
- package/export/deploy/02_deploy_vending_machine.js +25 -0
- package/export/deploy/03_transfer_vending_machine_roles.js +19 -0
- package/export/deploy/04_deploy_bank.js +21 -0
- package/export/deploy/05_deploy_bridge.js +69 -0
- package/export/deploy/06_deploy_tbtc_vault.js +24 -0
- package/export/deploy/07_bank_update_bridge.js +13 -0
- package/export/deploy/08_transfer_bank_ownership.js +11 -0
- package/export/deploy/09_transfer_tbtc_vault_ownership.js +11 -0
- package/export/deploy/10_transfer_bridge_governance.js +11 -0
- package/export/deploy/11_initialize_wallet_owner.js +14 -0
- package/export/deploy/11_transfer_proxy_admin_ownership.js +23 -0
- package/export/deploy/12_deploy_proxy_admin_with_deputy.js +22 -0
- package/export/hardhat.config.js +169 -0
- package/export/test/bank/Bank.test.js +1012 -0
- package/export/test/bridge/Bridge.Deployment.test.js +76 -0
- package/export/test/bridge/Bridge.Deposit.test.js +1834 -0
- package/export/test/bridge/Bridge.Frauds.test.js +1349 -0
- package/export/test/bridge/Bridge.MovingFunds.test.js +2437 -0
- package/export/test/bridge/Bridge.Parameters.test.js +400 -0
- package/export/test/bridge/Bridge.Redemption.test.js +2523 -0
- package/export/test/bridge/Bridge.Vaults.test.js +74 -0
- package/export/test/bridge/Bridge.Wallets.test.js +1017 -0
- package/export/test/bridge/EcdsaLib.test.js +46 -0
- package/export/test/bridge/Heartbeat.test.js +77 -0
- package/export/test/bridge/VendingMachine.Upgrade.test.js +160 -0
- package/export/test/bridge/VendingMachine.test.js +762 -0
- package/export/test/data/deposit-sweep.js +655 -0
- package/export/test/data/ecdsa.js +18 -0
- package/export/test/data/fraud.js +158 -0
- package/export/test/data/moving-funds.js +815 -0
- package/export/test/data/redemption.js +1011 -0
- package/export/test/fixtures/bridge.js +54 -0
- package/export/test/fixtures/index.js +57 -0
- package/export/test/helpers/contract-test-helpers.js +18 -0
- package/export/test/integration/Slashing.test.js +279 -0
- package/export/test/integration/WalleCreation.test.js +66 -0
- package/export/test/integration/utils/ecdsa-wallet-registry.js +137 -0
- package/export/test/integration/utils/fixture.js +77 -0
- package/export/test/integration/utils/gas.js +36 -0
- package/export/test/integration/utils/random-beacon.js +26 -0
- package/export/test/integration/utils/staking.js +19 -0
- package/export/test/vault/DonationVault.test.js +202 -0
- package/export/test/vault/TBTCVault.Redemption.test.js +357 -0
- package/export/test/vault/TBTCVault.test.js +768 -0
- package/export/typechain/BTCUtils.js +2 -0
- package/export/typechain/Bank.js +2 -0
- package/export/typechain/BankStub.js +2 -0
- package/export/typechain/Bridge.js +2 -0
- package/export/typechain/BridgeState.js +2 -0
- package/export/typechain/BridgeStub.js +2 -0
- package/export/typechain/Deposit.js +2 -0
- package/export/typechain/DepositSweep.js +2 -0
- package/export/typechain/DonationVault.js +2 -0
- package/export/typechain/ERC165.js +2 -0
- package/export/typechain/ERC1967Proxy.js +2 -0
- package/export/typechain/ERC1967Upgrade.js +2 -0
- package/export/typechain/ERC20WithPermit.js +2 -0
- package/export/typechain/ERC721.js +2 -0
- package/export/typechain/EcdsaAuthorization.js +2 -0
- package/export/typechain/EcdsaDkg.js +2 -0
- package/export/typechain/EcdsaDkgValidator.js +2 -0
- package/export/typechain/EcdsaInactivity.js +2 -0
- package/export/typechain/Fraud.js +2 -0
- package/export/typechain/Governable.js +2 -0
- package/export/typechain/HeartbeatStub.js +2 -0
- package/export/typechain/IApplication.js +2 -0
- package/export/typechain/IApproveAndCall.js +2 -0
- package/export/typechain/IBeacon.js +2 -0
- package/export/typechain/IERC165.js +2 -0
- package/export/typechain/IERC1822Proxiable.js +2 -0
- package/export/typechain/IERC20.js +2 -0
- package/export/typechain/IERC20Metadata.js +2 -0
- package/export/typechain/IERC20WithPermit.js +2 -0
- package/export/typechain/IERC721.js +2 -0
- package/export/typechain/IERC721Metadata.js +2 -0
- package/export/typechain/IERC721Receiver.js +2 -0
- package/export/typechain/IRandomBeacon.js +2 -0
- package/export/typechain/IRandomBeaconConsumer.js +2 -0
- package/export/typechain/IReceiveApproval.js +2 -0
- package/export/typechain/IReceiveBalanceApproval.js +2 -0
- package/export/typechain/IRelay.js +2 -0
- package/export/typechain/IStaking.js +2 -0
- package/export/typechain/IVault.js +2 -0
- package/export/typechain/IWalletOwner.js +2 -0
- package/export/typechain/IWalletRegistry.js +2 -0
- package/export/typechain/Initializable.js +2 -0
- package/export/typechain/MisfundRecovery.js +2 -0
- package/export/typechain/MovingFunds.js +2 -0
- package/export/typechain/Ownable.js +2 -0
- package/export/typechain/Proxy.js +2 -0
- package/export/typechain/ProxyAdmin.js +2 -0
- package/export/typechain/ReceiveApprovalStub.js +2 -0
- package/export/typechain/Redemption.js +2 -0
- package/export/typechain/Reimbursable.js +2 -0
- package/export/typechain/ReimbursementPool.js +2 -0
- package/export/typechain/Rewards.js +2 -0
- package/export/typechain/SortitionPool.js +2 -0
- package/export/typechain/SortitionTree.js +2 -0
- package/export/typechain/TBTC.js +2 -0
- package/export/typechain/TBTCVault.js +2 -0
- package/export/typechain/TestERC20.js +2 -0
- package/export/typechain/TestERC721.js +2 -0
- package/export/typechain/TestEcdsaLib.js +2 -0
- package/export/typechain/TestRelay.js +2 -0
- package/export/typechain/TransparentUpgradeableProxy.js +2 -0
- package/export/typechain/VendingMachine.js +2 -0
- package/export/typechain/WalletRegistry.js +2 -0
- package/export/typechain/Wallets.js +2 -0
- package/export/typechain/common.js +2 -0
- package/export/typechain/factories/BTCUtils__factory.js +94 -0
- package/export/typechain/factories/BankStub__factory.js +586 -0
- package/export/typechain/factories/Bank__factory.js +573 -0
- package/export/typechain/factories/BridgeState__factory.js +257 -0
- package/export/typechain/factories/BridgeStub__factory.js +2912 -0
- package/export/typechain/factories/Bridge__factory.js +2526 -0
- package/export/typechain/factories/DepositSweep__factory.js +61 -0
- package/export/typechain/factories/Deposit__factory.js +103 -0
- package/export/typechain/factories/DonationVault__factory.js +139 -0
- package/export/typechain/factories/ERC165__factory.js +38 -0
- package/export/typechain/factories/ERC1967Proxy__factory.js +111 -0
- package/export/typechain/factories/ERC1967Upgrade__factory.js +64 -0
- package/export/typechain/factories/ERC20WithPermit__factory.js +524 -0
- package/export/typechain/factories/ERC721__factory.js +388 -0
- package/export/typechain/factories/EcdsaAuthorization__factory.js +211 -0
- package/export/typechain/factories/EcdsaDkgValidator__factory.js +441 -0
- package/export/typechain/factories/EcdsaDkg__factory.js +192 -0
- package/export/typechain/factories/EcdsaInactivity__factory.js +134 -0
- package/export/typechain/factories/Fraud__factory.js +117 -0
- package/export/typechain/factories/Governable__factory.js +64 -0
- package/export/typechain/factories/HeartbeatStub__factory.js +61 -0
- package/export/typechain/factories/IApplication__factory.js +152 -0
- package/export/typechain/factories/IApproveAndCall__factory.js +48 -0
- package/export/typechain/factories/IBeacon__factory.js +32 -0
- package/export/typechain/factories/IERC165__factory.js +38 -0
- package/export/typechain/factories/IERC1822Proxiable__factory.js +32 -0
- package/export/typechain/factories/IERC20Metadata__factory.js +241 -0
- package/export/typechain/factories/IERC20WithPermit__factory.js +389 -0
- package/export/typechain/factories/IERC20__factory.js +202 -0
- package/export/typechain/factories/IERC721Metadata__factory.js +349 -0
- package/export/typechain/factories/IERC721Receiver__factory.js +53 -0
- package/export/typechain/factories/IERC721__factory.js +304 -0
- package/export/typechain/factories/IRandomBeaconConsumer__factory.js +37 -0
- package/export/typechain/factories/IRandomBeacon__factory.js +32 -0
- package/export/typechain/factories/IReceiveApproval__factory.js +47 -0
- package/export/typechain/factories/IReceiveBalanceApproval__factory.js +42 -0
- package/export/typechain/factories/IRelay__factory.js +45 -0
- package/export/typechain/factories/IStaking__factory.js +722 -0
- package/export/typechain/factories/IVault__factory.js +60 -0
- package/export/typechain/factories/IWalletOwner__factory.js +65 -0
- package/export/typechain/factories/IWalletRegistry__factory.js +138 -0
- package/export/typechain/factories/Initializable__factory.js +32 -0
- package/export/typechain/factories/MisfundRecovery__factory.js +145 -0
- package/export/typechain/factories/MovingFunds__factory.js +169 -0
- package/export/typechain/factories/Ownable__factory.js +71 -0
- package/export/typechain/factories/ProxyAdmin__factory.js +191 -0
- package/export/typechain/factories/Proxy__factory.js +27 -0
- package/export/typechain/factories/ReceiveApprovalStub__factory.js +127 -0
- package/export/typechain/factories/Redemption__factory.js +123 -0
- package/export/typechain/factories/Reimbursable__factory.js +58 -0
- package/export/typechain/factories/ReimbursementPool__factory.js +350 -0
- package/export/typechain/factories/Rewards__factory.js +117 -0
- package/export/typechain/factories/SortitionPool__factory.js +610 -0
- package/export/typechain/factories/SortitionTree__factory.js +149 -0
- package/export/typechain/factories/TBTCVault__factory.js +480 -0
- package/export/typechain/factories/TBTC__factory.js +564 -0
- package/export/typechain/factories/TestERC20__factory.js +539 -0
- package/export/typechain/factories/TestERC721__factory.js +421 -0
- package/export/typechain/factories/TestEcdsaLib__factory.js +66 -0
- package/export/typechain/factories/TestRelay__factory.js +94 -0
- package/export/typechain/factories/TransparentUpgradeableProxy__factory.js +186 -0
- package/export/typechain/factories/VendingMachine__factory.js +549 -0
- package/export/typechain/factories/WalletRegistry__factory.js +1919 -0
- package/export/typechain/factories/Wallets__factory.js +143 -0
- package/export/typechain/index.js +132 -0
- package/export.json +15932 -503
- package/package.json +47 -26
- 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
|
+
}
|