Skip to content

Commit

Permalink
libraries: darkpool: ExternalTransfers: Implement withdrawals
Browse files Browse the repository at this point in the history
  • Loading branch information
joeykraut committed Mar 5, 2025
1 parent 9c90477 commit 607d83b
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 17 deletions.
30 changes: 20 additions & 10 deletions src/libraries/darkpool/ExternalTransfers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import {
hashDepositWitness,
DEPOSIT_WITNESS_TYPE_STRING
} from "../darkpool/Types.sol";
import { WalletOperations } from "../darkpool/WalletOperations.sol";
import { IPermit2 } from "permit2/interfaces/IPermit2.sol";
import { IERC20 } from "forge-std/interfaces/IERC20.sol";
import { ISignatureTransfer } from "permit2/interfaces/ISignatureTransfer.sol";

// @title TransferExecutor
Expand All @@ -35,7 +37,7 @@ library TransferExecutor {
if (isDeposit) {
executeDeposit(oldPkRoot, transfer, authorization, permit2);
} else {
executeWithdrawal(transfer);
executeWithdrawal(oldPkRoot, transfer, authorization);
}
}

Expand Down Expand Up @@ -80,18 +82,26 @@ library TransferExecutor {
);
}

/// @notice Builds the deposit witness hash from the public root key
/// @param oldPkRoot The public root key of the sender's Renegade wallet
/// @return The deposit witness hash
function buildDepositWitnessHash(PublicRootKey calldata oldPkRoot) internal pure returns (bytes32) {
return keccak256(abi.encode(oldPkRoot));
}

// --- Withdrawal --- //

/// @notice Executes a withdrawal of shares from the darkpool
/// @param transfer The transfer to execute
function executeWithdrawal(ExternalTransfer calldata transfer) internal {
// TODO: Implement withdrawal logic
function executeWithdrawal(
PublicRootKey calldata oldPkRoot,
ExternalTransfer calldata transfer,
TransferAuthorization calldata authorization
)
internal
{
// 1. Verify the signature of the withdrawal
bytes memory transferBytes = abi.encode(transfer);
bytes32 transferHash = keccak256(transferBytes);
bool sigValid =
WalletOperations.verifyRootKeySignature(transferHash, authorization.externalTransferSignature, oldPkRoot);
require(sigValid, "Invalid withdrawal signature");

// 2. Execute the withdrawal as a direct ERC20 transfer
IERC20 token = IERC20(transfer.mint);
token.transfer(transfer.account, transfer.amount);
}
}
27 changes: 20 additions & 7 deletions src/libraries/darkpool/WalletOperations.sol
Original file line number Diff line number Diff line change
Expand Up @@ -61,23 +61,36 @@ library WalletOperations {
bytes32 commitmentHash = walletCommitmentDigest(walletCommitment);

// 2. Verify the signature
require(newSharesCommitmentSig.length == 65, "Invalid signature length");
return verifyRootKeySignature(commitmentHash, newSharesCommitmentSig, oldRootKey);
}

bytes32 r = bytes32(newSharesCommitmentSig[:32]);
bytes32 s = bytes32(newSharesCommitmentSig[32:64]);
uint8 v = uint8(newSharesCommitmentSig[64]);
/// @notice Verify the root key signature of a digest
function verifyRootKeySignature(
bytes32 digest,
bytes calldata signature,
PublicRootKey memory rootKey
)
internal
view
returns (bool)
{
// Split the signature into r, s and v
require(signature.length == 65, "Invalid signature length");
bytes32 r = bytes32(signature[:32]);
bytes32 s = bytes32(signature[32:64]);
uint8 v = uint8(signature[64]);
// Clients (notably ethers) sometimes use v = 0 or 1, the ecrecover precompile expects 27 or 28
if (v == 0 || v == 1) {
v += 27;
}

// Recover signer address using ecrecover
address signer = ecrecover(commitmentHash, v, r, s);
address signer = ecrecover(digest, v, r, s);
require(signer != address(0), "Invalid signature");

// Convert oldRootKey to address and compare
address oldRootKeyAddress = addressFromRootKey(oldRootKey);
return signer == oldRootKeyAddress;
address rootKeyAddress = addressFromRootKey(rootKey);
return signer == rootKeyAddress;
}

/// @notice Get the digest of a wallet commitment
Expand Down

0 comments on commit 607d83b

Please sign in to comment.