Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(WIP)fix: replace light relay with full relay contracts. #301

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions script/Marketplace.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {Script, console2} from "forge-std/Script.sol";
import {BtcMarketPlace} from "../src/swap/Btc_Marketplace.sol";
import {OrdMarketplace} from "../src/swap/Ord_Marketplace.sol";
import {MarketPlace} from "../src/swap/Marketplace.sol";
import {TestLightRelay} from "../src/relay/TestLightRelay.sol";
import {TestFullRelay} from "../src/relay/TestFullRelay.sol";

contract MarketplaceScript is Script {
function setUp() public {}
Expand All @@ -16,7 +16,12 @@ contract MarketplaceScript is Script {

vm.startBroadcast(deployerPrivateKey);

TestLightRelay relay = new TestLightRelay();
// initialize with some dummy values
TestFullRelay relay = new TestFullRelay(
hex"00000020db62962b5989325f30f357762ae456b2ec340432278e14000000000000000000d1dd4e30908c361dfeabfb1e560281c1a270bde3c8719dbda7c848005317594440bf615c886f2e17bd6b082d",
0,
bytes32(0)
);
new BtcMarketPlace(relay, forwarder);
new OrdMarketplace(relay);
new MarketPlace(forwarder);
Expand Down
37 changes: 37 additions & 0 deletions src/relay/TestFullRelay.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
pragma solidity ^0.8.17;

// Forked from https://github.com/keep-network/tbtc-v2

import {BTCUtils} from "@bob-collective/bitcoin-spv/BTCUtils.sol";
import {FullRelay} from "./FullRelay.sol";

/// @title Test Light Relay
/// @notice TestLightRelay is a stub version of LightRelay intended to be
/// used on for testing network. It allows to set the relay's
/// difficulty based on arbitrary Bitcoin headers thus effectively
/// bypass the validation of difficulties of Bitcoin testnet blocks.
/// Since difficulty in Bitcoin testnet often falls to `1` it would not
/// be possible to validate blocks with the real LightRelay.
/// @dev Notice that TestLightRelay is derived from LightRelay so that the two
/// contracts have the same API and correct bindings can be generated.
contract TestFullRelay is FullRelay {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not entirely sure why we need this contract, could you explain?

using BTCUtils for bytes;
using BTCUtils for uint256;

/// @notice Sets the current and previous difficulty based on the difficulty
/// inferred from the provided Bitcoin headers.
function setDifficultyFromHeaders(bytes memory bitcoinHeaders) external {
uint256 firstHeaderDiff = bitcoinHeaders.extractTarget().calculateDifficulty();

currentEpochDiff = firstHeaderDiff;
prevEpochDiff = firstHeaderDiff;
}

/// @notice Constructor for TestFullRelay
/// @param _genesisHeader The starting header
/// @param _height The starting height
/// @param _periodStart The hash of the first header in the genesis epoch
constructor(bytes memory _genesisHeader, uint256 _height, bytes32 _periodStart)
FullRelay(_genesisHeader, _height, _periodStart)
{}
}
20 changes: 10 additions & 10 deletions src/swap/Btc_Marketplace.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {BTCUtils} from "@bob-collective/bitcoin-spv/BTCUtils.sol";
import {BitcoinTx} from "../utils/BitcoinTx.sol";
import {ERC2771Recipient} from "@opengsn/packages/contracts/src/ERC2771Recipient.sol";
import {TestLightRelay} from "../relay/TestLightRelay.sol";
import {TestFullRelay} from "../relay/TestFullRelay.sol";

using SafeERC20 for IERC20;

contract BtcMarketPlace is ERC2771Recipient {
using BitcoinTx for TestLightRelay;
using BitcoinTx for TestFullRelay;

mapping(uint256 => BtcBuyOrder) public btcBuyOrders;
mapping(uint256 => AcceptedBtcBuyOrder) public acceptedBtcBuyOrders;
Expand All @@ -21,17 +21,17 @@ contract BtcMarketPlace is ERC2771Recipient {
uint256 nextOrderId;
uint256 public constant REQUEST_EXPIRATION_SECONDS = 6 hours;

TestLightRelay internal testLightRelay;
TestFullRelay internal testFullRelay;
uint256 internal txProofDifficultyFactor;

constructor(TestLightRelay _relay, address erc2771Forwarder) {
constructor(TestFullRelay _relay, address erc2771Forwarder) {
_setTrustedForwarder(erc2771Forwarder);
setRelay(_relay);
txProofDifficultyFactor = 1;
}

function setRelay(TestLightRelay _relay) internal {
testLightRelay = _relay;
function setRelay(TestFullRelay _relay) internal {
testFullRelay = _relay;
}

// TODO: should we merge buy&sell structs? They're structurally identical except for the
Expand Down Expand Up @@ -162,8 +162,8 @@ contract BtcMarketPlace is ERC2771Recipient {

require(accept.requester == _msgSender());

testLightRelay.setDifficultyFromHeaders(proof.bitcoinHeaders);
testLightRelay.validateProof(txProofDifficultyFactor, transaction, proof);
testFullRelay.setDifficultyFromHeaders(proof.bitcoinHeaders);
testFullRelay.validateProof(txProofDifficultyFactor, transaction, proof);

_checkBitcoinTxOutput(accept.amountBtc, accept.bitcoinAddress, transaction);

Expand Down Expand Up @@ -259,8 +259,8 @@ contract BtcMarketPlace is ERC2771Recipient {

require(accept.accepter == _msgSender());

testLightRelay.setDifficultyFromHeaders(proof.bitcoinHeaders);
testLightRelay.validateProof(txProofDifficultyFactor, transaction, proof);
testFullRelay.setDifficultyFromHeaders(proof.bitcoinHeaders);
testFullRelay.validateProof(txProofDifficultyFactor, transaction, proof);

BtcBuyOrder storage order = btcBuyOrders[accept.orderId];
_checkBitcoinTxOutput(order.amountBtc, order.bitcoinAddress, transaction);
Expand Down
16 changes: 8 additions & 8 deletions src/swap/Ord_Marketplace.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,29 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {BTCUtils} from "@bob-collective/bitcoin-spv/BTCUtils.sol";
import {BitcoinTx} from "../utils/BitcoinTx.sol";
import {TestLightRelay} from "../relay/TestLightRelay.sol";
import {TestFullRelay} from "../relay/TestFullRelay.sol";

using SafeERC20 for IERC20;

contract OrdMarketplace {
using BitcoinTx for TestLightRelay;
using BitcoinTx for TestFullRelay;

mapping(uint256 => OrdinalSellOrder) public ordinalSellOrders;
mapping(uint256 => AcceptedOrdinalSellOrder) public acceptedOrdinalSellOrders;

uint256 nextOrdinalId;
uint256 public constant REQUEST_EXPIRATION_SECONDS = 6 hours;

TestLightRelay internal testLightRelay;
TestFullRelay internal testFullRelay;
uint256 internal txProofDifficultyFactor;

constructor(TestLightRelay _relay) {
constructor(TestFullRelay _relay) {
setRelay(_relay);
txProofDifficultyFactor = 1;
}

function setRelay(TestLightRelay _relay) internal {
testLightRelay = _relay;
function setRelay(TestFullRelay _relay) internal {
testFullRelay = _relay;
}

event placeOrdinalSellOrderEvent(
Expand Down Expand Up @@ -124,8 +124,8 @@ contract OrdMarketplace {

OrdinalSellOrder storage order = ordinalSellOrders[accept.orderId];

testLightRelay.setDifficultyFromHeaders(proof.bitcoinHeaders);
testLightRelay.validateProof(txProofDifficultyFactor, transaction, proof);
testFullRelay.setDifficultyFromHeaders(proof.bitcoinHeaders);
testFullRelay.validateProof(txProofDifficultyFactor, transaction, proof);

BitcoinTx.ensureTxInputSpendsUtxo(transaction.inputVector, order.utxo);

Expand Down
5 changes: 3 additions & 2 deletions src/utils/BitcoinTx.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {BytesLib} from "@bob-collective/bitcoin-spv/BytesLib.sol";
import {ValidateSPV} from "@bob-collective/bitcoin-spv/ValidateSPV.sol";

import {IRelay} from "../relay/IRelay.sol";
import {IFullRelay} from "../relay/FullRelayInterfaces.sol";

/// @title Bitcoin transaction
/// @notice Allows to reference Bitcoin raw transaction in Solidity.
Expand Down Expand Up @@ -144,7 +145,7 @@ library BitcoinTx {
/// @param txInfo Bitcoin transaction data.
/// @param proof Bitcoin proof data.
/// @return txHash Proven 32-byte transaction hash.
function validateProof(IRelay relay, uint256 txProofDifficultyFactor, Info memory txInfo, Proof memory proof)
function validateProof(IFullRelay relay, uint256 txProofDifficultyFactor, Info memory txInfo, Proof memory proof)
internal
view
returns (bytes32 txHash)
Expand Down Expand Up @@ -172,7 +173,7 @@ library BitcoinTx {
/// @param txProofDifficultyFactor The number of confirmations required on the Bitcoin chain.
/// @param bitcoinHeaders Bitcoin headers chain being part of the SPV
/// proof. Used to extract the observed proof difficulty.
function evaluateProofDifficulty(IRelay relay, uint256 txProofDifficultyFactor, bytes memory bitcoinHeaders)
function evaluateProofDifficulty(IFullRelay relay, uint256 txProofDifficultyFactor, bytes memory bitcoinHeaders)
internal
view
{
Expand Down
4 changes: 2 additions & 2 deletions src/utils/WitnessTx.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {SegWitUtils} from "@bob-collective/bitcoin-spv/SegWitUtils.sol";
import {ValidateSPV} from "@bob-collective/bitcoin-spv/ValidateSPV.sol";

import {BitcoinTx} from "./BitcoinTx.sol";
import {IRelay} from "../relay/IRelay.sol";
import {IFullRelay} from "../relay/FullRelayInterfaces.sol";

library WitnessTx {
using BTCUtils for bytes;
Expand Down Expand Up @@ -107,7 +107,7 @@ library WitnessTx {
/// @param proof Bitcoin proof data.
/// @return wTxHash Proven 32-byte transaction hash.
function validateWitnessProofAndDifficulty(
IRelay relay,
IFullRelay relay,
uint256 txProofDifficultyFactor,
WitnessInfo memory txInfo,
WitnessProof memory proof
Expand Down
73 changes: 0 additions & 73 deletions test/LightRelay.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -809,77 +809,4 @@ contract LightRelayTest is Test {
assertEq(current, nextDifficulty);
assertEq(previous, genesisDifficulty);
}

function test_ValidateProof() public view {
uint256 txProofDifficultyFactor = 1;

// txId = 15afe550f468cf0134557533e7f0bd6f210c1a2791d75a8ea57f17c4209448f9
relay.validateProof(
txProofDifficultyFactor,
BitcoinTx.Info({
version: hex"02000000",
inputVector: hex"01123c43f161517343e93191e838b2f04356665ff526bf95cfe6c9986de7a10a3e010000001716001402c8f68bb02b257de42f5ca11b525bd3b47a0369feffffff",
outputVector: hex"02c20d02070000000017a9140ad70885943285fae498b08e00f90ac9e403e1bb8760d360020000000017a914f9b4725bd496b113d44be16f92d14df62096387387",
locktime: hex"76750800"
}),
BitcoinTx.Proof({
merkleProof: hex"180011aff0b64a62d2587d6d1b47d4049b77940222084640d71e3af330f1ed7a463219df439dadf415f9e9e0c3887bf25658ccdd75df8226affdb9e85708c6220f043131ee89dc6b9a2791827a62132348204b681e5801c85ffc5bf8857f1ae481210664933aeb429aeaef433148b9c8deb20ff31189ffcf10e940788897fa2ff4ebf1173c5b7eff6b3cf10e0b55bd59e8375ac1717eb2dc5c0eda687f4d4e3db16ec84a99bbda99dd161e44f8830944e052832d8adc56b73bad0ba280b07d491bf705b5562190e01e49f7dcbe40b35d1f0780f10bd69d5c7b6d5739f46ae6302e37fbe381a82a5a11c5436e6432554b46b93fee53da85109f062fa6e07e070bc2bce25a294949d50baccb0fb46b822d4d203e6784065b233e81f3c52e4ca9a538180159cc5864497e9b2ef9a7412e49d6fb724e13d709b50c1fd97306e255296e77523b15bfd67423e801fb428d40597bbeffda818d15759c9dd89b4bac4e87438fff12f1390e675092e1c8a446347c06026ee2b35f5b140b40b8acbb88ee7d",
txIndexInBlock: 1,
bitcoinHeaders: abi.encodePacked(proofHeader.data)
})
);
}

function test_ValidateProofWithInvalidData() public {
uint256 txProofDifficultyFactor = 1;

// txId = 15afe550f468cf0134557533e7f0bd6f210c1a2791d75a8ea57f17c4209448f9
vm.expectRevert("Invalid input vector provided");
relay.validateProof(
txProofDifficultyFactor,
BitcoinTx.Info({
version: hex"02000000",
// invalid input
inputVector: hex"01123c43f161517343e93191e838b2f04356665ff526bf95cfe6c9986de7a10a3e010000001716001402c8f68bb02b257de42f5ca11b525bd3b25bd3b47a0369feffffff",
outputVector: hex"02c20d02070000000017a9140ad70885943285fae498b08e00f90ac9e403e1bb8760d360020000000017a914f9b4725bd496b113d44be16f92d14df62096387387",
locktime: hex"76750800"
}),
BitcoinTx.Proof({
merkleProof: hex"180011aff0b64a62d2587d6d1b47d4049b77940222084640d71e3af330f1ed7a463219df439dadf415f9e9e0c3887bf25658ccdd75df8226affdb9e85708c6220f043131ee89dc6b9a2791827a62132348204b681e5801c85ffc5bf8857f1ae481210664933aeb429aeaef433148b9c8deb20ff31189ffcf10e940788897fa2ff4ebf1173c5b7eff6b3cf10e0b55bd59e8375ac1717eb2dc5c0eda687f4d4e3db16ec84a99bbda99dd161e44f8830944e052832d8adc56b73bad0ba280b07d491bf705b5562190e01e49f7dcbe40b35d1f0780f10bd69d5c7b6d5739f46ae6302e37fbe381a82a5a11c5436e6432554b46b93fee53da85109f062fa6e07e070bc2bce25a294949d50baccb0fb46b822d4d203e6784065b233e81f3c52e4ca9a538180159cc5864497e9b2ef9a7412e49d6fb724e13d709b50c1fd97306e255296e77523b15bfd67423e801fb428d40597bbeffda818d15759c9dd89b4bac4e87438fff12f1390e675092e1c8a446347c06026ee2b35f5b140b40b8acbb88ee7d",
txIndexInBlock: 1,
bitcoinHeaders: abi.encodePacked(proofHeader.data)
})
);

// Invalid output vector provided ()
vm.expectRevert("Invalid output vector provided");
relay.validateProof(
txProofDifficultyFactor,
BitcoinTx.Info({
version: hex"02000000",
inputVector: hex"01123c43f161517343e93191e838b2f04356665ff526bf95cfe6c9986de7a10a3e010000001716001402c8f68bb02b257de42f5ca11b525bd3b47a0369feffffff",
// invalid output
outputVector: hex"0285943285fae498b08e00f90ac9e403e1bb8760d360020000000017a914f9b4725bd496b113d44be16f92d14df62096387387",
locktime: hex"76750800"
}),
BitcoinTx.Proof({
merkleProof: hex"180011aff0b64a62d2587d6d1b47d4049b77940222084640d71e3af330f1ed7a463219df439dadf415f9e9e0c3887bf25658ccdd75df8226affdb9e85708c6220f043131ee89dc6b9a2791827a62132348204b681e5801c85ffc5bf8857f1ae481210664933aeb429aeaef433148b9c8deb20ff31189ffcf10e940788897fa2ff4ebf1173c5b7eff6b3cf10e0b55bd59e8375ac1717eb2dc5c0eda687f4d4e3db16ec84a99bbda99dd161e44f8830944e052832d8adc56b73bad0ba280b07d491bf705b5562190e01e49f7dcbe40b35d1f0780f10bd69d5c7b6d5739f46ae6302e37fbe381a82a5a11c5436e6432554b46b93fee53da85109f062fa6e07e070bc2bce25a294949d50baccb0fb46b822d4d203e6784065b233e81f3c52e4ca9a538180159cc5864497e9b2ef9a7412e49d6fb724e13d709b50c1fd97306e255296e77523b15bfd67423e801fb428d40597bbeffda818d15759c9dd89b4bac4e87438fff12f1390e675092e1c8a446347c06026ee2b35f5b140b40b8acbb88ee7d",
txIndexInBlock: 1,
bitcoinHeaders: abi.encodePacked(proofHeader.data)
})
);

vm.expectRevert("Insufficient accumulated difficulty in header chain");
relay.evaluateProofDifficulty(
txProofDifficultyFactor,
// header difficult is 1 but expected difficult is 2
abi.encodePacked(proofHeader.data)
);
}

function test_EvaluateProofDifficulty() public view {
uint256 txProofDifficultyFactor = 1;

relay.evaluateProofDifficulty(txProofDifficultyFactor, abi.encodePacked(proofHeader.data));
}
}
17 changes: 11 additions & 6 deletions test/swap/Btc_Marketplace.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ using stdStorage for StdStorage;

import {ERC20} from "openzeppelin-contracts/token/ERC20/ERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {stdStorage, StdStorage, Test, console} from "forge-std/Test.sol";
import {stdStorage, StdStorage, Test, console2, console} from "forge-std/Test.sol";
import {BtcMarketPlace} from "../../src/swap/Btc_Marketplace.sol";
import {Utilities} from "./Utilities.sol";
import {BitcoinTx} from "../../src/utils/BitcoinTx.sol";
import {TestLightRelay} from "../../src/relay/TestLightRelay.sol";
import {TestFullRelay} from "../../src/relay/TestFullRelay.sol";
import {FullRelayTestUtils} from "../fullRelay/FullRelayTestUtils.sol";

contract ArbitaryErc20 is ERC20, Ownable {
constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) {}
Expand All @@ -27,7 +28,7 @@ contract MarketPlaceTest is BtcMarketPlace, Test {

ArbitaryErc20 token1;

constructor() BtcMarketPlace(testLightRelay, address(0x00)) {}
constructor() BtcMarketPlace(testFullRelay, address(0x00)) {}

function setUp() public {
utils = new Utilities();
Expand All @@ -40,8 +41,12 @@ contract MarketPlaceTest is BtcMarketPlace, Test {

token1 = new ArbitaryErc20("Some token", "TKN");

testLightRelay = new TestLightRelay();
super.setRelay(testLightRelay);
testFullRelay = new TestFullRelay(
hex"00000020db62962b5989325f30f357762ae456b2ec340432278e14000000000000000000d1dd4e30908c361dfeabfb1e560281c1a270bde3c8719dbda7c848005317594440bf615c886f2e17bd6b082d",
0,
bytes32(0)
);
super.setRelay(testFullRelay);
}

function dummyTransaction() public pure returns (BitcoinTx.Info memory) {
Expand All @@ -60,7 +65,7 @@ contract MarketPlaceTest is BtcMarketPlace, Test {
bitcoinHeaders: abi.encodePacked(
hex"04000000e0879a33a87bf9481385adae91fa9e93713b932cbe8a09030000000000000000ee5ded948d805bb71bee5de25b447c42527898cac93eee1afe04663bb8204b358627fe56f4960618304a7db1",
hex"04000000c0de92e7326cb020b59ffc5998405e539863c57da088a7040000000000000000d8e7273d0198ba4f10dfd57d151327c32113fc244fd0587d161a5c5332a53651ed28fe56f4960618b24502cc"
)
)
});
}

Expand Down
Loading
Loading