Skip to content

Commit

Permalink
Tweaks to AbstractTBTCDepositor contract (#779)
Browse files Browse the repository at this point in the history
In this PR I propose some modifications to the initial implementation of
`AbstractTBTCDepositor` contract
(#778).

### Return initial deposit amount from _initializeDeposit function

Integrators may be interested in adding more fees to the deposit amount.
For this reason, it may be cleanest to calculate it based on the initial
deposit amount. By returning the value here they will avoid the need to
read the funding deposit amount from the storage again.

### Mock contracts tweaks

I added modifications to the MockBridge and MockTBTCVault contracts,
that were useful in tests of the integrator's implementation
(thesis/acre#91).
  • Loading branch information
lukasz-zimnoch authored Feb 2, 2024
2 parents dd4bd02 + 106aed5 commit 301497d
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 22 deletions.
1 change: 1 addition & 0 deletions solidity/.nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lts/hydrogen
19 changes: 16 additions & 3 deletions solidity/contracts/integrator/AbstractTBTCDepositor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ import "./ITBTCVault.sol";
/// }
///
/// function finalizeProcess(uint256 depositKey) external {
/// (uint256 tbtcAmount, bytes32 extraData) = _finalizeDeposit(depositKey);
/// (
/// uint256 initialDepositAmount,
/// uint256 tbtcAmount,
/// bytes32 extraData
/// ) = _finalizeDeposit(depositKey);
///
/// // Do something with the minted TBTC using context
/// // embedded in the extraData.
Expand Down Expand Up @@ -166,7 +170,10 @@ abstract contract AbstractTBTCDepositor {
/// @notice Finalizes a deposit by calculating the amount of TBTC minted
/// for the deposit
/// @param depositKey Deposit key identifying the deposit.
/// @return tbtcAmount Approximate amount of TBTC minted for the deposit.
/// @return initialDepositAmount Amount of funding transaction deposit. In
/// TBTC token decimals precision.
/// @return tbtcAmount Approximate amount of TBTC minted for the deposit. In
/// TBTC token decimals precision.
/// @return extraData 32-byte deposit extra data.
/// @dev Requirements:
/// - The deposit must be initialized but not finalized
Expand All @@ -179,7 +186,11 @@ abstract contract AbstractTBTCDepositor {
// slither-disable-next-line dead-code
function _finalizeDeposit(uint256 depositKey)
internal
returns (uint256 tbtcAmount, bytes32 extraData)
returns (
uint256 initialDepositAmount,
uint256 tbtcAmount,
bytes32 extraData
)
{
require(pendingDeposits[depositKey], "Deposit not initialized");

Expand All @@ -203,6 +214,8 @@ abstract contract AbstractTBTCDepositor {
// slither-disable-next-line reentrancy-no-eth
delete pendingDeposits[depositKey];

initialDepositAmount = deposit.amount * SATOSHI_MULTIPLIER;

tbtcAmount = _calculateTbtcAmount(deposit.amount, deposit.treasuryFee);

// slither-disable-next-line reentrancy-events
Expand Down
41 changes: 33 additions & 8 deletions solidity/contracts/test/TestTBTCDepositor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ import "../integrator/ITBTCVault.sol";
contract TestTBTCDepositor is AbstractTBTCDepositor {
event InitializeDepositReturned(uint256 depositKey);

event FinalizeDepositReturned(uint256 tbtcAmount, bytes32 extraData);
event FinalizeDepositReturned(
uint256 initialDepositAmount,
uint256 tbtcAmount,
bytes32 extraData
);

function initialize(address _bridge, address _tbtcVault) external {
__AbstractTBTCDepositor_initialize(_bridge, _tbtcVault);
Expand All @@ -27,8 +31,16 @@ contract TestTBTCDepositor is AbstractTBTCDepositor {
}

function finalizeDepositPublic(uint256 depositKey) external {
(uint256 tbtcAmount, bytes32 extraData) = _finalizeDeposit(depositKey);
emit FinalizeDepositReturned(tbtcAmount, extraData);
(
uint256 initialDepositAmount,
uint256 tbtcAmount,
bytes32 extraData
) = _finalizeDeposit(depositKey);
emit FinalizeDepositReturned(
initialDepositAmount,
tbtcAmount,
extraData
);
}

function calculateTbtcAmountPublic(
Expand All @@ -44,7 +56,8 @@ contract MockBridge is IBridge {

mapping(uint256 => IBridgeTypes.DepositRequest) internal _deposits;

uint64 internal _depositTxMaxFee = 1 * 1e7; // 0.1 BTC
uint64 internal _depositTreasuryFeeDivisor = 50; // 1/50 == 100 bps == 2% == 0.02
uint64 internal _depositTxMaxFee = 1000; // 1000 satoshi = 0.00001 BTC

event DepositRevealed(uint256 depositKey);

Expand Down Expand Up @@ -73,14 +86,22 @@ contract MockBridge is IBridge {
"Deposit already revealed"
);

bytes memory fundingOutput = fundingTx
.outputVector
.extractOutputAtIndex(reveal.fundingOutputIndex);

uint64 fundingOutputAmount = fundingOutput.extractValue();

IBridgeTypes.DepositRequest memory request;

request.depositor = msg.sender;
request.amount = uint64(10 * 1e8); // 10 BTC
request.amount = fundingOutputAmount;
/* solhint-disable-next-line not-rely-on-time */
request.revealedAt = uint32(block.timestamp);
request.vault = reveal.vault;
request.treasuryFee = uint64(1 * 1e8); // 1 BTC
request.treasuryFee = _depositTreasuryFeeDivisor > 0
? fundingOutputAmount / _depositTreasuryFeeDivisor
: 0;
request.sweptAt = 0;
request.extraData = extraData;

Expand All @@ -89,7 +110,7 @@ contract MockBridge is IBridge {
emit DepositRevealed(depositKey);
}

function sweepDeposit(uint256 depositKey) external {
function sweepDeposit(uint256 depositKey) public {
require(_deposits[depositKey].revealedAt != 0, "Deposit not revealed");
require(_deposits[depositKey].sweptAt == 0, "Deposit already swept");
/* solhint-disable-next-line not-rely-on-time */
Expand Down Expand Up @@ -120,6 +141,10 @@ contract MockBridge is IBridge {
depositRevealAheadPeriod = 0;
}

function setDepositTreasuryFeeDivisor(uint64 value) external {
_depositTreasuryFeeDivisor = value;
}

function setDepositTxMaxFee(uint64 value) external {
_depositTxMaxFee = value;
}
Expand Down Expand Up @@ -152,7 +177,7 @@ contract MockTBTCVault is ITBTCVault {
_requests[depositKey].requestedAt = uint64(block.timestamp);
}

function finalizeOptimisticMintingRequest(uint256 depositKey) external {
function finalizeOptimisticMintingRequest(uint256 depositKey) public {
require(
_requests[depositKey].requestedAt != 0,
"Request does not exist"
Expand Down
42 changes: 31 additions & 11 deletions solidity/test/integrator/AbstractTBTCDepositor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,13 +213,14 @@ describe("AbstractTBTCDepositor", () => {
context("when deposit is finalized by the Bridge", () => {
// The expected tbtcAmount is calculated as follows:
//
// - Deposit amount = 10 BTC (hardcoded in MockBridge)
// - Treasury fee = 1 BTC (hardcoded in MockBridge)
// - Optimistic minting fee = 1% (default value used in MockTBTCVault)
// - Transaction max fee = 0.1 BTC (default value used in MockBridge)
// - Deposit amount = 10000 satoshi (hardcoded in funding transaction fixture)
// - Treasury fee = 2% (default value used in MockBridge)
// - Optimistic minting fee = 1% (default value used in MockTBTCVault)
// - Transaction max fee = 1000 satoshi (default value used in MockBridge)
//
// ((10 BTC - 1 BTC) * 0.99) - 0.1 BTC = 8.81 BTC = 8.81 * 1e8 sat = 8.81 * 1e18 TBTC
const expectedTbtcAmount = to1ePrecision(881, 16).toString()
// ((10000 sat - 200 sat) * 0.99) - 2000 sat = 8702 sat = 8702 * 1e10 TBTC
const expectedInitialDepositAmount = to1ePrecision(10000, 10)
const expectedTbtcAmount = to1ePrecision(8702, 10).toString()

context("when the deposit is swept", () => {
let tx: ContractTransaction
Expand Down Expand Up @@ -257,7 +258,11 @@ describe("AbstractTBTCDepositor", () => {
it("should return proper values", async () => {
await expect(tx)
.to.emit(depositor, "FinalizeDepositReturned")
.withArgs(expectedTbtcAmount, fixture.extraData)
.withArgs(
expectedInitialDepositAmount,
expectedTbtcAmount,
fixture.extraData
)
})
})

Expand Down Expand Up @@ -303,14 +308,29 @@ describe("AbstractTBTCDepositor", () => {
it("should return proper values", async () => {
await expect(tx)
.to.emit(depositor, "FinalizeDepositReturned")
.withArgs(expectedTbtcAmount, fixture.extraData)
.withArgs(
expectedInitialDepositAmount,
expectedTbtcAmount,
fixture.extraData
)
})
})
})
})
})

describe("_calculateTbtcAmount", () => {
before(async () => {
await createSnapshot()

// Set the transaction max fee to 0.1 BTC.
await bridge.setDepositTxMaxFee(10000000)
})

after(async () => {
await restoreSnapshot()
})

context("when all fees are non-zero", () => {
it("should return the correct amount", async () => {
const depositAmount = to1ePrecision(10, 8) // 10 BTC
Expand All @@ -321,7 +341,7 @@ describe("AbstractTBTCDepositor", () => {
// - Deposit amount = 10 BTC
// - Treasury fee = 1 BTC
// - Optimistic minting fee = 1% (default value used in MockTBTCVault)
// - Transaction max fee = 0.1 BTC (default value used in MockBridge)
// - Transaction max fee = 0.1 BTC (set in MockBridge)
//
// ((10 BTC - 1 BTC) * 0.99) - 0.1 BTC = 8.81 BTC = 8.81 * 1e8 sat = 8.81 * 1e18 TBTC
const expectedTbtcAmount = to1ePrecision(881, 16)
Expand Down Expand Up @@ -377,7 +397,7 @@ describe("AbstractTBTCDepositor", () => {
// - Deposit amount = 10 BTC
// - Treasury fee = 0 BTC
// - Optimistic minting fee = 1% (default value used in MockTBTCVault)
// - Transaction max fee = 0.1 BTC (default value used in MockBridge)
// - Transaction max fee = 0.1 BTC (set in MockBridge)
//
// ((10 BTC - 0 BTC) * 0.99) - 0.1 BTC = 9.8 BTC = 9.8 * 1e8 sat = 9.8 * 1e18 TBTC
const expectedTbtcAmount = to1ePrecision(98, 17)
Expand Down Expand Up @@ -412,7 +432,7 @@ describe("AbstractTBTCDepositor", () => {
// - Deposit amount = 10 BTC
// - Treasury fee = 1 BTC
// - Optimistic minting fee = 0% (set in MockTBTCVault)
// - Transaction max fee = 0.1 BTC (default value used in MockBridge)
// - Transaction max fee = 0.1 BTC (set in MockBridge)
//
// ((10 BTC - 1 BTC) * 1) - 0.1 BTC = 8.9 BTC = 8.9 * 1e8 sat = 8.9 * 1e18 TBTC
const expectedTbtcAmount = to1ePrecision(89, 17)
Expand Down

0 comments on commit 301497d

Please sign in to comment.