Skip to content

Commit

Permalink
libraries: darkpool: ExternalTransfers: Handle native asset transfers
Browse files Browse the repository at this point in the history
  • Loading branch information
joeykraut committed Mar 8, 2025
1 parent fcd1ccb commit 8851926
Show file tree
Hide file tree
Showing 13 changed files with 73 additions and 43 deletions.
21 changes: 12 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 Down Expand Up @@ -273,16 +276,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 +318,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;
}
}
27 changes: 20 additions & 7 deletions src/libraries/darkpool/ExternalTransfers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ 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";

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, "Invalid ETH 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
File renamed without changes.
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
6 changes: 3 additions & 3 deletions test/darkpool/DarkpoolTestBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,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 @@ -37,7 +37,7 @@ contract DarkpoolTestBase is CalldataUtils {
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";

function setUp() public {
// Deploy a Permit2 instance for testing
Expand Down
14 changes: 7 additions & 7 deletions test/test-contracts/TestVerifier.sol
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import { PlonkProof, VerificationKey } from "../../src/libraries/verifier/Types.sol";
import { PlonkProof, VerificationKey } from "renegade/libraries/verifier/Types.sol";
import {
ValidWalletCreateStatement,
ValidWalletUpdateStatement,
ValidMatchSettleStatement,
ValidMatchSettleAtomicStatement,
StatementSerializer
} from "../../src/libraries/darkpool/PublicInputs.sol";
} from "renegade/libraries/darkpool/PublicInputs.sol";
import {
PartyMatchPayload,
MatchProofs,
MatchLinkingProofs,
MatchAtomicProofs,
MatchAtomicLinkingProofs
} from "../../src/libraries/darkpool/Types.sol";
import { VerificationKeys } from "../../src/libraries/darkpool/VerificationKeys.sol";
import { IVerifier } from "../../src/libraries/verifier/IVerifier.sol";
import { Verifier } from "../../src/Verifier.sol";
import { VerifierCore } from "../../src/libraries/verifier/VerifierCore.sol";
} from "renegade/libraries/darkpool/Types.sol";
import { VerificationKeys } from "renegade/libraries/darkpool/VerificationKeys.sol";
import { IVerifier } from "renegade/libraries/interfaces/IVerifier.sol";
import { Verifier } from "renegade/Verifier.sol";
import { VerifierCore } from "renegade/libraries/verifier/VerifierCore.sol";
import { BN254 } from "solidity-bn254/BN254.sol";

/// @title Test Verifier Implementation
Expand Down
2 changes: 1 addition & 1 deletion test/utils/CalldataUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { ISignatureTransfer } from "permit2/interfaces/ISignatureTransfer.sol";
import { IERC20 } from "oz-contracts/token/ERC20/IERC20.sol";
import { TestUtils } from "./TestUtils.sol";
import { PlonkProof, LinkingProof } from "renegade/libraries/verifier/Types.sol";
import { IHasher } from "renegade/libraries/poseidon2/IHasher.sol";
import { IHasher } from "renegade/libraries/interfaces/IHasher.sol";
import {
TypesLib,
ExternalTransfer,
Expand Down

0 comments on commit 8851926

Please sign in to comment.