diff --git a/script/Marketplace.sol b/script/Marketplace.sol index b6831e90..abac7b0d 100644 --- a/script/Marketplace.sol +++ b/script/Marketplace.sol @@ -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 {} @@ -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); diff --git a/src/relay/TestFullRelay.sol b/src/relay/TestFullRelay.sol new file mode 100644 index 00000000..a9cfb243 --- /dev/null +++ b/src/relay/TestFullRelay.sol @@ -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 { + 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) + {} +} diff --git a/src/swap/Btc_Marketplace.sol b/src/swap/Btc_Marketplace.sol index 3070999b..3faad2d9 100644 --- a/src/swap/Btc_Marketplace.sol +++ b/src/swap/Btc_Marketplace.sol @@ -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; @@ -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 @@ -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); @@ -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); diff --git a/src/swap/Ord_Marketplace.sol b/src/swap/Ord_Marketplace.sol index ec3c5c0a..a873922a 100644 --- a/src/swap/Ord_Marketplace.sol +++ b/src/swap/Ord_Marketplace.sol @@ -5,12 +5,12 @@ 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; @@ -18,16 +18,16 @@ contract OrdMarketplace { 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( @@ -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); diff --git a/src/utils/BitcoinTx.sol b/src/utils/BitcoinTx.sol index 796374de..dd942a1e 100644 --- a/src/utils/BitcoinTx.sol +++ b/src/utils/BitcoinTx.sol @@ -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. @@ -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) @@ -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 { diff --git a/src/utils/WitnessTx.sol b/src/utils/WitnessTx.sol index a7556f0b..eb4cff59 100644 --- a/src/utils/WitnessTx.sol +++ b/src/utils/WitnessTx.sol @@ -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; @@ -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 diff --git a/test/LightRelay.t.sol b/test/LightRelay.t.sol index 4a6d1331..c37c0db2 100644 --- a/test/LightRelay.t.sol +++ b/test/LightRelay.t.sol @@ -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)); - } } diff --git a/test/swap/Btc_Marketplace.t.sol b/test/swap/Btc_Marketplace.t.sol index 5cd8adad..0517538b 100644 --- a/test/swap/Btc_Marketplace.t.sol +++ b/test/swap/Btc_Marketplace.t.sol @@ -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_) {} @@ -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(); @@ -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) { @@ -60,7 +65,7 @@ contract MarketPlaceTest is BtcMarketPlace, Test { bitcoinHeaders: abi.encodePacked( hex"04000000e0879a33a87bf9481385adae91fa9e93713b932cbe8a09030000000000000000ee5ded948d805bb71bee5de25b447c42527898cac93eee1afe04663bb8204b358627fe56f4960618304a7db1", hex"04000000c0de92e7326cb020b59ffc5998405e539863c57da088a7040000000000000000d8e7273d0198ba4f10dfd57d151327c32113fc244fd0587d161a5c5332a53651ed28fe56f4960618b24502cc" - ) + ) }); } diff --git a/test/swap/Ord_Marketplace.t.sol b/test/swap/Ord_Marketplace.t.sol index 01f72244..6ec54568 100644 --- a/test/swap/Ord_Marketplace.t.sol +++ b/test/swap/Ord_Marketplace.t.sol @@ -9,7 +9,7 @@ import {stdStorage, StdStorage, Test, 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 "../../src/swap/Ord_Marketplace.sol"; contract ArbitaryErc20 is ERC20, Ownable { @@ -38,7 +38,7 @@ contract OrdMarketPlaceTest is OrdMarketplace, Test { Ordinal[3] ordinalsInfo; - constructor() OrdMarketplace(testLightRelay) { + constructor() OrdMarketplace(testFullRelay) { // data from testnet // https://btc-testnet.gobob.xyz/tx/c872fb11bbca1241aced71c692e7d0b0cf46aadb390ce66ddfcf5fbd8e5bc26f BitcoinTx.Info memory info = BitcoinTx.Info({ @@ -53,7 +53,7 @@ contract OrdMarketPlaceTest is OrdMarketplace, Test { txIndexInBlock: 4, bitcoinHeaders: abi.encodePacked( hex"00a00020a672b6254445e7b2dd6e5433f52ea9596e6ce51776fa6ea66d0200000000000013d7683b2bfc7d7cde91c6792f62e6b9453ca2f1e72cdbf106ecabf767dd2ac5bcf98f628886021ac954f84d" - ) + ) }); BitcoinTx.UTXO memory utxo; @@ -82,7 +82,7 @@ contract OrdMarketPlaceTest is OrdMarketplace, Test { txIndexInBlock: 25, bitcoinHeaders: abi.encodePacked( hex"00200020b70169ce36e45282d9e32c6b3cf815c4580872c94d7801000000000000000000a9bb880a70ef5e045fa684064c5229fb1c540a799e2bdb71efde06304a26de4dc2c77a65952e0417d2418bf4" - ) + ) }); BitcoinTx.UTXO memory utxo2; @@ -111,7 +111,7 @@ contract OrdMarketPlaceTest is OrdMarketplace, Test { txIndexInBlock: 72, bitcoinHeaders: abi.encodePacked( hex"0000002019ecad2d640319bad3cbe99dd2819fdba90023ccd6a479d31400000000000000f308f7de96bab7e11e64fdb06000e57806b7791b923cf0e8382547d3c609f2bf65438165ffff001d84cd32400000e0201a1e9727a2da2e112c761a0d3aa639c52e9b43c1e9d80bb0242632240000000056f577d01fbd2550679ced5da24291ec48bbb96a93f790349ac2f54fa075f90c64448165efdf2819529ec2d8" - ) + ) }); // https://mempool.space/testnet/tx/6e21808d026c3bca141825b3e684f2d11eb148a8cdf9c7e01e832fd3cede732c @@ -141,8 +141,12 @@ contract OrdMarketPlaceTest is OrdMarketplace, 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 test_OrdinalSellOrderFullFlow() public {