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

test: darkpool: SettleAtomicMatch: Add native asset tests #67

Merged
merged 2 commits into from
Mar 9, 2025
Merged
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
23 changes: 14 additions & 9 deletions src/Darkpool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import { PlonkProof, VerificationKey, NUM_SELECTORS, NUM_WIRE_TYPES } from "./li
import { BN254 } from "solidity-bn254/BN254.sol";
import { VerifierCore } from "./libraries/verifier/VerifierCore.sol";
import { VerificationKeys } from "./libraries/darkpool/VerificationKeys.sol";
import { IHasher } from "./libraries/poseidon2/IHasher.sol";
import { IVerifier } from "./libraries/verifier/IVerifier.sol";
import { IHasher } from "./libraries/interfaces/IHasher.sol";
import { IVerifier } from "./libraries/interfaces/IVerifier.sol";
import { IWETH9 } from "renegade/libraries/interfaces/IWETH9.sol";
import {
ValidWalletCreateStatement,
ValidWalletUpdateStatement,
Expand Down Expand Up @@ -62,6 +63,8 @@ contract Darkpool {
IVerifier public verifier;
/// @notice The Permit2 contract instance for handling deposits
IPermit2 public permit2;
/// @notice The WETH9 contract instance used for depositing/withdrawing native tokens
IWETH9 public weth;

/// @notice The Merkle tree for wallet commitments
MerkleTreeLib.MerkleTree private merkleTree;
Expand All @@ -78,6 +81,7 @@ contract Darkpool {
constructor(
uint256 protocolFeeRate_,
address protocolFeeRecipient_,
IWETH9 weth_,
IHasher hasher_,
IVerifier verifier_,
IPermit2 permit2_
Expand All @@ -87,6 +91,7 @@ contract Darkpool {
hasher = hasher_;
verifier = verifier_;
permit2 = permit2_;
weth = weth_;
merkleTree.initialize();
}

Expand Down Expand Up @@ -273,16 +278,16 @@ contract Darkpool {
ValidReblindStatement calldata reblindStatement = internalPartyPayload.validReblindStatement;

// 1. Validate the transaction value
// If the external party is selling native ETH, validate that they have provided the correct
// If the external party is selling a native token, validate that they have provided the correct
// amount in the transaction's value
ExternalMatchResult memory matchResult = matchSettleStatement.matchResult;
bool tradesNativeToken = DarkpoolConstants.isNativeEth(matchResult.baseMint);
bool tradesNativeToken = DarkpoolConstants.isNativeToken(matchResult.baseMint);
bool externalPartySells = matchResult.direction == ExternalMatchDirection.InternalPartyBuy;
bool nativeEthSell = tradesNativeToken && externalPartySells;
bool nativeTokenSell = tradesNativeToken && externalPartySells;

// The tx value should be zero unless the external party is selling native ETH
if (!nativeEthSell && msg.value != 0) {
revert("Invalid ETH value, should be zero unless selling native ETH");
// The tx value should be zero unless the external party is selling native token
if (!nativeTokenSell && msg.value != 0) {
revert("Invalid ETH value, should be zero unless selling native token");
}

// 2. Verify the proofs
Expand Down Expand Up @@ -315,7 +320,7 @@ contract Darkpool {
TransferExecutor.SimpleTransfer[] memory transfers = buildAtomicMatchTransfers(
receiver, statement.relayerFeeAddress, statement.matchResult, statement.externalPartyFees
);
TransferExecutor.executeTransferBatch(transfers);
TransferExecutor.executeTransferBatch(transfers, weth);
}

// --- Helpers --- //
Expand Down
2 changes: 1 addition & 1 deletion src/Verifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
MatchAtomicLinkingProofs
} from "./libraries/darkpool/Types.sol";
import { VerificationKeys } from "./libraries/darkpool/VerificationKeys.sol";
import { IVerifier } from "./libraries/verifier/IVerifier.sol";
import { IVerifier } from "./libraries/interfaces/IVerifier.sol";
import { VerifierCore } from "./libraries/verifier/VerifierCore.sol";
import { ProofLinkingCore } from "./libraries/verifier/ProofLinking.sol";
import { BN254 } from "solidity-bn254/BN254.sol";
Expand Down
13 changes: 7 additions & 6 deletions src/libraries/darkpool/Constants.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ library DarkpoolConstants {
/// @notice The depth of the Merkle tree
uint256 constant MERKLE_DEPTH = 32;

/// @notice The address used for native ETH in trade settlement
address constant NATIVE_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// @notice The address used for native tokens in trade settlement
/// @dev This is currently just ETH, but intentionally written abstractly
address constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

/// @notice Check whether an address is the native ETH address
/// @notice Check whether an address is the native token address
/// @param addr The address to check
/// @return True if the address is the native ETH address, false otherwise
function isNativeEth(address addr) public pure returns (bool) {
return addr == NATIVE_ETH_ADDRESS;
/// @return True if the address is the native token address, false otherwise
function isNativeToken(address addr) public pure returns (bool) {
return addr == NATIVE_TOKEN_ADDRESS;
}
}
33 changes: 23 additions & 10 deletions src/libraries/darkpool/ExternalTransfers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@ import {
DepositWitness,
DEPOSIT_WITNESS_TYPE_STRING
} from "../darkpool/Types.sol";
import { DarkpoolConstants } from "../darkpool/Constants.sol";
import { WalletOperations } from "../darkpool/WalletOperations.sol";
import { IPermit2 } from "permit2/interfaces/IPermit2.sol";
import { IWETH9 } from "renegade/libraries/interfaces/IWETH9.sol";
import { ISignatureTransfer } from "permit2/interfaces/ISignatureTransfer.sol";
import { IERC20 } from "forge-std/interfaces/IERC20.sol";

// @title TransferExecutor
// @notice This library implements the logic for executing external transfers
// @notice External transfers are either deposits or withdrawals into/from the darkpool
/// @title TransferExecutor
/// @notice This library implements the logic for executing external transfers
/// @notice External transfers are either deposits or withdrawals into/from the darkpool
library TransferExecutor {
using TypesLib for DepositWitness;

Expand Down Expand Up @@ -68,7 +70,7 @@ library TransferExecutor {
}

/// @notice Execute a batch of simple ERC20 transfers
function executeTransferBatch(SimpleTransfer[] memory transfers) internal {
function executeTransferBatch(SimpleTransfer[] memory transfers, IWETH9 wrapper) internal {
for (uint256 i = 0; i < transfers.length; i++) {
// Do nothing if the transfer amount i zero
if (transfers[i].amount == 0) {
Expand All @@ -78,9 +80,9 @@ library TransferExecutor {
// Otherwise, execute the transfer
SimpleTransferType transferType = transfers[i].transferType;
if (transferType == SimpleTransferType.Withdrawal) {
executeSimpleWithdrawal(transfers[i]);
executeSimpleWithdrawal(transfers[i], wrapper);
} else {
executeSimpleDeposit(transfers[i]);
executeSimpleDeposit(transfers[i], wrapper);
}
}
}
Expand Down Expand Up @@ -128,8 +130,14 @@ library TransferExecutor {

/// @notice Execute a simple ERC20 deposit
/// @dev It is assumed that the address from which we deposit has approved the darkpool to spend the tokens
function executeSimpleDeposit(SimpleTransfer memory transfer) internal {
// TODO: Handle native token deposits
function executeSimpleDeposit(SimpleTransfer memory transfer, IWETH9 wrapper) internal {
// Handle native token deposits by wrapping the transaction value
if (DarkpoolConstants.isNativeToken(transfer.mint)) {
require(msg.value == transfer.amount, "msg.value does not match deposit amount");
wrapper.deposit{ value: transfer.amount }();
return;
}

IERC20 token = IERC20(transfer.mint);
address self = address(this);
token.transferFrom(transfer.account, self, transfer.amount);
Expand Down Expand Up @@ -159,8 +167,13 @@ library TransferExecutor {
}

/// @notice Execute a simple ERC20 withdrawal
function executeSimpleWithdrawal(SimpleTransfer memory transfer) internal {
// TODO: Handle native token withdrawals
function executeSimpleWithdrawal(SimpleTransfer memory transfer, IWETH9 wrapper) internal {
// Handle native token withdrawals by unwrapping the transfer amount into ETH
if (DarkpoolConstants.isNativeToken(transfer.mint)) {
wrapper.withdrawTo(transfer.account, transfer.amount);
return;
}

IERC20 token = IERC20(transfer.mint);
token.transfer(transfer.account, transfer.amount);
}
Expand Down
2 changes: 1 addition & 1 deletion src/libraries/darkpool/WalletOperations.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity ^0.8.20;

import { BN254 } from "solidity-bn254/BN254.sol";
import { PublicRootKey } from "./Types.sol";
import { IHasher } from "../poseidon2/IHasher.sol";
import { IHasher } from "../interfaces/IHasher.sol";
import { MerkleTreeLib } from "../merkle/MerkleTree.sol";
import { NullifierLib } from "./NullifierSet.sol";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import { PlonkProof } from "./Types.sol";
import { PlonkProof } from "renegade/libraries/verifier/Types.sol";
import {
ValidWalletCreateStatement,
ValidWalletUpdateStatement,
ValidMatchSettleStatement,
ValidMatchSettleAtomicStatement
} from "../darkpool/PublicInputs.sol";
} from "renegade/libraries/darkpool/PublicInputs.sol";
import {
PartyMatchPayload,
MatchProofs,
MatchLinkingProofs,
MatchAtomicProofs,
MatchAtomicLinkingProofs
} from "../darkpool/Types.sol";
} from "renegade/libraries/darkpool/Types.sol";

interface IVerifier {
/// @notice Verify a proof of `VALID WALLET CREATE`
Expand Down
13 changes: 13 additions & 0 deletions src/libraries/interfaces/IWETH9.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "oz-contracts/token/ERC20/IERC20.sol";

/// @title Interface for WETH9
interface IWETH9 is IERC20 {
/// @notice Deposit ETH and mint WETH
function deposit() external payable;

/// @notice Withdraw (burn) WETH and receive ETH
function withdrawTo(address, uint256) external;
}
2 changes: 1 addition & 1 deletion src/libraries/merkle/MerkleTree.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity ^0.8.0;

import { BN254 } from "solidity-bn254/BN254.sol";
import { IHasher } from "../poseidon2/IHasher.sol";
import { IHasher } from "../interfaces/IHasher.sol";
import { DarkpoolConstants } from "../darkpool/Constants.sol";
import { MerkleZeros } from "./MerkleZeros.sol";

Expand Down
8 changes: 4 additions & 4 deletions test/Merkle.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import { Test } from "forge-std/Test.sol";
import { console } from "forge-std/console.sol";
import { HuffDeployer } from "foundry-huff/HuffDeployer.sol";
import { TestUtils } from "./utils/TestUtils.sol";
import { IHasher } from "../src/libraries/poseidon2/IHasher.sol";
import { MerkleTreeLib } from "../src/libraries/merkle/MerkleTree.sol";
import { MerkleZeros } from "../src/libraries/merkle/MerkleZeros.sol";
import { DarkpoolConstants } from "../src/libraries/darkpool/Constants.sol";
import { IHasher } from "renegade/libraries/interfaces/IHasher.sol";
import { MerkleTreeLib } from "renegade/libraries/merkle/MerkleTree.sol";
import { MerkleZeros } from "renegade/libraries/merkle/MerkleZeros.sol";
import { DarkpoolConstants } from "renegade/libraries/darkpool/Constants.sol";

contract MerkleTest is TestUtils {
using MerkleTreeLib for MerkleTreeLib.MerkleTree;
Expand Down
15 changes: 11 additions & 4 deletions test/darkpool/DarkpoolTestBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity ^0.8.0;

import { BN254 } from "solidity-bn254/BN254.sol";
import { ERC20Mock } from "oz-contracts/mocks/token/ERC20Mock.sol";
import { WethMock } from "../test-contracts/WethMock.sol";
import { IPermit2 } from "permit2/interfaces/IPermit2.sol";
import { DeployPermit2 } from "permit2-test/utils/DeployPermit2.sol";
import { Test } from "forge-std/Test.sol";
Expand All @@ -17,8 +18,8 @@ import { TestVerifier } from "../test-contracts/TestVerifier.sol";
import { Darkpool } from "renegade/Darkpool.sol";
import { NullifierLib } from "renegade/libraries/darkpool/NullifierSet.sol";
import { WalletOperations } from "renegade/libraries/darkpool/WalletOperations.sol";
import { IHasher } from "renegade/libraries/poseidon2/IHasher.sol";
import { IVerifier } from "renegade/libraries/verifier/IVerifier.sol";
import { IHasher } from "renegade/libraries/interfaces/IHasher.sol";
import { IVerifier } from "renegade/libraries/interfaces/IVerifier.sol";
import { PlonkProof } from "renegade/libraries/verifier/Types.sol";

contract DarkpoolTestBase is CalldataUtils {
Expand All @@ -30,14 +31,16 @@ contract DarkpoolTestBase is CalldataUtils {
IPermit2 public permit2;
ERC20Mock public quoteToken;
ERC20Mock public baseToken;
WethMock public weth;

address public protocolFeeAddr;

bytes constant INVALID_NULLIFIER_REVERT_STRING = "Nullifier already spent";
bytes constant INVALID_ROOT_REVERT_STRING = "Merkle root not in history";
bytes constant INVALID_SIGNATURE_REVERT_STRING = "Invalid signature";
bytes constant INVALID_PROTOCOL_FEE_REVERT_STRING = "Invalid protocol fee rate";
bytes constant INVALID_ETH_VALUE_REVERT_STRING = "Invalid ETH value, should be zero unless selling native ETH";
bytes constant INVALID_ETH_VALUE_REVERT_STRING = "Invalid ETH value, should be zero unless selling native token";
bytes constant INVALID_ETH_DEPOSIT_AMOUNT_REVERT_STRING = "msg.value does not match deposit amount";

function setUp() public {
// Deploy a Permit2 instance for testing
Expand All @@ -47,12 +50,16 @@ contract DarkpoolTestBase is CalldataUtils {
// Deploy mock tokens for testing
quoteToken = new ERC20Mock();
baseToken = new ERC20Mock();
weth = new WethMock();

// Capitalize the weth contract
vm.deal(address(weth), 100 ether);

// Deploy the darkpool implementation contracts
hasher = IHasher(HuffDeployer.deploy("libraries/poseidon2/poseidonHasher"));
IVerifier verifier = new TestVerifier();
protocolFeeAddr = vm.randomAddress();
darkpool = new Darkpool(TEST_PROTOCOL_FEE, protocolFeeAddr, hasher, verifier, permit2);
darkpool = new Darkpool(TEST_PROTOCOL_FEE, protocolFeeAddr, weth, hasher, verifier, permit2);
}

// ---------------------------
Expand Down
Loading
Loading