@keep-network/tbtc-v2 0.1.1-dev.9 → 0.1.1-dev.92

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 (115) hide show
  1. package/README.adoc +12 -0
  2. package/artifacts/Bank.json +807 -0
  3. package/artifacts/Bridge.json +2300 -0
  4. package/artifacts/Deposit.json +117 -0
  5. package/artifacts/DepositSweep.json +77 -0
  6. package/artifacts/EcdsaDkgValidator.json +532 -0
  7. package/artifacts/EcdsaInactivity.json +156 -0
  8. package/artifacts/EcdsaSortitionPool.json +1004 -0
  9. package/artifacts/Fraud.json +164 -0
  10. package/artifacts/KeepRegistry.json +99 -0
  11. package/artifacts/KeepStake.json +286 -0
  12. package/artifacts/KeepToken.json +711 -0
  13. package/artifacts/KeepTokenStaking.json +483 -0
  14. package/artifacts/MovingFunds.json +249 -0
  15. package/artifacts/NuCypherStakingEscrow.json +256 -0
  16. package/artifacts/NuCypherToken.json +711 -0
  17. package/artifacts/RandomBeaconStub.json +141 -0
  18. package/artifacts/Redemption.json +174 -0
  19. package/artifacts/ReimbursementPool.json +509 -0
  20. package/artifacts/Relay.json +123 -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/TBTCVault.json +691 -0
  25. package/artifacts/TokenStaking.json +2288 -0
  26. package/artifacts/TokenholderGovernor.json +1795 -0
  27. package/artifacts/TokenholderTimelock.json +1058 -0
  28. package/artifacts/VendingMachine.json +31 -30
  29. package/artifacts/VendingMachineKeep.json +400 -0
  30. package/artifacts/VendingMachineNuCypher.json +400 -0
  31. package/artifacts/WalletRegistry.json +1843 -0
  32. package/artifacts/WalletRegistryGovernance.json +2754 -0
  33. package/artifacts/Wallets.json +186 -0
  34. package/artifacts/solcInputs/2522ad78efeee521d6cb3252a08f9f62.json +314 -0
  35. package/build/contracts/GovernanceUtils.sol/GovernanceUtils.dbg.json +1 -1
  36. package/build/contracts/GovernanceUtils.sol/GovernanceUtils.json +2 -2
  37. package/build/contracts/bank/Bank.sol/Bank.dbg.json +1 -1
  38. package/build/contracts/bank/Bank.sol/Bank.json +27 -4
  39. package/build/contracts/bank/IReceiveBalanceApproval.sol/IReceiveBalanceApproval.dbg.json +4 -0
  40. package/build/contracts/bank/IReceiveBalanceApproval.sol/IReceiveBalanceApproval.json +34 -0
  41. package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.dbg.json +1 -1
  42. package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.json +2 -2
  43. package/build/contracts/bridge/Bridge.sol/Bridge.dbg.json +1 -1
  44. package/build/contracts/bridge/Bridge.sol/Bridge.json +2547 -196
  45. package/build/contracts/bridge/BridgeState.sol/BridgeState.dbg.json +4 -0
  46. package/build/contracts/bridge/BridgeState.sol/BridgeState.json +226 -0
  47. package/build/contracts/bridge/Deposit.sol/Deposit.dbg.json +4 -0
  48. package/build/contracts/bridge/Deposit.sol/Deposit.json +72 -0
  49. package/build/contracts/bridge/DepositSweep.sol/DepositSweep.dbg.json +4 -0
  50. package/build/contracts/bridge/DepositSweep.sol/DepositSweep.json +30 -0
  51. package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.dbg.json +4 -0
  52. package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.json +10 -0
  53. package/build/contracts/bridge/Fraud.sol/Fraud.dbg.json +4 -0
  54. package/build/contracts/bridge/Fraud.sol/Fraud.json +86 -0
  55. package/build/contracts/bridge/Heartbeat.sol/Heartbeat.dbg.json +4 -0
  56. package/build/contracts/bridge/Heartbeat.sol/Heartbeat.json +10 -0
  57. package/build/contracts/bridge/IRelay.sol/IRelay.dbg.json +4 -0
  58. package/build/contracts/bridge/IRelay.sol/IRelay.json +37 -0
  59. package/build/contracts/bridge/MovingFunds.sol/MovingFunds.dbg.json +4 -0
  60. package/build/contracts/bridge/MovingFunds.sol/MovingFunds.json +138 -0
  61. package/build/contracts/bridge/Redemption.sol/OutboundTx.dbg.json +4 -0
  62. package/build/contracts/bridge/Redemption.sol/OutboundTx.json +10 -0
  63. package/build/contracts/bridge/Redemption.sol/Redemption.dbg.json +4 -0
  64. package/build/contracts/bridge/Redemption.sol/Redemption.json +92 -0
  65. package/build/contracts/bridge/VendingMachine.sol/VendingMachine.dbg.json +1 -1
  66. package/build/contracts/bridge/VendingMachine.sol/VendingMachine.json +2 -2
  67. package/build/contracts/bridge/Wallets.sol/Wallets.dbg.json +4 -0
  68. package/build/contracts/bridge/Wallets.sol/Wallets.json +112 -0
  69. package/build/contracts/token/TBTC.sol/TBTC.dbg.json +1 -1
  70. package/build/contracts/token/TBTC.sol/TBTC.json +2 -2
  71. package/build/contracts/vault/DonationVault.sol/DonationVault.dbg.json +4 -0
  72. package/build/contracts/vault/DonationVault.sol/DonationVault.json +108 -0
  73. package/build/contracts/vault/IVault.sol/IVault.dbg.json +1 -1
  74. package/build/contracts/vault/IVault.sol/IVault.json +24 -1
  75. package/build/contracts/vault/TBTCVault.sol/TBTCVault.dbg.json +1 -1
  76. package/build/contracts/vault/TBTCVault.sol/TBTCVault.json +295 -9
  77. package/contracts/GovernanceUtils.sol +4 -4
  78. package/contracts/bank/Bank.sol +119 -57
  79. package/contracts/bank/IReceiveBalanceApproval.sol +45 -0
  80. package/contracts/bridge/BitcoinTx.sol +232 -10
  81. package/contracts/bridge/Bridge.sol +1692 -244
  82. package/contracts/bridge/BridgeState.sol +739 -0
  83. package/contracts/bridge/Deposit.sol +269 -0
  84. package/contracts/bridge/DepositSweep.sol +571 -0
  85. package/contracts/bridge/EcdsaLib.sol +45 -0
  86. package/contracts/bridge/Fraud.sol +604 -0
  87. package/contracts/bridge/Heartbeat.sol +112 -0
  88. package/contracts/bridge/IRelay.sol +28 -0
  89. package/contracts/bridge/MovingFunds.sol +1089 -0
  90. package/contracts/bridge/Redemption.sol +1021 -0
  91. package/contracts/bridge/VendingMachine.sol +2 -2
  92. package/contracts/bridge/Wallets.sol +553 -0
  93. package/contracts/hardhat-dependency-compiler/.hardhat-dependency-compiler +1 -0
  94. package/contracts/hardhat-dependency-compiler/@keep-network/ecdsa/contracts/WalletRegistry.sol +3 -0
  95. package/contracts/hardhat-dependency-compiler/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol +3 -0
  96. package/contracts/hardhat-dependency-compiler/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol +3 -0
  97. package/contracts/token/TBTC.sol +1 -1
  98. package/contracts/vault/DonationVault.sol +125 -0
  99. package/contracts/vault/IVault.sol +19 -13
  100. package/contracts/vault/TBTCVault.sol +200 -23
  101. package/deploy/00_resolve_relay.ts +28 -0
  102. package/deploy/{03_transfer_roles.ts → 03_transfer_vending_machine_roles.ts} +1 -1
  103. package/deploy/04_deploy_bank.ts +27 -0
  104. package/deploy/05_deploy_bridge.ts +80 -0
  105. package/deploy/06_deploy_tbtc_vault.ts +30 -0
  106. package/deploy/07_bank_update_bridge.ts +19 -0
  107. package/deploy/08_transfer_bank_ownership.ts +15 -0
  108. package/deploy/09_transfer_tbtc_vault_ownership.ts +15 -0
  109. package/deploy/10_transfer_bridge_governance.ts +20 -0
  110. package/deploy/11_initialize_wallet_owner.ts +18 -0
  111. package/deploy/11_transfer_proxy_admin_ownership.ts +30 -0
  112. package/deploy/12_deploy_proxy_admin_with_deputy.ts +33 -0
  113. package/export.json +15771 -443
  114. package/package.json +34 -26
  115. package/artifacts/solcInputs/58d5b3ee7688835879381470de985d6b.json +0 -128
@@ -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(
84
+ address owner,
85
+ uint256 amount,
86
+ bytes memory
87
+ ) external override onlyBank {
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,31 @@
13
13
  // ▐████▌ ▐████▌
14
14
  // ▐████▌ ▐████▌
15
15
 
16
- pragma solidity 0.8.4;
16
+ pragma solidity ^0.8.9;
17
+
18
+ import "../bank/IReceiveBalanceApproval.sol";
17
19
 
18
20
  /// @title Bank Vault interface
19
21
  /// @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.
26
- interface IVault {
22
+ /// balances of other contracts or externally owned accounts (EOA).
23
+ interface IVault is IReceiveBalanceApproval {
27
24
  /// @notice Called by the Bank in `increaseBalanceAndCall` function after
28
- /// increasing the balance in the Bank for the vault.
29
- /// @param depositors Addresses of depositors whose deposits have been swept
25
+ /// increasing the balance in the Bank for the vault. It happens in
26
+ /// the same transaction in which deposits were swept by the Bridge.
27
+ /// This allows the depositor to route their deposit revealed to the
28
+ /// Bridge to the particular smart contract (vault) in the same
29
+ /// transaction in which the deposit is revealed. This way, the
30
+ /// depositor does not have to execute additional transaction after
31
+ /// the deposit gets swept by the Bridge to approve and transfer
32
+ /// their balance to the vault.
33
+ /// @param depositors Addresses of depositors whose deposits have been swept.
30
34
  /// @param depositedAmounts Amounts deposited by individual depositors and
31
- /// swept
35
+ /// swept.
32
36
  /// @dev The implementation must ensure this function can only be called
33
- /// by the Bank.
34
- function onBalanceIncreased(
37
+ /// by the Bank. The Bank guarantees that the vault's balance was
38
+ /// increased by the sum of all deposited amounts before this function
39
+ /// is called, in the same transaction.
40
+ function receiveBalanceIncrease(
35
41
  address[] calldata depositors,
36
42
  uint256[] calldata depositedAmounts
37
43
  ) external;
@@ -13,33 +13,63 @@
13
13
  // ▐████▌ ▐████▌
14
14
  // ▐████▌ ▐████▌
15
15
 
16
- pragma solidity 0.8.4;
16
+ pragma solidity ^0.8.9;
17
+
18
+ import "@openzeppelin/contracts/access/Ownable.sol";
17
19
 
18
20
  import "./IVault.sol";
19
21
  import "../bank/Bank.sol";
20
22
  import "../token/TBTC.sol";
23
+ import "../GovernanceUtils.sol";
21
24
 
22
25
  /// @title TBTC application vault
23
26
  /// @notice TBTC is a fully Bitcoin-backed ERC-20 token pegged to the price of
24
27
  /// Bitcoin. It facilitates Bitcoin holders to act on the Ethereum
25
28
  /// blockchain and access the decentralized finance (DeFi) ecosystem.
26
- /// TBTC Vault mints and redeems TBTC based on Bitcoin balances in the
29
+ /// TBTC Vault mints and unmints TBTC based on Bitcoin balances in the
27
30
  /// Bank.
28
31
  /// @dev TBTC Vault is the owner of TBTC token contract and is the only contract
29
32
  /// minting the token.
30
- contract TBTCVault is IVault {
33
+ contract TBTCVault is IVault, Ownable {
34
+ using SafeERC20 for IERC20;
35
+
36
+ /// @notice The time delay that needs to pass between initializing and
37
+ /// finalizing upgrade to a new vault. The time delay forces the
38
+ /// upgrading party to reflect on the vault address it is upgrading
39
+ /// to and lets all TBTC holders notice the planned
40
+ /// upgrade.
41
+ uint256 public constant UPGRADE_GOVERNANCE_DELAY = 24 hours;
42
+
31
43
  Bank public bank;
32
44
  TBTC public tbtcToken;
33
45
 
46
+ /// @notice The address of a new TBTC vault. Set only when the upgrade
47
+ /// process is pending. Once the upgrade gets finalized, the new
48
+ /// TBTC vault will become an owner of TBTC token.
49
+ address public newVault;
50
+ /// @notice The timestamp at which an upgrade to a new TBTC vault was
51
+ /// initiated. Set only when the upgrade process is pending.
52
+ uint256 public upgradeInitiatedTimestamp;
53
+
34
54
  event Minted(address indexed to, uint256 amount);
55
+ event Unminted(address indexed from, uint256 amount);
35
56
 
36
- event Redeemed(address indexed from, uint256 amount);
57
+ event UpgradeInitiated(address newVault, uint256 timestamp);
58
+ event UpgradeFinalized(address newVault);
37
59
 
38
60
  modifier onlyBank() {
39
61
  require(msg.sender == address(bank), "Caller is not the Bank");
40
62
  _;
41
63
  }
42
64
 
65
+ modifier onlyAfterUpgradeGovernanceDelay() {
66
+ GovernanceUtils.onlyAfterGovernanceDelay(
67
+ upgradeInitiatedTimestamp,
68
+ UPGRADE_GOVERNANCE_DELAY
69
+ );
70
+ _;
71
+ }
72
+
43
73
  constructor(Bank _bank, TBTC _tbtcToken) {
44
74
  require(
45
75
  address(_bank) != address(0),
@@ -59,7 +89,7 @@ contract TBTCVault is IVault {
59
89
  /// to TBTC Vault, and mints `amount` of TBTC to the caller.
60
90
  /// @dev TBTC Vault must have an allowance for caller's balance in the Bank
61
91
  /// for at least `amount`.
62
- /// @param amount Amount of TBTC to mint
92
+ /// @param amount Amount of TBTC to mint.
63
93
  function mint(uint256 amount) external {
64
94
  address minter = msg.sender;
65
95
  require(
@@ -70,13 +100,31 @@ contract TBTCVault is IVault {
70
100
  bank.transferBalanceFrom(minter, address(this), amount);
71
101
  }
72
102
 
103
+ /// @notice Transfers the given `amount` of the Bank balance from the caller
104
+ /// to TBTC Vault and mints `amount` of TBTC to the caller.
105
+ /// @dev Can only be called by the Bank via `approveBalanceAndCall`.
106
+ /// @param owner The owner who approved their Bank balance.
107
+ /// @param amount Amount of TBTC to mint.
108
+ function receiveBalanceApproval(
109
+ address owner,
110
+ uint256 amount,
111
+ bytes calldata
112
+ ) external override onlyBank {
113
+ require(
114
+ bank.balanceOf(owner) >= amount,
115
+ "Amount exceeds balance in the bank"
116
+ );
117
+ _mint(owner, amount);
118
+ bank.transferBalanceFrom(owner, address(this), amount);
119
+ }
120
+
73
121
  /// @notice Mints the same amount of TBTC as the deposited amount for each
74
122
  /// depositor in the array. Can only be called by the Bank after the
75
123
  /// Bridge swept deposits and Bank increased balance for the
76
124
  /// vault.
77
125
  /// @dev Fails if `depositors` array is empty. Expects the length of
78
126
  /// `depositors` and `depositedAmounts` is the same.
79
- function onBalanceIncreased(
127
+ function receiveBalanceIncrease(
80
128
  address[] calldata depositors,
81
129
  uint256[] calldata depositedAmounts
82
130
  ) external override onlyBank {
@@ -86,32 +134,151 @@ contract TBTCVault is IVault {
86
134
  }
87
135
  }
88
136
 
89
- /// @notice Burns `amount` of TBTC from the caller's account and transfers
137
+ /// @notice Burns `amount` of TBTC from the caller's balance and transfers
90
138
  /// `amount` back to the caller's balance in the Bank.
91
139
  /// @dev Caller must have at least `amount` of TBTC approved to
92
140
  /// TBTC Vault.
93
- /// @param amount Amount of TBTC to redeem
94
- function redeem(uint256 amount) external {
95
- _redeem(msg.sender, amount);
141
+ /// @param amount Amount of TBTC to unmint.
142
+ function unmint(uint256 amount) external {
143
+ _unmint(msg.sender, amount);
96
144
  }
97
145
 
98
- /// @notice Burns `amount` of TBTC from the caller's account and transfers
99
- /// `amount` back to the caller's balance in the Bank.
100
- /// @dev This function is doing the same as `redeem` but it allows to
101
- /// execute redemption without an additional approval transaction.
102
- /// The function can be called only via `approveAndCall` of TBTC token.
103
- /// @param from TBTC token holder executing redemption
104
- /// @param amount Amount of TBTC to redeem
105
- /// @param token TBTC token address
146
+ /// @notice Burns `amount` of TBTC from the caller's balance and transfers
147
+ /// `amount` of Bank balance to the Bridge requesting redemption
148
+ /// based on the provided `redemptionData`.
149
+ /// @dev Caller must have at least `amount` of TBTC approved to
150
+ /// TBTC Vault.
151
+ /// @param amount Amount of TBTC to unmint and request to redeem in Bridge.
152
+ /// @param redemptionData Redemption data in a format expected from
153
+ /// `redemptionData` parameter of Bridge's `receiveBalanceApproval`
154
+ /// function.
155
+ function unmintAndRedeem(uint256 amount, bytes calldata redemptionData)
156
+ external
157
+ {
158
+ _unmintAndRedeem(msg.sender, amount, redemptionData);
159
+ }
160
+
161
+ /// @notice Burns `amount` of TBTC from the caller's balance. If `extraData`
162
+ /// is empty, transfers `amount` back to the caller's balance in the
163
+ /// Bank. If `extraData` is not empty, requests redemption in the
164
+ /// Bridge using the `extraData` as a `redemptionData` parameter to
165
+ /// Bridge's `receiveBalanceApproval` function.
166
+ /// @dev This function is doing the same as `unmint` or `unmintAndRedeem`
167
+ /// (depending on `extraData` parameter) but it allows to execute
168
+ /// unminting without a separate approval transaction. The function can
169
+ /// be called only via `approveAndCall` of TBTC token.
170
+ /// @param from TBTC token holder executing unminting.
171
+ /// @param amount Amount of TBTC to unmint.
172
+ /// @param token TBTC token address.
173
+ /// @param extraData Redemption data in a format expected from
174
+ /// `redemptionData` parameter of Bridge's `receiveBalanceApproval`
175
+ /// function. If empty, `receiveApproval` is not requesting a
176
+ /// redemption of Bank balance but is instead performing just TBTC
177
+ /// unminting to a Bank balance.
106
178
  function receiveApproval(
107
179
  address from,
108
180
  uint256 amount,
109
181
  address token,
110
- bytes calldata
182
+ bytes calldata extraData
111
183
  ) external {
112
184
  require(token == address(tbtcToken), "Token is not TBTC");
113
185
  require(msg.sender == token, "Only TBTC caller allowed");
114
- _redeem(from, amount);
186
+ if (extraData.length == 0) {
187
+ _unmint(from, amount);
188
+ } else {
189
+ _unmintAndRedeem(from, amount, extraData);
190
+ }
191
+ }
192
+
193
+ /// @notice Initiates vault upgrade process. The upgrade process needs to be
194
+ /// finalized with a call to `finalizeUpgrade` function after the
195
+ /// `UPGRADE_GOVERNANCE_DELAY` passes. Only the governance can
196
+ /// initiate the upgrade.
197
+ /// @param _newVault The new vault address.
198
+ function initiateUpgrade(address _newVault) external onlyOwner {
199
+ require(_newVault != address(0), "New vault address cannot be zero");
200
+ /* solhint-disable-next-line not-rely-on-time */
201
+ emit UpgradeInitiated(_newVault, block.timestamp);
202
+ /* solhint-disable-next-line not-rely-on-time */
203
+ upgradeInitiatedTimestamp = block.timestamp;
204
+ newVault = _newVault;
205
+ }
206
+
207
+ /// @notice Allows the governance to finalize vault upgrade process. The
208
+ /// upgrade process needs to be first initiated with a call to
209
+ /// `initiateUpgrade` and the `UPGRADE_GOVERNANCE_DELAY` needs to
210
+ /// pass. Once the upgrade is finalized, the new vault becomes the
211
+ /// owner of the TBTC token and receives the whole Bank balance of
212
+ /// this vault.
213
+ function finalizeUpgrade()
214
+ external
215
+ onlyOwner
216
+ onlyAfterUpgradeGovernanceDelay
217
+ {
218
+ emit UpgradeFinalized(newVault);
219
+ // slither-disable-next-line reentrancy-no-eth
220
+ tbtcToken.transferOwnership(newVault);
221
+ bank.transferBalance(newVault, bank.balanceOf(address(this)));
222
+ newVault = address(0);
223
+ upgradeInitiatedTimestamp = 0;
224
+ }
225
+
226
+ /// @notice Allows the governance of the TBTCVault to recover any ERC20
227
+ /// token sent mistakenly to the TBTC token contract address.
228
+ /// @param token Address of the recovered ERC20 token contract.
229
+ /// @param recipient Address the recovered token should be sent to.
230
+ /// @param amount Recovered amount.
231
+ function recoverERC20FromToken(
232
+ IERC20 token,
233
+ address recipient,
234
+ uint256 amount
235
+ ) external onlyOwner {
236
+ tbtcToken.recoverERC20(token, recipient, amount);
237
+ }
238
+
239
+ /// @notice Allows the governance of the TBTCVault to recover any ERC721
240
+ /// token sent mistakenly to the TBTC token contract address.
241
+ /// @param token Address of the recovered ERC721 token contract.
242
+ /// @param recipient Address the recovered token should be sent to.
243
+ /// @param tokenId Identifier of the recovered token.
244
+ /// @param data Additional data.
245
+ function recoverERC721FromToken(
246
+ IERC721 token,
247
+ address recipient,
248
+ uint256 tokenId,
249
+ bytes calldata data
250
+ ) external onlyOwner {
251
+ tbtcToken.recoverERC721(token, recipient, tokenId, data);
252
+ }
253
+
254
+ /// @notice Allows the governance of the TBTCVault to recover any ERC20
255
+ /// token sent - mistakenly or not - to the vault address. This
256
+ /// function should be used to withdraw TBTC v1 tokens transferred
257
+ /// to TBTCVault as a result of VendingMachine > TBTCVault upgrade.
258
+ /// @param token Address of the recovered ERC20 token contract.
259
+ /// @param recipient Address the recovered token should be sent to.
260
+ /// @param amount Recovered amount.
261
+ function recoverERC20(
262
+ IERC20 token,
263
+ address recipient,
264
+ uint256 amount
265
+ ) external onlyOwner {
266
+ token.safeTransfer(recipient, amount);
267
+ }
268
+
269
+ /// @notice Allows the governance of the TBTCVault to recover any ERC721
270
+ /// token sent mistakenly to the vault address.
271
+ /// @param token Address of the recovered ERC721 token contract.
272
+ /// @param recipient Address the recovered token should be sent to.
273
+ /// @param tokenId Identifier of the recovered token.
274
+ /// @param data Additional data.
275
+ function recoverERC721(
276
+ IERC721 token,
277
+ address recipient,
278
+ uint256 tokenId,
279
+ bytes calldata data
280
+ ) external onlyOwner {
281
+ token.safeTransferFrom(address(this), recipient, tokenId, data);
115
282
  }
116
283
 
117
284
  // slither-disable-next-line calls-loop
@@ -120,9 +287,19 @@ contract TBTCVault is IVault {
120
287
  tbtcToken.mint(minter, amount);
121
288
  }
122
289
 
123
- function _redeem(address redeemer, uint256 amount) internal {
124
- emit Redeemed(redeemer, amount);
290
+ function _unmint(address unminter, uint256 amount) internal {
291
+ emit Unminted(unminter, amount);
292
+ tbtcToken.burnFrom(unminter, amount);
293
+ bank.transferBalance(unminter, amount);
294
+ }
295
+
296
+ function _unmintAndRedeem(
297
+ address redeemer,
298
+ uint256 amount,
299
+ bytes calldata redemptionData
300
+ ) internal {
301
+ emit Unminted(redeemer, amount);
125
302
  tbtcToken.burnFrom(redeemer, amount);
126
- bank.transferBalance(redeemer, amount);
303
+ bank.approveBalanceAndCall(bank.bridge(), amount, redemptionData);
127
304
  }
128
305
  }
@@ -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"]
@@ -38,7 +38,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
38
38
 
39
39
  export default func
40
40
 
41
- func.tags = ["TransferRoles"]
41
+ func.tags = ["TransferVendingMachineRoles"]
42
42
  func.dependencies = ["TBTC", "VendingMachine"]
43
43
  func.runAtTheEnd = true
44
44
  func.skip = async function (hre: HardhatRuntimeEnvironment): Promise<boolean> {
@@ -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
+ process.env.TEST_USE_STUBS_TBTC === "true" ? "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,80 @@
1
+ import { HardhatRuntimeEnvironment } from "hardhat/types"
2
+ import { DeployFunction } from "hardhat-deploy/types"
3
+
4
+ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
5
+ const { ethers, helpers, 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", {
28
+ contract: "contracts/bridge/Wallets.sol:Wallets",
29
+ from: deployer,
30
+ log: true,
31
+ })
32
+ const Fraud = await deploy("Fraud", { from: deployer, log: true })
33
+ const MovingFunds = await deploy("MovingFunds", {
34
+ from: deployer,
35
+ log: true,
36
+ })
37
+
38
+ const bridge = await helpers.upgrades.deployProxy("Bridge", {
39
+ contractName:
40
+ process.env.TEST_USE_STUBS_TBTC === "true" ? "BridgeStub" : undefined,
41
+ initializerArgs: [
42
+ Bank.address,
43
+ Relay.address,
44
+ treasury,
45
+ WalletRegistry.address,
46
+ txProofDifficultyFactor,
47
+ ],
48
+ factoryOpts: {
49
+ signer: await ethers.getSigner(deployer),
50
+ libraries: {
51
+ Deposit: Deposit.address,
52
+ DepositSweep: DepositSweep.address,
53
+ Redemption: Redemption.address,
54
+ Wallets: Wallets.address,
55
+ Fraud: Fraud.address,
56
+ MovingFunds: MovingFunds.address,
57
+ },
58
+ },
59
+ proxyOpts: {
60
+ kind: "transparent",
61
+ // Allow external libraries linking. We need to ensure manually that the
62
+ // external libraries we link are upgrade safe, as the OpenZeppelin plugin
63
+ // doesn't perform such a validation yet.
64
+ // See: https://docs.openzeppelin.com/upgrades-plugins/1.x/faq#why-cant-i-use-external-libraries
65
+ unsafeAllow: ["external-library-linking"],
66
+ },
67
+ })
68
+
69
+ if (hre.network.tags.tenderly) {
70
+ await hre.tenderly.verify({
71
+ name: "Bridge",
72
+ address: bridge.address,
73
+ })
74
+ }
75
+ }
76
+
77
+ export default func
78
+
79
+ func.tags = ["Bridge"]
80
+ func.dependencies = ["Bank", "Relay", "Treasury", "WalletRegistry"]
@@ -0,0 +1,30 @@
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 deployments.get("Bank")
10
+ const TBTC = await deployments.get("TBTC")
11
+
12
+ const TBTCVault = await deploy("TBTCVault", {
13
+ contract: "TBTCVault",
14
+ from: deployer,
15
+ args: [Bank.address, TBTC.address],
16
+ log: true,
17
+ })
18
+
19
+ if (hre.network.tags.tenderly) {
20
+ await hre.tenderly.verify({
21
+ name: "TBTCVault",
22
+ address: TBTCVault.address,
23
+ })
24
+ }
25
+ }
26
+
27
+ export default func
28
+
29
+ func.tags = ["TBTCVault"]
30
+ func.dependencies = ["Bank", "TBTC"]
@@ -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"]