Skip to content

Commit

Permalink
libraries: darkpool: ExternalTransfers: Implement deposit
Browse files Browse the repository at this point in the history
  • Loading branch information
joeykraut committed Mar 5, 2025
1 parent d0cc4ad commit 5111187
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 2 deletions.
1 change: 1 addition & 0 deletions remappings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ foundry-huff/=lib/foundry-huff/src/
solidity-stringutils/=lib/foundry-huff/lib/solidity-stringutils/
stringutils/=lib/foundry-huff/lib/solidity-stringutils/
solidity-bn254/=lib/solidity-bn254/src/
permit2/=lib/permit2/src/
97 changes: 97 additions & 0 deletions src/libraries/darkpool/ExternalTransfers.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;

import {
ExternalTransfer,
TransferType,
TransferAuthorization,
PublicRootKey,
publicKeyToUints,
DepositWitness,
hashDepositWitness,
DEPOSIT_WITNESS_TYPE_STRING
} from "../darkpool/Types.sol";
import { IPermit2 } from "permit2/interfaces/IPermit2.sol";
import { ISignatureTransfer } from "permit2/interfaces/ISignatureTransfer.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
library TransferExecutor {
/// @notice Executes an external transfer (deposit or withdrawal) for the darkpool
/// @param transfer The external transfer details including account, mint, amount and type
/// @param oldPkRoot The public root key of the sender's Renegade wallet
/// @param authorization The authorization data for the transfer (permit2 or withdrawal signature)
/// @param permit2 The Permit2 contract instance for handling deposits
function executeTransfer(
ExternalTransfer calldata transfer,
PublicRootKey calldata oldPkRoot,
TransferAuthorization calldata authorization,
IPermit2 permit2
)
internal
{
bool isDeposit = transfer.transferType == TransferType.Deposit;
if (isDeposit) {
executeDeposit(oldPkRoot, transfer, authorization, permit2);
} else {
executeWithdrawal(transfer);
}
}

// --- Deposit --- //

/// @notice Executes a deposit of shares into the darkpool
/// @dev Deposits flow through the permit2 contract, which allows us to attach the public root
/// @dev key to the deposit's witness. This provides a link between the on-chain wallet and the
/// @dev Renegade wallet, ensuring that only one Renegade wallet may redeem the permit.
/// @param transfer The transfer to execute
/// @param authorization The authorization for the deposit
/// @param permit2 The permit2 contract
function executeDeposit(
PublicRootKey calldata oldPkRoot,
ExternalTransfer calldata transfer,
TransferAuthorization calldata authorization,
IPermit2 permit2
)
internal
{
// Build the permit
ISignatureTransfer.TokenPermissions memory tokenPermissions =
ISignatureTransfer.TokenPermissions({ token: transfer.mint, amount: transfer.amount });
ISignatureTransfer.PermitTransferFrom memory permit = ISignatureTransfer.PermitTransferFrom({
permitted: tokenPermissions,
nonce: authorization.permit2Nonce,
deadline: authorization.permit2Deadline
});
ISignatureTransfer.SignatureTransferDetails memory signatureTransferDetails =
ISignatureTransfer.SignatureTransferDetails({ to: address(this), requestedAmount: transfer.amount });
DepositWitness memory depositWitness = DepositWitness({ pkRoot: publicKeyToUints(oldPkRoot) });
bytes32 depositWitnessHash = hashDepositWitness(depositWitness);

address owner = transfer.account;
permit2.permitWitnessTransferFrom(
permit,
signatureTransferDetails,
owner,
depositWitnessHash,
DEPOSIT_WITNESS_TYPE_STRING,
authorization.permit2Signature
);
}

/// @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
}
}
46 changes: 46 additions & 0 deletions src/libraries/darkpool/Types.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ pragma solidity ^0.8.0;

import { BN254 } from "solidity-bn254/BN254.sol";

/// @dev The type hash for the DepositWitness struct
bytes32 constant DEPOSIT_WITNESS_TYPEHASH = keccak256("DepositWitness(uint256[4] pkRoot)");
/// @dev The type string for the DepositWitness struct
string constant DEPOSIT_WITNESS_TYPE_STRING =
"DepositWitness witness)DepositWitness(uint256[4] pkRoot)TokenPermissions(address token,uint256 amount)";

// ---------------------
// | External Transfer |
// ---------------------
Expand All @@ -27,6 +33,38 @@ enum TransferType {
Withdrawal
}

/// @notice Auxiliary data authorizing a transfer
/// @dev This struct is effectively a union of the auth required for
/// @dev a deposit (permit2) and that required for a withdrawal (a simple signature)
/// @dev The external transfer implementation will use the appropriate authorization
/// @dev based on the transfer type
struct TransferAuthorization {
/// @dev The nonce of the permit
uint256 permit2Nonce;
/// @dev The deadline of the permit
uint256 permit2Deadline;
/// @dev The signature of the permit
bytes permit2Signature;
/// @dev The signature of the external transfer
bytes externalTransferSignature;
}

/// @notice The permit2 witness for a deposit
/// @dev The Permit2 witness type used in a deposit
struct DepositWitness {
/// @dev The limb-serialization of the public key of the old wallet
uint256[4] pkRoot;
}

/// @notice Computes the EIP-712 hash of a DepositWitness
/// @param witness The DepositWitness to hash
/// @return The EIP-712 hash of the DepositWitness
function hashDepositWitness(DepositWitness memory witness) pure returns (bytes32) {
// Hash the struct data according to EIP-712
bytes32 pkRootHash = keccak256(abi.encode(witness.pkRoot));
return keccak256(abi.encode(DEPOSIT_WITNESS_TYPEHASH, pkRootHash));
}

// ------------
// | Keychain |
// ------------
Expand All @@ -40,3 +78,11 @@ struct PublicRootKey {
/// @dev The y coordinate of the public key
BN254.ScalarField[2] y;
}

/// @notice Serialize the public root key into a list of uint256s
function publicKeyToUints(PublicRootKey memory pk) pure returns (uint256[4] memory scalars) {
scalars[0] = BN254.ScalarField.unwrap(pk.x[0]);
scalars[1] = BN254.ScalarField.unwrap(pk.x[1]);
scalars[2] = BN254.ScalarField.unwrap(pk.y[0]);
scalars[3] = BN254.ScalarField.unwrap(pk.y[1]);
}
2 changes: 1 addition & 1 deletion src/libraries/darkpool/WalletOperations.sol
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ library WalletOperations {
}

/// @notice Get an ethereum address from a public root key
function addressFromRootKey(PublicRootKey memory rootKey) internal view returns (address) {
function addressFromRootKey(PublicRootKey memory rootKey) internal pure returns (address) {
uint256 x = scalarWordsToUint(rootKey.x[0], rootKey.x[1]);
uint256 y = scalarWordsToUint(rootKey.y[0], rootKey.y[1]);
// Pack x and y into 64 bytes
Expand Down
2 changes: 1 addition & 1 deletion test/utils/CalldataUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ contract CalldataUtils is TestUtils {
}

/// @notice Convert a forge wallet to a public root key
function forgeWalletToRootKey(Vm.Wallet memory wallet) internal returns (PublicRootKey memory rootKey) {
function forgeWalletToRootKey(Vm.Wallet memory wallet) internal pure returns (PublicRootKey memory rootKey) {
(BN254.ScalarField xLow, BN254.ScalarField xHigh) = uintToScalarWords(wallet.publicKeyX);
(BN254.ScalarField yLow, BN254.ScalarField yHigh) = uintToScalarWords(wallet.publicKeyY);
rootKey = PublicRootKey({ x: [xLow, xHigh], y: [yLow, yHigh] });
Expand Down

0 comments on commit 5111187

Please sign in to comment.