-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Don't return awaited promise in getUnnamedSigner
Fix `@typescript-eslint/return-await` error returned by eslint.
- Loading branch information
Showing
14 changed files
with
9,115 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
// SPDX-License-Identifier: GPL-3.0-only | ||
pragma solidity ^0.8.21; | ||
|
||
import {BTCUtils} from "@keep-network/bitcoin-spv-sol/contracts/BTCUtils.sol"; | ||
|
||
import "./Acre.sol"; | ||
|
||
import "hardhat/console.sol"; | ||
|
||
interface IBridge { | ||
struct BitcoinTxInfo { | ||
bytes4 version; | ||
bytes inputVector; | ||
bytes outputVector; | ||
bytes4 locktime; | ||
} | ||
|
||
struct DepositRevealInfo { | ||
uint32 fundingOutputIndex; | ||
bytes8 blindingFactor; | ||
bytes20 walletPubKeyHash; | ||
bytes20 refundPubKeyHash; | ||
bytes4 refundLocktime; | ||
address vault; | ||
bytes32 depositorExtraData; | ||
} | ||
|
||
struct DepositRequest { | ||
address depositor; | ||
uint64 amount; | ||
uint32 revealedAt; | ||
address vault; | ||
uint64 treasuryFee; | ||
uint32 sweptAt; | ||
bytes32 depositorExtraData; | ||
} | ||
|
||
function revealDepositWithExtraData( | ||
BitcoinTxInfo calldata fundingTx, | ||
DepositRevealInfo calldata reveal | ||
) external; | ||
|
||
function deposits( | ||
uint256 depositKey | ||
) external view returns (DepositRequest memory); | ||
} | ||
|
||
interface ITBTCVault { | ||
struct OptimisticMintingRequest { | ||
// UNIX timestamp at which the optimistic minting was requested. | ||
uint64 requestedAt; | ||
// UNIX timestamp at which the optimistic minting was finalized. | ||
// 0 if not yet finalized. | ||
uint64 finalizedAt; | ||
// TODO: This field is not included in the original struct. It would require upgrade. | ||
uint256 optimisticMintFee; | ||
} | ||
|
||
function optimisticMintingRequests( | ||
uint256 depositKey | ||
) external returns (OptimisticMintingRequest memory); | ||
} | ||
|
||
// Extra Data 32 byte | ||
// receiver - address - 20 byte | ||
// referral - uint16 - 2 byte | ||
|
||
contract TbtcDepositor { | ||
// TODO: Do we need to import it? | ||
using BTCUtils for bytes; | ||
|
||
IBridge public bridge; | ||
ITBTCVault public tbtcVault; | ||
Acre public acre; | ||
|
||
struct DepositRequest { | ||
// UNIX timestamp at which the optimistic minting was requested. | ||
uint64 requestedAt; | ||
// UNIX timestamp at which the optimistic minting was finalized. | ||
// 0 if not yet finalized. | ||
uint64 finalizedAt; | ||
} | ||
|
||
mapping(uint256 => DepositRequest) public depositRequests; | ||
|
||
constructor(IBridge _bridge, ITBTCVault _tbtcVault, Acre _acre) { | ||
bridge = _bridge; | ||
tbtcVault = _tbtcVault; | ||
acre = _acre; | ||
} | ||
|
||
// TODO: Implement | ||
function initializeDeposit( | ||
IBridge.BitcoinTxInfo calldata fundingTx, | ||
IBridge.DepositRevealInfo calldata reveal | ||
) external { | ||
bytes32 fundingTxHash = abi | ||
.encodePacked( | ||
fundingTx.version, | ||
fundingTx.inputVector, | ||
fundingTx.outputVector, | ||
fundingTx.locktime | ||
) | ||
.hash256View(); | ||
|
||
DepositRequest storage request = depositRequests[ | ||
calculateDepositKey(fundingTxHash, reveal.fundingOutputIndex) | ||
]; | ||
|
||
// TODO: Replace with custom errors | ||
require(request.requestedAt == 0, "deposit already initialized"); | ||
request.requestedAt = uint64(block.timestamp); | ||
|
||
bridge.revealDepositWithExtraData(fundingTx, reveal); | ||
} | ||
|
||
function finalizeDeposit( | ||
bytes32 fundingTxHash, | ||
uint32 fundingOutputIndex | ||
) external { | ||
uint256 depositKey = calculateDepositKey( | ||
fundingTxHash, | ||
fundingOutputIndex | ||
); | ||
DepositRequest storage request = depositRequests[depositKey]; | ||
|
||
require(request.requestedAt > 0, "deposit not initialized"); | ||
require(request.finalizedAt == 0, "deposit already finalized"); | ||
|
||
ITBTCVault.OptimisticMintingRequest | ||
memory optimisticMintingRequest = tbtcVault | ||
.optimisticMintingRequests(depositKey); | ||
|
||
IBridge.DepositRequest memory bridgeDepositRequest = bridge.deposits( | ||
depositKey | ||
); | ||
|
||
uint256 amount= bridgeDepositRequest.amount - bridgeDepositRequest.treasuryFee; | ||
if (optimisticMintingRequest.requestedAt > 0) { | ||
require( | ||
optimisticMintingRequest.finalizedAt > 0, | ||
"optimistic minting not yet finalized" | ||
); | ||
amount -= optimisticMintingRequest.optimisticMintFee; | ||
} else { | ||
require( | ||
bridgeDepositRequest.sweptAt > 0, | ||
"tbtc deposit not yet swept" | ||
); | ||
} | ||
|
||
request.finalizedAt = uint64(block.timestamp); | ||
|
||
// TODO: Consider decoding inline | ||
(address receiver, uint16 referral) = decodeExtraData( | ||
bridgeDepositRequest.depositorExtraData | ||
); | ||
|
||
IERC20(acre.asset()).approve(address(acre), amount); | ||
|
||
// acre.stake(amount, receiver, referral); | ||
} | ||
|
||
/// @notice Calculates deposit key the same way as the Bridge contract. | ||
/// The deposit key is computed as | ||
/// `keccak256(fundingTxHash | fundingOutputIndex)`. | ||
function calculateDepositKey( | ||
bytes32 fundingTxHash, | ||
uint32 fundingOutputIndex | ||
) public pure returns (uint256) { | ||
return | ||
uint256( | ||
keccak256(abi.encodePacked(fundingTxHash, fundingOutputIndex)) | ||
); | ||
} | ||
|
||
function decodeExtraData( | ||
bytes32 extraData | ||
) public pure returns (address receiver, uint16 referral) { | ||
// First 20 bytes of extra data is receiver address. | ||
receiver = address(uint160(bytes20(extraData))); | ||
// Next 2 bytes of extra data is referral info. | ||
referral = uint16(bytes2(extraData << (8 * 20))); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// SPDX-License-Identifier: GPL-3.0-only | ||
pragma solidity ^0.8.21; | ||
|
||
import {BTCUtils} from "@keep-network/bitcoin-spv-sol/contracts/BTCUtils.sol"; | ||
import {IBridge} from "../TbtcDepositor.sol"; | ||
|
||
contract BridgeStub is IBridge { | ||
using BTCUtils for bytes; | ||
|
||
mapping(uint256 => DepositRequest) dep; | ||
|
||
uint64 depositTreasuryFeeDivisor = 2000; // 0.05% | ||
|
||
function revealDepositWithExtraData( | ||
BitcoinTxInfo calldata fundingTx, | ||
DepositRevealInfo calldata reveal | ||
) external { | ||
bytes32 fundingTxHash = abi | ||
.encodePacked( | ||
fundingTx.version, | ||
fundingTx.inputVector, | ||
fundingTx.outputVector, | ||
fundingTx.locktime | ||
) | ||
.hash256View(); | ||
|
||
DepositRequest storage deposit = dep[ | ||
calculateDepositKey(fundingTxHash, reveal.fundingOutputIndex) | ||
]; | ||
|
||
require(deposit.revealedAt == 0, "Deposit already revealed"); | ||
|
||
bytes memory fundingOutput = fundingTx | ||
.outputVector | ||
.extractOutputAtIndex(reveal.fundingOutputIndex); | ||
|
||
uint64 fundingOutputAmount = fundingOutput.extractValue(); | ||
|
||
deposit.amount = fundingOutputAmount; | ||
deposit.depositor = msg.sender; | ||
/* solhint-disable-next-line not-rely-on-time */ | ||
deposit.revealedAt = uint32(block.timestamp); | ||
deposit.vault = reveal.vault; | ||
deposit.treasuryFee = depositTreasuryFeeDivisor > 0 | ||
? fundingOutputAmount / depositTreasuryFeeDivisor | ||
: 0; | ||
deposit.depositorExtraData = reveal.depositorExtraData; | ||
} | ||
|
||
function deposits( | ||
uint256 depositKey | ||
) external view returns (DepositRequest memory) { | ||
return dep[depositKey]; | ||
} | ||
|
||
function sweep(bytes32 fundingTxHash, uint32 fundingOutputIndex) public { | ||
DepositRequest storage deposit = dep[ | ||
calculateDepositKey(fundingTxHash, fundingOutputIndex) | ||
]; | ||
|
||
deposit.sweptAt = uint32(block.timestamp); | ||
|
||
// TODO: Mint TBTC | ||
} | ||
|
||
function calculateDepositKey( | ||
bytes32 fundingTxHash, | ||
uint32 fundingOutputIndex | ||
) public pure returns (uint256) { | ||
return | ||
uint256( | ||
keccak256(abi.encodePacked(fundingTxHash, fundingOutputIndex)) | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// SPDX-License-Identifier: GPL-3.0-only | ||
pragma solidity ^0.8.21; | ||
import {ITBTCVault} from "../TbtcDepositor.sol"; | ||
|
||
contract TBTCVaultStub is ITBTCVault { | ||
uint32 public optimisticMintingFeeDivisor = 500; // 1/500 = 0.002 = 0.2% | ||
|
||
// request.optimisticMintFee = optimisticMintingFeeDivisor > 0 | ||
// ? (amountToMint / optimisticMintingFeeDivisor) | ||
// : 0; | ||
|
||
function optimisticMintingRequests( | ||
uint256 depositKey | ||
) external returns (OptimisticMintingRequest memory) { | ||
OptimisticMintingRequest memory result; | ||
return result; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
// SPDX-License-Identifier: GPL-3.0-only | ||
pragma solidity ^0.8.21; | ||
|
||
import "../Acre.sol"; | ||
import "./TestERC20.sol"; | ||
|
||
// interface IBridge { | ||
// struct BitcoinTxInfo { | ||
// bytes4 version; | ||
// bytes inputVector; | ||
// bytes outputVector; | ||
// bytes4 locktime; | ||
// } | ||
|
||
// struct DepositRevealInfo { | ||
// uint32 fundingOutputIndex; | ||
// bytes8 blindingFactor; | ||
// bytes20 walletPubKeyHash; | ||
// bytes20 refundPubKeyHash; | ||
// bytes4 refundLocktime; | ||
// address vault; | ||
// bytes32 depositorExtraData; | ||
// } | ||
|
||
// function revealDepositWithExtraData( | ||
// BitcoinTxInfo calldata fundingTx, | ||
// DepositRevealInfo calldata reveal | ||
// ) external; | ||
// } | ||
|
||
contract AcreDepositor { | ||
// IBridge bridge; | ||
// Acre acre; | ||
// TestERC20 tbtc; | ||
|
||
// struct DepositRequest { | ||
// // UNIX timestamp at which the optimistic minting was requested. | ||
// uint64 requestedAt; | ||
// // UNIX timestamp at which the optimistic minting was finalized. | ||
// // 0 if not yet finalized. | ||
// uint64 finalizedAt; | ||
// } | ||
|
||
// mapping(uint256 => DepositRequest) public depositRequests; | ||
|
||
// constructor(IBridge _bridge, Acre _acre, TestERC20 _tbtc) { | ||
// bridge = _bridge; | ||
// acre = _acre; | ||
// } | ||
|
||
// function revealDeposit( | ||
// IBridge.BitcoinTxInfo calldata fundingTx, | ||
// IBridge.DepositRevealInfo calldata reveal | ||
// ) external {} | ||
|
||
// function stake( | ||
// bytes32 fundingTxHash, | ||
// uint32 fundingOutputIndex, | ||
// address receiver, | ||
// bytes32 referral | ||
// ) { | ||
// // acre.stake(assets, receiver, referral); | ||
// } | ||
|
||
// /// @notice Calculates deposit key the same way as the Bridge contract. | ||
// /// The deposit key is computed as | ||
// /// `keccak256(fundingTxHash | fundingOutputIndex)`. | ||
// function calculateDepositKey( | ||
// bytes32 fundingTxHash, | ||
// uint32 fundingOutputIndex | ||
// ) public pure returns (uint256) { | ||
// return | ||
// uint256( | ||
// keccak256(abi.encodePacked(fundingTxHash, fundingOutputIndex)) | ||
// ); | ||
// } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import type { DeployFunction } from "hardhat-deploy/types" | ||
import type { | ||
HardhatNetworkConfig, | ||
HardhatRuntimeEnvironment, | ||
} from "hardhat/types" | ||
import { isNonZeroAddress } from "../helpers/address" | ||
|
||
const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { | ||
const { getNamedAccounts, deployments } = hre | ||
const { log } = deployments | ||
const { deployer } = await getNamedAccounts() | ||
|
||
console.log("network", hre.network.name) | ||
|
||
const bridge = await deployments.getOrNull("Bridge") | ||
|
||
console.log("bridge", await deployments.all()) | ||
|
||
if (bridge && isNonZeroAddress(bridge.address)) { | ||
log(`using Bridge contract at ${bridge.address}`) | ||
} else if ( | ||
!hre.network.tags.allowStubs || | ||
(hre.network.config as HardhatNetworkConfig)?.forking?.enabled | ||
) { | ||
throw new Error("deployed Bridge contract not found") | ||
} else { | ||
log("deploying Bridge contract stub") | ||
await deployments.deploy("Bridge", { | ||
contract: "BridgeStub", | ||
from: deployer, | ||
log: true, | ||
waitConfirmations: 1, | ||
}) | ||
} | ||
} | ||
|
||
export default func | ||
|
||
func.tags = ["TBTC"] |
Oops, something went wrong.