@keep-network/tbtc-v2 0.1.1-dev.6 → 0.1.1-dev.62

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 (101) hide show
  1. package/README.adoc +12 -0
  2. package/artifacts/Bank.json +752 -0
  3. package/artifacts/Bridge.json +3962 -0
  4. package/artifacts/Deposit.json +117 -0
  5. package/artifacts/DepositSweep.json +76 -0
  6. package/artifacts/EcdsaDkgValidator.json +532 -0
  7. package/artifacts/EcdsaInactivity.json +156 -0
  8. package/artifacts/Fraud.json +154 -0
  9. package/artifacts/KeepRegistry.json +99 -0
  10. package/artifacts/KeepStake.json +286 -0
  11. package/artifacts/KeepToken.json +711 -0
  12. package/artifacts/KeepTokenStaking.json +483 -0
  13. package/artifacts/MovingFunds.json +227 -0
  14. package/artifacts/NuCypherStakingEscrow.json +256 -0
  15. package/artifacts/NuCypherToken.json +711 -0
  16. package/artifacts/RandomBeaconStub.json +141 -0
  17. package/artifacts/Redemption.json +162 -0
  18. package/artifacts/ReimbursementPool.json +509 -0
  19. package/artifacts/Relay.json +123 -0
  20. package/artifacts/SortitionPool.json +944 -0
  21. package/artifacts/T.json +1148 -0
  22. package/artifacts/TBTC.json +27 -26
  23. package/artifacts/TBTCToken.json +27 -26
  24. package/artifacts/TokenStaking.json +2288 -0
  25. package/artifacts/TokenholderGovernor.json +1795 -0
  26. package/artifacts/TokenholderTimelock.json +1058 -0
  27. package/artifacts/VendingMachine.json +30 -29
  28. package/artifacts/VendingMachineKeep.json +400 -0
  29. package/artifacts/VendingMachineNuCypher.json +400 -0
  30. package/artifacts/WalletRegistry.json +2709 -0
  31. package/artifacts/WalletRegistryGovernance.json +2364 -0
  32. package/artifacts/Wallets.json +186 -0
  33. package/artifacts/solcInputs/05c98d94f96a77da7702c7818a8cadac.json +227 -0
  34. package/build/contracts/GovernanceUtils.sol/GovernanceUtils.dbg.json +1 -1
  35. package/build/contracts/GovernanceUtils.sol/GovernanceUtils.json +2 -2
  36. package/build/contracts/bank/Bank.sol/Bank.dbg.json +1 -1
  37. package/build/contracts/bank/Bank.sol/Bank.json +20 -2
  38. package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.dbg.json +4 -0
  39. package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.json +10 -0
  40. package/build/contracts/bridge/Bridge.sol/Bridge.dbg.json +1 -1
  41. package/build/contracts/bridge/Bridge.sol/Bridge.json +2470 -132
  42. package/build/contracts/bridge/BridgeState.sol/BridgeState.dbg.json +4 -0
  43. package/build/contracts/bridge/BridgeState.sol/BridgeState.json +220 -0
  44. package/build/contracts/bridge/Deposit.sol/Deposit.dbg.json +4 -0
  45. package/build/contracts/bridge/Deposit.sol/Deposit.json +72 -0
  46. package/build/contracts/bridge/DepositSweep.sol/DepositSweep.dbg.json +4 -0
  47. package/build/contracts/bridge/DepositSweep.sol/DepositSweep.json +30 -0
  48. package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.dbg.json +4 -0
  49. package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.json +10 -0
  50. package/build/contracts/bridge/Fraud.sol/Fraud.dbg.json +4 -0
  51. package/build/contracts/bridge/Fraud.sol/Fraud.json +86 -0
  52. package/build/contracts/bridge/Heartbeat.sol/Heartbeat.dbg.json +4 -0
  53. package/build/contracts/bridge/Heartbeat.sol/Heartbeat.json +10 -0
  54. package/build/contracts/bridge/IRelay.sol/IRelay.dbg.json +4 -0
  55. package/build/contracts/bridge/IRelay.sol/IRelay.json +37 -0
  56. package/build/contracts/bridge/MovingFunds.sol/MovingFunds.dbg.json +4 -0
  57. package/build/contracts/bridge/MovingFunds.sol/MovingFunds.json +125 -0
  58. package/build/contracts/bridge/Redemption.sol/OutboundTx.dbg.json +4 -0
  59. package/build/contracts/bridge/Redemption.sol/OutboundTx.json +10 -0
  60. package/build/contracts/bridge/Redemption.sol/Redemption.dbg.json +4 -0
  61. package/build/contracts/bridge/Redemption.sol/Redemption.json +92 -0
  62. package/build/contracts/bridge/VendingMachine.sol/VendingMachine.dbg.json +1 -1
  63. package/build/contracts/bridge/VendingMachine.sol/VendingMachine.json +2 -2
  64. package/build/contracts/bridge/Wallets.sol/Wallets.dbg.json +4 -0
  65. package/build/contracts/bridge/Wallets.sol/Wallets.json +112 -0
  66. package/build/contracts/token/TBTC.sol/TBTC.dbg.json +1 -1
  67. package/build/contracts/token/TBTC.sol/TBTC.json +2 -2
  68. package/build/contracts/vault/DonationVault.sol/DonationVault.dbg.json +4 -0
  69. package/build/contracts/vault/DonationVault.sol/DonationVault.json +103 -0
  70. package/build/contracts/vault/IVault.sol/IVault.dbg.json +1 -1
  71. package/build/contracts/vault/IVault.sol/IVault.json +19 -1
  72. package/build/contracts/vault/TBTCVault.sol/TBTCVault.dbg.json +1 -1
  73. package/build/contracts/vault/TBTCVault.sol/TBTCVault.json +36 -18
  74. package/contracts/GovernanceUtils.sol +1 -1
  75. package/contracts/bank/Bank.sol +34 -18
  76. package/contracts/bridge/BitcoinTx.sol +318 -0
  77. package/contracts/bridge/Bridge.sol +1527 -247
  78. package/contracts/bridge/BridgeState.sol +698 -0
  79. package/contracts/bridge/Deposit.sol +266 -0
  80. package/contracts/bridge/DepositSweep.sol +514 -0
  81. package/contracts/bridge/EcdsaLib.sol +45 -0
  82. package/contracts/bridge/Fraud.sol +508 -0
  83. package/contracts/bridge/Heartbeat.sol +107 -0
  84. package/contracts/bridge/IRelay.sol +28 -0
  85. package/contracts/bridge/MovingFunds.sol +1034 -0
  86. package/contracts/bridge/Redemption.sol +868 -0
  87. package/contracts/bridge/VendingMachine.sol +1 -1
  88. package/contracts/bridge/Wallets.sol +550 -0
  89. package/contracts/token/TBTC.sol +1 -1
  90. package/contracts/vault/DonationVault.sol +125 -0
  91. package/contracts/vault/IVault.sol +32 -10
  92. package/contracts/vault/TBTCVault.sol +20 -2
  93. package/deploy/00_resolve_relay.ts +28 -0
  94. package/deploy/04_deploy_bank.ts +27 -0
  95. package/deploy/05_deploy_bridge.ts +67 -0
  96. package/deploy/06_bank_update_bridge.ts +19 -0
  97. package/deploy/07_transfer_ownership.ts +15 -0
  98. package/deploy/08_transfer_governance.ts +20 -0
  99. package/export.json +15711 -475
  100. package/package.json +27 -24
  101. package/artifacts/solcInputs/c4fd2c31cc58f5fe0cc586dd84a84b60.json +0 -125
@@ -0,0 +1,125 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ // ██████████████ ▐████▌ ██████████████
4
+ // ██████████████ ▐████▌ ██████████████
5
+ // ▐████▌ ▐████▌
6
+ // ▐████▌ ▐████▌
7
+ // ██████████████ ▐████▌ ██████████████
8
+ // ██████████████ ▐████▌ ██████████████
9
+ // ▐████▌ ▐████▌
10
+ // ▐████▌ ▐████▌
11
+ // ▐████▌ ▐████▌
12
+ // ▐████▌ ▐████▌
13
+ // ▐████▌ ▐████▌
14
+ // ▐████▌ ▐████▌
15
+
16
+ pragma solidity ^0.8.9;
17
+
18
+ import "./IVault.sol";
19
+ import "../bank/Bank.sol";
20
+
21
+ /// @title BTC donation vault
22
+ /// @notice Vault that allows making BTC donations to the system. Upon deposit,
23
+ /// this vault does not increase depositors' balances and always
24
+ /// decreases its own balance in the same transaction. The vault also
25
+ /// allows making donations using existing Bank balances.
26
+ ///
27
+ /// BEWARE: ALL BTC DEPOSITS TARGETING THIS VAULT ARE NOT REDEEMABLE
28
+ /// AND THERE IS NO WAY TO RESTORE THE DONATED BALANCE.
29
+ /// USE THIS VAULT ONLY WHEN YOU REALLY KNOW WHAT YOU ARE DOING!
30
+ contract DonationVault is IVault {
31
+ Bank public bank;
32
+
33
+ event DonationReceived(address donor, uint256 donatedAmount);
34
+
35
+ modifier onlyBank() {
36
+ require(msg.sender == address(bank), "Caller is not the Bank");
37
+ _;
38
+ }
39
+
40
+ constructor(Bank _bank) {
41
+ require(
42
+ address(_bank) != address(0),
43
+ "Bank can not be the zero address"
44
+ );
45
+
46
+ bank = _bank;
47
+ }
48
+
49
+ /// @notice Transfers the given `amount` of the Bank balance from the
50
+ /// caller to the Donation Vault and immediately decreases the
51
+ /// vault's balance in the Bank by the transferred `amount`.
52
+ /// @param amount Amount of the Bank balance to donate
53
+ /// @dev Requirements:
54
+ /// - The caller's balance in the Bank must be greater than or equal
55
+ /// to the `amount`.
56
+ /// - Donation Vault must have an allowance for caller's balance in
57
+ /// the Bank for at least `amount`.
58
+ function donate(uint256 amount) external {
59
+ address donor = msg.sender;
60
+
61
+ require(
62
+ bank.balanceOf(donor) >= amount,
63
+ "Amount exceeds balance in the bank"
64
+ );
65
+
66
+ emit DonationReceived(donor, amount);
67
+
68
+ bank.transferBalanceFrom(donor, address(this), amount);
69
+ bank.decreaseBalance(amount);
70
+ }
71
+
72
+ /// @notice Transfers the given `amount` of the Bank balance from the
73
+ /// `owner` to the Donation Vault and immediately decreases the
74
+ /// vault's balance in the Bank by the transferred `amount`.
75
+ /// @param owner Address of the Bank balance owner who approved their
76
+ /// balance to be used by the vault
77
+ /// @param amount The amount of the Bank balance approved by the owner
78
+ /// to be used by the vault
79
+ /// @dev Requirements:
80
+ /// - Can only be called by the Bank via `approveBalanceAndCall`.
81
+ /// - The `owner` balance in the Bank must be greater than or equal
82
+ /// to the `amount`.
83
+ function receiveBalanceApproval(address owner, uint256 amount)
84
+ external
85
+ override
86
+ onlyBank
87
+ {
88
+ require(
89
+ bank.balanceOf(owner) >= amount,
90
+ "Amount exceeds balance in the bank"
91
+ );
92
+
93
+ emit DonationReceived(owner, amount);
94
+
95
+ bank.transferBalanceFrom(owner, address(this), amount);
96
+ bank.decreaseBalance(amount);
97
+ }
98
+
99
+ /// @notice Ignores the deposited amounts and does not increase depositors'
100
+ /// individual balances. The vault decreases its own tBTC balance
101
+ /// in the Bank by the total deposited amount.
102
+ /// @param depositors Addresses of depositors whose deposits have been swept
103
+ /// @param depositedAmounts Amounts deposited by individual depositors and
104
+ /// swept
105
+ /// @dev Requirements:
106
+ /// - Can only be called by the Bank after the Bridge swept deposits
107
+ /// and Bank increased balance for the vault.
108
+ /// - The `depositors` array must not be empty.
109
+ /// - The `depositors` array length must be equal to the
110
+ /// `depositedAmounts` array length.
111
+ function receiveBalanceIncrease(
112
+ address[] calldata depositors,
113
+ uint256[] calldata depositedAmounts
114
+ ) external override onlyBank {
115
+ require(depositors.length != 0, "No depositors specified");
116
+
117
+ uint256 totalAmount = 0;
118
+ for (uint256 i = 0; i < depositors.length; i++) {
119
+ totalAmount += depositedAmounts[i];
120
+ emit DonationReceived(depositors[i], depositedAmounts[i]);
121
+ }
122
+
123
+ bank.decreaseBalance(totalAmount);
124
+ }
125
+ }
@@ -13,25 +13,47 @@
13
13
  // ▐████▌ ▐████▌
14
14
  // ▐████▌ ▐████▌
15
15
 
16
- pragma solidity 0.8.4;
16
+ pragma solidity ^0.8.9;
17
17
 
18
18
  /// @title Bank Vault interface
19
19
  /// @notice `IVault` is an interface for a smart contract consuming Bank
20
- /// balances allowing the smart contract to receive Bank balances right
21
- /// after sweeping the deposit by the Bridge. This method allows the
22
- /// depositor to route their deposit revealed to the Bridge to the
23
- /// particular smart contract in the same transaction the deposit is
24
- /// revealed. This way, the depositor does not have to execute
25
- /// additional transaction after the deposit gets swept by the Bridge.
20
+ /// balances of other contracts or externally owned accounts (EOA).
26
21
  interface IVault {
22
+ /// @notice Called by the Bank in `approveBalanceAndCall` function after
23
+ /// the balance `owner` approved `amount` of their balance in the
24
+ /// Bank for the vault. This way, the depositor can approve balance
25
+ /// and call the vault to use the approved balance in a single
26
+ /// transaction.
27
+ /// @param owner Address of the Bank balance owner who approved their
28
+ /// balance to be used by the vault
29
+ /// @param amount The amount of the Bank balance approved by the owner
30
+ /// to be used by the vault
31
+ // @dev The implementation must ensure this function can only be called
32
+ /// by the Bank. The Bank does _not_ guarantee that the `amount`
33
+ /// approved by the `owner` currently exists on their balance. That is,
34
+ /// the `owner` could approve more balance than they currently have.
35
+ /// This works the same as `Bank.approve` function. The vault must
36
+ /// ensure the actual balance is checked before performing any action
37
+ /// based on it.
38
+ function receiveBalanceApproval(address owner, uint256 amount) external;
39
+
27
40
  /// @notice Called by the Bank in `increaseBalanceAndCall` function after
28
- /// increasing the balance in the Bank for the vault.
41
+ /// increasing the balance in the Bank for the vault. It happens in
42
+ /// the same transaction in which deposits were swept by the Bridge.
43
+ /// This allows the depositor to route their deposit revealed to the
44
+ /// Bridge to the particular smart contract (vault) in the same
45
+ /// transaction in which the deposit is revealed. This way, the
46
+ /// depositor does not have to execute additional transaction after
47
+ /// the deposit gets swept by the Bridge to approve and transfer
48
+ /// their balance to the vault.
29
49
  /// @param depositors Addresses of depositors whose deposits have been swept
30
50
  /// @param depositedAmounts Amounts deposited by individual depositors and
31
51
  /// swept
32
52
  /// @dev The implementation must ensure this function can only be called
33
- /// by the Bank.
34
- function onBalanceIncreased(
53
+ /// by the Bank. The Bank guarantees that the vault's balance was
54
+ /// increased by the sum of all deposited amounts before this function
55
+ /// is called, in the same transaction.
56
+ function receiveBalanceIncrease(
35
57
  address[] calldata depositors,
36
58
  uint256[] calldata depositedAmounts
37
59
  ) external;
@@ -13,7 +13,7 @@
13
13
  // ▐████▌ ▐████▌
14
14
  // ▐████▌ ▐████▌
15
15
 
16
- pragma solidity 0.8.4;
16
+ pragma solidity ^0.8.9;
17
17
 
18
18
  import "./IVault.sol";
19
19
  import "../bank/Bank.sol";
@@ -70,13 +70,31 @@ contract TBTCVault is IVault {
70
70
  bank.transferBalanceFrom(minter, address(this), amount);
71
71
  }
72
72
 
73
+ /// @notice Transfers the given `amount` of the Bank balance from the caller
74
+ /// to TBTC Vault and mints `amount` of TBTC to the caller.
75
+ /// @dev Can only be called by the Bank via `approveBalanceAndCall`.
76
+ /// @param owner The owner who approved their Bank balance
77
+ /// @param amount Amount of TBTC to mint
78
+ function receiveBalanceApproval(address owner, uint256 amount)
79
+ external
80
+ override
81
+ onlyBank
82
+ {
83
+ require(
84
+ bank.balanceOf(owner) >= amount,
85
+ "Amount exceeds balance in the bank"
86
+ );
87
+ _mint(owner, amount);
88
+ bank.transferBalanceFrom(owner, address(this), amount);
89
+ }
90
+
73
91
  /// @notice Mints the same amount of TBTC as the deposited amount for each
74
92
  /// depositor in the array. Can only be called by the Bank after the
75
93
  /// Bridge swept deposits and Bank increased balance for the
76
94
  /// vault.
77
95
  /// @dev Fails if `depositors` array is empty. Expects the length of
78
96
  /// `depositors` and `depositedAmounts` is the same.
79
- function onBalanceIncreased(
97
+ function receiveBalanceIncrease(
80
98
  address[] calldata depositors,
81
99
  uint256[] calldata depositedAmounts
82
100
  ) external override onlyBank {
@@ -0,0 +1,28 @@
1
+ import { HardhatRuntimeEnvironment } from "hardhat/types"
2
+ import { DeployFunction } from "hardhat-deploy/types"
3
+
4
+ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
5
+ const { getNamedAccounts, deployments, helpers } = hre
6
+ const { log } = deployments
7
+ const { deployer } = await getNamedAccounts()
8
+
9
+ const Relay = await deployments.getOrNull("Relay")
10
+
11
+ if (Relay && helpers.address.isValid(Relay.address)) {
12
+ log(`using external Relay at ${Relay.address}`)
13
+ } else if (hre.network.name !== "hardhat") {
14
+ throw new Error("deployed Relay contract not found")
15
+ } else {
16
+ log("deploying Relay stub")
17
+
18
+ await deployments.deploy("Relay", {
19
+ contract: "TestRelay",
20
+ from: deployer,
21
+ log: true,
22
+ })
23
+ }
24
+ }
25
+
26
+ export default func
27
+
28
+ func.tags = ["Relay"]
@@ -0,0 +1,27 @@
1
+ import { HardhatRuntimeEnvironment } from "hardhat/types"
2
+ import { DeployFunction } from "hardhat-deploy/types"
3
+
4
+ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
5
+ const { deployments, getNamedAccounts } = hre
6
+ const { deploy } = deployments
7
+ const { deployer } = await getNamedAccounts()
8
+
9
+ const Bank = await deploy("Bank", {
10
+ contract:
11
+ deployments.getNetworkName() === "hardhat" ? "BankStub" : undefined,
12
+ from: deployer,
13
+ args: [],
14
+ log: true,
15
+ })
16
+
17
+ if (hre.network.tags.tenderly) {
18
+ await hre.tenderly.verify({
19
+ name: "Bank",
20
+ address: Bank.address,
21
+ })
22
+ }
23
+ }
24
+
25
+ export default func
26
+
27
+ func.tags = ["Bank"]
@@ -0,0 +1,67 @@
1
+ import { HardhatRuntimeEnvironment } from "hardhat/types"
2
+ import { DeployFunction } from "hardhat-deploy/types"
3
+
4
+ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
5
+ const { deployments, getNamedAccounts } = hre
6
+ const { deploy } = deployments
7
+ const { deployer, treasury } = await getNamedAccounts()
8
+
9
+ const Bank = await deployments.get("Bank")
10
+ const Relay = await deployments.get("Relay")
11
+
12
+ // TODO: Test for mainnet deployment that when `WalletRegistry` is provided
13
+ // in `external/mainnet/` directory it gets resolved correctly, and the deployment
14
+ // script from `@keep-network/ecdsa` is not invoked once again.
15
+ const WalletRegistry = await deployments.get("WalletRegistry")
16
+
17
+ // For local tests use `1`.
18
+ const txProofDifficultyFactor =
19
+ deployments.getNetworkName() === "hardhat" ? 1 : 6
20
+
21
+ const Deposit = await deploy("Deposit", { from: deployer, log: true })
22
+ const DepositSweep = await deploy("DepositSweep", {
23
+ from: deployer,
24
+ log: true,
25
+ })
26
+ const Redemption = await deploy("Redemption", { from: deployer, log: true })
27
+ const Wallets = await deploy("Wallets", { from: deployer, log: true })
28
+ const Fraud = await deploy("Fraud", { from: deployer, log: true })
29
+ const MovingFunds = await deploy("MovingFunds", {
30
+ from: deployer,
31
+ log: true,
32
+ })
33
+
34
+ const Bridge = await deploy("Bridge", {
35
+ contract:
36
+ deployments.getNetworkName() === "hardhat" ? "BridgeStub" : undefined,
37
+ from: deployer,
38
+ args: [
39
+ Bank.address,
40
+ Relay.address,
41
+ treasury,
42
+ WalletRegistry.address,
43
+ txProofDifficultyFactor,
44
+ ],
45
+ libraries: {
46
+ Deposit: Deposit.address,
47
+ DepositSweep: DepositSweep.address,
48
+ Redemption: Redemption.address,
49
+ Wallets: Wallets.address,
50
+ Fraud: Fraud.address,
51
+ MovingFunds: MovingFunds.address,
52
+ },
53
+ log: true,
54
+ })
55
+
56
+ if (hre.network.tags.tenderly) {
57
+ await hre.tenderly.verify({
58
+ name: "Bridge",
59
+ address: Bridge.address,
60
+ })
61
+ }
62
+ }
63
+
64
+ export default func
65
+
66
+ func.tags = ["Bridge"]
67
+ func.dependencies = ["Bank", "Relay", "Treasury", "WalletRegistry"]
@@ -0,0 +1,19 @@
1
+ import { HardhatRuntimeEnvironment } from "hardhat/types"
2
+ import { DeployFunction } from "hardhat-deploy/types"
3
+
4
+ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
5
+ const { getNamedAccounts, deployments } = hre
6
+ const { execute, log } = deployments
7
+ const { deployer } = await getNamedAccounts()
8
+
9
+ const Bridge = await deployments.get("Bridge")
10
+
11
+ log("updating Bridge in Bank")
12
+
13
+ await execute("Bank", { from: deployer }, "updateBridge", Bridge.address)
14
+ }
15
+
16
+ export default func
17
+
18
+ func.tags = ["BankUpdateBridge"]
19
+ func.dependencies = ["Bank", "Bridge"]
@@ -0,0 +1,15 @@
1
+ import { HardhatRuntimeEnvironment } from "hardhat/types"
2
+ import { DeployFunction } from "hardhat-deploy/types"
3
+
4
+ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
5
+ const { getNamedAccounts, helpers } = hre
6
+ const { deployer, governance } = await getNamedAccounts()
7
+
8
+ await helpers.ownable.transferOwnership("Bank", governance, deployer)
9
+ }
10
+
11
+ export default func
12
+
13
+ func.tags = ["TransferOwnership"]
14
+ func.dependencies = ["Bank"]
15
+ func.runAtTheEnd = true
@@ -0,0 +1,20 @@
1
+ import { HardhatRuntimeEnvironment } from "hardhat/types"
2
+ import { DeployFunction } from "hardhat-deploy/types"
3
+
4
+ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
5
+ const { getNamedAccounts, deployments } = hre
6
+ const { deployer, governance } = await getNamedAccounts()
7
+
8
+ await deployments.execute(
9
+ "Bridge",
10
+ { from: deployer },
11
+ "transferGovernance",
12
+ governance
13
+ )
14
+ }
15
+
16
+ export default func
17
+
18
+ func.tags = ["TransferGovernance"]
19
+ func.dependencies = ["Bridge"]
20
+ func.runAtTheEnd = true