编译器
0.8.20+commit.a1b79de6
文件 1 的 18:Address.sol
pragma solidity ^0.8.20;
library Address {
error AddressInsufficientBalance(address account);
error AddressEmptyCode(address target);
error FailedInnerCall();
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
function _revert(bytes memory returndata) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}
文件 2 的 18:BaseAssetManager.sol
pragma solidity >=0.8.20;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IAssetPool} from "../interfaces/IAssetPool.sol";
import {IVerifier} from "../interfaces/IVerifier.sol";
import {IVerifierHub} from "../interfaces/IVerifierHub.sol";
import {IRelayerHub} from "../interfaces/IRelayerHub.sol";
import {IFeeManager} from "../interfaces/IFeeManager.sol";
import {IComplianceManager} from "../interfaces/IComplianceManager.sol";
import {IMerkleTreeOperator} from "../interfaces/IMerkleTreeOperator.sol";
import {IMimc254} from "../interfaces/IMimc254.sol";
import {BaseInputBuilder} from "./BaseInputBuilder.sol";
abstract contract BaseAssetManager is Ownable, BaseInputBuilder {
using SafeERC20 for IERC20;
struct FundReleaseDetails {
address assetAddress;
address payable recipient;
address payable relayer;
uint256 relayerGasFee;
uint256 amount;
}
IVerifierHub internal _verifierHub;
IAssetPool internal _assetPoolERC20;
IAssetPool internal _assetPoolERC721;
IAssetPool internal _assetPoolETH;
IRelayerHub internal _relayerHub;
IFeeManager internal _feeManager;
IComplianceManager internal _complianceManager;
IMerkleTreeOperator internal immutable _merkleTreeOperator;
IMimc254 internal immutable _mimc254;
address public constant ETH_ADDRESS =
0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
bytes32 public constant ASSET_ETH = keccak256(abi.encode(ETH_ADDRESS));
uint256 public constant P =
21888242871839275222246405745257275088548364400416034343698204186575808495617;
error RelayerNotRegistered();
error NullifierUsed();
error NullifierLocked();
error MerkleRootNotAllowed();
error NoteFooterUsed();
error NoteAlreadyCreated();
error InvalidNoteParameters();
error ZeroAddress();
error NoteFooterDuplicated();
error RelayerMismatch();
modifier onlyETHAssetPool() {
require(
msg.sender == address(_assetPoolETH),
"BaseAssetManager: Only ETH Asset Pool"
);
_;
}
constructor(
address assetPoolERC20,
address assetPoolERC721,
address assetPoolETH,
address verifierHub,
address relayerHub,
address feeManager,
address complianceManager,
address merkleTreeOperator,
address mimc254,
address initialOwner
) Ownable(initialOwner) {
if (assetPoolERC20 == address(0) ||
assetPoolERC721 == address(0) ||
assetPoolETH == address(0) ||
verifierHub == address(0) ||
relayerHub == address(0) ||
feeManager == address(0) ||
complianceManager == address(0) ||
merkleTreeOperator == address(0) ||
mimc254 == address(0) ||
initialOwner == address(0)
) {
revert ZeroAddress();
}
_assetPoolERC20 = IAssetPool(assetPoolERC20);
_assetPoolERC721 = IAssetPool(assetPoolERC721);
_assetPoolETH = IAssetPool(assetPoolETH);
_verifierHub = IVerifierHub(verifierHub);
_relayerHub = IRelayerHub(relayerHub);
_feeManager = IFeeManager(feeManager);
_complianceManager = IComplianceManager(complianceManager);
_merkleTreeOperator = IMerkleTreeOperator(merkleTreeOperator);
_mimc254 = IMimc254(mimc254);
}
receive() external payable {}
function releaseToAsssetPool(
address asset,
uint256 amount
) external onlyOwner {
require(amount > 0, "BaseAssetManager: amount must be greater than 0");
if (asset == address(0) || asset == ETH_ADDRESS) {
(bool success, ) = address(_assetPoolETH).call{value: amount}("");
require(success, "BaseAssetManager: Failed to send Ether");
} else {
IERC20(asset).safeTransfer(address(_assetPoolERC20), amount);
}
}
function setAssetPoolERC20(address assetPoolERC20) public onlyOwner {
if (assetPoolERC20 != address(0)) {
_assetPoolERC20 = IAssetPool(assetPoolERC20);
}
}
function setAssetPoolERC721(address assetPoolERC721) public onlyOwner {
if (assetPoolERC721 != address(0)) {
_assetPoolERC721 = IAssetPool(assetPoolERC721);
}
}
function setAssetPoolETH(address assetPoolETH) public onlyOwner {
if (assetPoolETH != address(0)) {
_assetPoolETH = IAssetPool(assetPoolETH);
}
}
function setVerifierHub(address verifierHub) public onlyOwner {
if (verifierHub != address(0)) {
_verifierHub = IVerifierHub(verifierHub);
}
}
function setRelayerHub(address relayerHub) public onlyOwner {
if (relayerHub != address(0)) {
_relayerHub = IRelayerHub(relayerHub);
}
}
function setFeeManager(address feeManager) public onlyOwner {
if (feeManager != address(0)) {
_feeManager = IFeeManager(feeManager);
}
}
function setComplianceManager(address complianceManager) public onlyOwner {
if (complianceManager != address(0)) {
_complianceManager = IComplianceManager(complianceManager);
}
}
function getAssetPoolERC20() public view returns (address) {
return address(_assetPoolERC20);
}
function getAssetPoolERC721() public view returns (address) {
return address(_assetPoolERC721);
}
function getAssetPoolETH() public view returns (address) {
return address(_assetPoolETH);
}
function getVerifierHub() public view returns (address) {
return address(_verifierHub);
}
function getRelayerHub() public view returns (address) {
return address(_relayerHub);
}
function getFeeManager() public view returns (address) {
return address(_feeManager);
}
function getComplianceManager() public view returns (address) {
return address(_complianceManager);
}
function getMerkleTreeOperator() public view returns (address) {
return address(_merkleTreeOperator);
}
function getMimc254() public view returns (address) {
return address(_mimc254);
}
function _postDeposit(bytes32 _noteCommitment) internal {
_merkleTreeOperator.setNoteCommitmentCreated(_noteCommitment);
_merkleTreeOperator.appendMerkleLeaf(bytes32(_noteCommitment));
}
function _postWithdraw(bytes32 _nullifier) internal {
_merkleTreeOperator.setNullifierUsed(_nullifier);
}
function _setNullifierLock(bytes32 _nullifier, bool _locked) internal {
_merkleTreeOperator.setNullifierLocked(_nullifier, _locked);
}
function _registerNoteFooter(bytes32 _noteFooter) internal {
_merkleTreeOperator.setNoteFooterUsed(_noteFooter);
}
function _releaseERC20WithFee(
address _asset,
address _to,
address _relayer,
uint256 _relayerGasFee,
uint256 _amount
) internal returns (uint256, uint256, uint256) {
(
uint256 actualAmount,
uint256 serviceFee,
uint256 relayerRefund
) = _feeManager.calculateFee(_amount, _relayerGasFee);
_assetPoolERC20.release(_asset, _to, actualAmount);
if (relayerRefund > 0) {
_assetPoolERC20.release(_asset, _relayer, relayerRefund);
}
if (serviceFee > 0) {
_assetPoolERC20.release(_asset, address(_feeManager), serviceFee);
}
return (actualAmount, serviceFee, relayerRefund);
}
function _releaseETHWithFee(
address payable _to,
address payable _relayer,
uint256 _relayerGasFee,
uint256 _amount
) internal returns (uint256, uint256, uint256) {
(
uint256 actualAmount,
uint256 serviceFee,
uint256 relayerRefund
) = _feeManager.calculateFee(_amount, _relayerGasFee);
_assetPoolETH.release(_to, actualAmount);
if (relayerRefund > 0) {
_assetPoolETH.release(_relayer, relayerRefund);
}
if (serviceFee > 0) {
_assetPoolETH.release(payable(address(_feeManager)), serviceFee);
}
return (actualAmount, serviceFee, relayerRefund);
}
function _releaseFunds(
FundReleaseDetails memory details
) internal returns (uint256, uint256, uint256) {
if (
details.assetAddress == ETH_ADDRESS ||
details.assetAddress == address(0)
) {
return
_releaseETHWithFee(
details.recipient,
details.relayer,
details.relayerGasFee,
details.amount
);
} else {
return
_releaseERC20WithFee(
details.assetAddress,
details.recipient,
details.relayer,
details.relayerGasFee,
details.amount
);
}
}
function _verifyProof(
bytes calldata _proof,
bytes32[] memory _inputs,
string memory verifierType
) internal view {
IVerifier verifier = _verifierHub.getVerifier(verifierType);
require(verifier.verify(_proof, _inputs), "invalid proof");
}
function _buildNoteForERC20(
address asset,
uint256 amount,
bytes32 noteFooter
) internal view returns (bytes32) {
return _buildNote(
asset,
amount,
noteFooter,
IMimc254.NoteDomainSeparator.FUNGIBLE
);
}
function _buildNoteForERC721(
address asset,
uint256 tokenId,
bytes32 noteFooter
) internal view returns (bytes32) {
return _buildNote(
asset,
tokenId,
noteFooter,
IMimc254.NoteDomainSeparator.NON_FUNGIBLE
);
}
function _validateRelayerIsRegistered(address relayer) internal view {
if (!_relayerHub.isRelayerRegistered(relayer)) {
revert RelayerNotRegistered();
}
}
function _validateNullifierIsNotUsed(bytes32 nullifier) internal view {
if (!_merkleTreeOperator.nullifierIsNotUsed(nullifier)) {
revert NullifierUsed();
}
}
function _validateNullifierIsNotLocked(bytes32 nullifier) internal view {
if (!_merkleTreeOperator.nullifierIsNotLocked(nullifier)) {
revert NullifierLocked();
}
}
function _validateMerkleRootIsAllowed(bytes32 merkleRoot) internal view {
if (!_merkleTreeOperator.merkleRootIsAllowed(merkleRoot)) {
revert MerkleRootNotAllowed();
}
}
function _validateNoteFooterIsNotUsed(bytes32 noteFooter) internal view {
if (!_merkleTreeOperator.noteFooterIsNotUsed(noteFooter)) {
revert NoteFooterUsed();
}
}
function _validateNoteIsNotCreated(bytes32 noteCommitment) internal view {
if (!_merkleTreeOperator.noteIsNotCreated(noteCommitment)) {
revert NoteAlreadyCreated();
}
}
function _buildNote(
address asset,
uint256 amount,
bytes32 noteFooter,
IMimc254.NoteDomainSeparator domainSeparator
) private view returns (bytes32) {
if (asset == address(0) || amount == 0 || noteFooter == bytes32(0)){
revert InvalidNoteParameters();
}
uint256[] memory array = new uint256[](4);
array[0] = uint256(domainSeparator);
array[1] = uint256(_bytifyToNoir(asset));
array[2] = amount;
array[3] = uint256(noteFooter);
return
bytes32(_mimc254.mimcBn254(array));
}
}
文件 3 的 18:BaseInputBuilder.sol
pragma solidity ^0.8.20;
contract BaseInputBuilder {
uint256 internal _primeField;
constructor(uint256 primeField) {
_primeField = primeField;
}
function _bytifyToNoir(address value) internal pure returns (bytes32) {
return bytes32(uint256(uint160(ripemd160(abi.encode(value)))));
}
}
文件 4 的 18:Context.sol
pragma solidity ^0.8.20;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
文件 5 的 18:DarkpoolAssetManager.sol
pragma solidity >=0.8.20;
import {BaseAssetManager} from "./base/BaseAssetManager.sol";
import {DarkpoolInputBuilder} from "./DarkpoolInputBuilder.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract DarkpoolAssetManager is BaseAssetManager, DarkpoolInputBuilder {
using SafeERC20 for IERC20;
event Deposit(
address depositor,
bytes32 noteOut,
uint256 amount,
address asset
);
event Withdraw(
bytes32 nullifierIn,
uint256 amount,
address asset,
address recipient
);
event Transfer(
bytes32 nullifierIn,
uint256 amount,
address asset,
bytes32 noteOut,
bytes32 noteFooter
);
event Split(
bytes32 nullifierIn,
bytes32 noteOut1,
bytes32 noteOut2
);
event JoinSplit(
bytes32 nullifierIn1,
bytes32 nullifierIn2,
bytes32 noteOut1,
bytes32 noteOut2
);
event Join(
bytes32 nullifierIn1,
bytes32 nullifierIn2,
bytes32 noteOut1
);
constructor(
address assetPoolERC20,
address assetPoolERC721,
address assetPoolETH,
address verifierHub,
address relayerHub,
address feeManager,
address comlianceManager,
address merkleTreeOperator,
address mimc254,
address initialOwner
)
BaseAssetManager(
assetPoolERC20,
assetPoolERC721,
assetPoolETH,
verifierHub,
relayerHub,
feeManager,
comlianceManager,
merkleTreeOperator,
mimc254,
initialOwner
)
DarkpoolInputBuilder(P)
{}
function depositERC20(
address _asset,
uint256 _amount,
bytes32 _noteCommitment,
bytes32 _noteFooter,
bytes calldata _proof
) public {
require(
_complianceManager.isAuthorized(address(this), msg.sender),
"BaseAssetManager: invalid credential"
);
_validateNoteIsNotCreated(_noteCommitment);
_validateNoteFooterIsNotUsed(_noteFooter);
DepositRawInputs memory inputs = DepositRawInputs(
msg.sender,
_noteCommitment,
_asset,
_amount,
_noteFooter
);
_verifyProof(_proof, _buildDepositInputs(inputs), "deposit");
_registerNoteFooter(_noteFooter);
IERC20(_asset).safeTransferFrom(
msg.sender,
address(_assetPoolERC20),
_amount
);
_postDeposit(_noteCommitment);
emit Deposit(msg.sender, _noteCommitment, _amount, _asset);
}
function depositETH(
bytes32 _noteCommitment,
bytes32 _noteFooter,
bytes calldata _proof
) public payable {
require(
_complianceManager.isAuthorized(address(this), msg.sender),
"BaseAssetManager: invalid credential"
);
_validateNoteIsNotCreated(_noteCommitment);
_validateNoteFooterIsNotUsed(_noteFooter);
DepositRawInputs memory inputs = DepositRawInputs(
msg.sender,
_noteCommitment,
ETH_ADDRESS,
msg.value,
_noteFooter
);
_verifyProof(_proof, _buildDepositInputs(inputs), "deposit");
_registerNoteFooter(_noteFooter);
(bool success, ) = address(_assetPoolETH).call{value: msg.value}("");
require(success, "depositETH: transfer failed");
_postDeposit(_noteCommitment);
emit Deposit(msg.sender, _noteCommitment, msg.value, ETH_ADDRESS);
}
function withdrawERC20(
address _asset,
bytes calldata _proof,
bytes32 _merkleRoot,
bytes32 _nullifier,
address _recipient,
address _relayer,
uint256 _amount,
uint256 _relayerGasFee
) public {
require(
_complianceManager.isAuthorized(address(this), _recipient),
"BaseAssetManager: invalid credential"
);
_validateMerkleRootIsAllowed(_merkleRoot);
_validateNullifierIsNotUsed(_nullifier);
_validateNullifierIsNotLocked(_nullifier);
_validateRelayerIsRegistered(_relayer);
if(msg.sender != _relayer) {
revert RelayerMismatch();
}
WithdrawRawInputs memory inputs = WithdrawRawInputs(
_recipient,
_merkleRoot,
_asset,
_amount,
_nullifier,
_relayer
);
_verifyProof(_proof, _buildWithdrawInputs(inputs), "withdraw");
_postWithdraw(_nullifier);
_releaseERC20WithFee(
_asset,
_recipient,
_relayer,
_relayerGasFee,
_amount
);
emit Withdraw(_nullifier, _amount, _asset, _recipient);
}
function withdrawETH(
bytes calldata _proof,
bytes32 _merkleRoot,
bytes32 _nullifier,
address payable _recipient,
address payable _relayer,
uint256 _relayerGasFee,
uint256 _amount
) public {
require(
_complianceManager.isAuthorized(address(this), _recipient),
"BaseAssetManager: invalid credential"
);
_validateMerkleRootIsAllowed(_merkleRoot);
_validateNullifierIsNotUsed(_nullifier);
_validateNullifierIsNotLocked(_nullifier);
_validateRelayerIsRegistered(_relayer);
if(msg.sender != _relayer) {
revert RelayerMismatch();
}
WithdrawRawInputs memory inputs = WithdrawRawInputs(
_recipient,
_merkleRoot,
ETH_ADDRESS,
_amount,
_nullifier,
_relayer
);
_verifyProof(_proof, _buildWithdrawInputs(inputs), "withdraw");
_postWithdraw(_nullifier);
_releaseETHWithFee(_recipient, _relayer, _relayerGasFee, _amount);
emit Withdraw(_nullifier, _amount, ETH_ADDRESS, _recipient);
}
function transfer(
bytes32 _merkleRoot,
bytes32 _nullifierIn,
address _asset,
uint256 _amount,
bytes32 _noteOut,
bytes32 _noteFooter,
bytes calldata _proof
) public {
_validateMerkleRootIsAllowed(_merkleRoot);
_validateNullifierIsNotUsed(_nullifierIn);
_validateNullifierIsNotLocked(_nullifierIn);
_validateNoteIsNotCreated(_noteOut);
_validateNoteFooterIsNotUsed(_noteFooter);
TransferRawInputs memory inputs = TransferRawInputs(
_merkleRoot,
_asset,
_amount,
_nullifierIn,
_noteOut,
_noteFooter
);
_verifyProof(_proof, _buildTransferInputs(inputs), "transfer");
_registerNoteFooter(_noteFooter);
_postWithdraw(_nullifierIn);
_postDeposit(_noteOut);
emit Transfer(
_nullifierIn,
_amount,
_asset,
_noteOut,
_noteFooter
);
}
function split(
bytes32 _merkleRoot,
bytes32 _nullifierIn1,
bytes32 _noteOut1,
bytes32 _noteOut2,
bytes32 _noteFooter1,
bytes32 _noteFooter2,
bytes calldata _proof
) public payable {
_validateMerkleRootIsAllowed(_merkleRoot);
_validateNullifierIsNotUsed(_nullifierIn1);
_validateNullifierIsNotLocked(_nullifierIn1);
_validateNoteIsNotCreated(_noteOut1);
_validateNoteIsNotCreated(_noteOut2);
_validateNoteFooterIsNotUsed(_noteFooter1);
_validateNoteFooterIsNotUsed(_noteFooter2);
if(_noteFooter1 == _noteFooter2) {
revert NoteFooterDuplicated();
}
SplitRawInputs memory inputs = SplitRawInputs(
_merkleRoot,
_nullifierIn1,
_noteOut1,
_noteOut2,
_noteFooter1,
_noteFooter2
);
_verifyProof(_proof, _buildSplitInputs(inputs), "split");
_registerNoteFooter(_noteFooter1);
_registerNoteFooter(_noteFooter2);
_postWithdraw(_nullifierIn1);
_postDeposit(_noteOut1);
_postDeposit(_noteOut2);
emit Split(_nullifierIn1, _noteOut1, _noteOut2);
}
function joinSplit(
bytes32 _merkleRoot,
bytes32 _nullifierIn1,
bytes32 _nullifierIn2,
bytes32 _noteOut1,
bytes32 _noteOut2,
bytes32 _noteFooter1,
bytes32 _noteFooter2,
bytes calldata _proof
) public payable {
_validateMerkleRootIsAllowed(_merkleRoot);
_validateNullifierIsNotUsed(_nullifierIn1);
_validateNullifierIsNotUsed(_nullifierIn2);
_validateNullifierIsNotLocked(_nullifierIn1);
_validateNullifierIsNotLocked(_nullifierIn2);
_validateNoteIsNotCreated(_noteOut1);
_validateNoteIsNotCreated(_noteOut2);
_validateNoteFooterIsNotUsed(_noteFooter1);
_validateNoteFooterIsNotUsed(_noteFooter2);
if (_noteFooter1 == _noteFooter2) {
revert NoteFooterDuplicated();
}
JoinSplitRawInputs memory inputs = JoinSplitRawInputs(
_merkleRoot,
_nullifierIn1,
_nullifierIn2,
_noteOut1,
_noteOut2,
_noteFooter1,
_noteFooter2
);
_verifyProof(_proof, _buildJoinSplitInputs(inputs), "joinSplit");
_registerNoteFooter(_noteFooter1);
_registerNoteFooter(_noteFooter2);
_postWithdraw(_nullifierIn1);
_postWithdraw(_nullifierIn2);
_postDeposit(_noteOut1);
_postDeposit(_noteOut2);
emit JoinSplit(_nullifierIn1, _nullifierIn2, _noteOut1, _noteOut2);
}
function join(
bytes32 _merkleRoot,
bytes32 _nullifierIn1,
bytes32 _nullifierIn2,
bytes32 _noteOut,
bytes32 _noteFooter,
bytes calldata _proof
) public payable {
_validateMerkleRootIsAllowed(_merkleRoot);
_validateNullifierIsNotUsed(_nullifierIn1);
_validateNullifierIsNotUsed(_nullifierIn2);
_validateNullifierIsNotLocked(_nullifierIn1);
_validateNullifierIsNotLocked(_nullifierIn2);
_validateNoteIsNotCreated(_noteOut);
_validateNoteFooterIsNotUsed(_noteFooter);
JoinRawInputs memory inputs = JoinRawInputs(
_merkleRoot,
_nullifierIn1,
_nullifierIn2,
_noteOut,
_noteFooter
);
_verifyProof(_proof, _buildJoinInputs(inputs), "join");
_registerNoteFooter(_noteFooter);
_postWithdraw(_nullifierIn1);
_postWithdraw(_nullifierIn2);
_postDeposit(_noteOut);
emit Join(_nullifierIn1, _nullifierIn2, _noteOut);
}
}
文件 6 的 18:DarkpoolInputBuilder.sol
pragma solidity ^0.8.20;
import {BaseInputBuilder} from "./base/BaseInputBuilder.sol";
contract DarkpoolInputBuilder is BaseInputBuilder {
struct DepositRawInputs {
address owner;
bytes32 noteCommitment;
address asset;
uint256 amount;
bytes32 noteFooter;
}
struct WithdrawRawInputs {
address recipient;
bytes32 merkleRoot;
address asset;
uint256 amount;
bytes32 nullifier;
address relayer;
}
struct TransferRawInputs {
bytes32 merkleRoot;
address asset;
uint256 amount;
bytes32 nullifierIn;
bytes32 noteOut;
bytes32 noteFooter;
}
struct SplitRawInputs {
bytes32 merkleRoot;
bytes32 nullifierIn1;
bytes32 noteOut1;
bytes32 noteOut2;
bytes32 noteFooter1;
bytes32 noteFooter2;
}
struct JoinSplitRawInputs {
bytes32 merkleRoot;
bytes32 nullifierIn1;
bytes32 nullifierIn2;
bytes32 noteOut1;
bytes32 noteOut2;
bytes32 noteFooter1;
bytes32 noteFooter2;
}
struct JoinRawInputs {
bytes32 merkleRoot;
bytes32 nullifierIn1;
bytes32 nullifierIn2;
bytes32 noteOut1;
bytes32 noteFooter1;
}
struct SwapRawInputs {
bytes32 merkleRoot;
bytes32 aliceNullifier;
bytes32 aliceOut;
bytes32 bobNullifier;
bytes32 bobOut;
bytes32 aliceNoteFooter;
bytes32 bobNoteFooter;
}
constructor(uint256 primeField) BaseInputBuilder(primeField) {}
function _buildDepositInputs(
DepositRawInputs memory _rawInputs
) internal pure returns (bytes32[] memory) {
bytes32[] memory inputs = new bytes32[](5);
inputs[0] = _bytifyToNoir(_rawInputs.owner);
inputs[1] = bytes32(_rawInputs.noteCommitment);
inputs[2] = _bytifyToNoir(_rawInputs.asset);
inputs[3] = bytes32(_rawInputs.amount);
inputs[4] = _rawInputs.noteFooter;
return inputs;
}
function _buildWithdrawInputs(
WithdrawRawInputs memory _rawInputs
) internal pure returns (bytes32[] memory) {
bytes32[] memory inputs = new bytes32[](6);
inputs[0] = _bytifyToNoir(_rawInputs.recipient);
inputs[1] = _rawInputs.merkleRoot;
inputs[2] = _bytifyToNoir(_rawInputs.asset);
inputs[3] = bytes32(_rawInputs.amount);
inputs[4] = _rawInputs.nullifier;
inputs[5] = _bytifyToNoir(_rawInputs.relayer);
return inputs;
}
function _buildTransferInputs(
TransferRawInputs memory _rawInputs
) internal pure returns (bytes32[] memory) {
bytes32[] memory inputs = new bytes32[](6);
inputs[0] = _rawInputs.merkleRoot;
inputs[1] = _bytifyToNoir(_rawInputs.asset);
inputs[2] = bytes32(_rawInputs.amount);
inputs[3] = _rawInputs.nullifierIn;
inputs[4] = _rawInputs.noteOut;
inputs[5] = _rawInputs.noteFooter;
return inputs;
}
function _buildSplitInputs(
SplitRawInputs memory _rawInputs
) internal pure returns (bytes32[] memory) {
bytes32[] memory inputs = new bytes32[](6);
inputs[0] = _rawInputs.merkleRoot;
inputs[1] = _rawInputs.nullifierIn1;
inputs[2] = _rawInputs.noteOut1;
inputs[3] = _rawInputs.noteOut2;
inputs[4] = _rawInputs.noteFooter1;
inputs[5] = _rawInputs.noteFooter2;
return inputs;
}
function _buildJoinSplitInputs(
JoinSplitRawInputs memory _rawInputs
) internal pure returns (bytes32[] memory) {
bytes32[] memory inputs = new bytes32[](7);
inputs[0] = _rawInputs.merkleRoot;
inputs[1] = _rawInputs.nullifierIn1;
inputs[2] = _rawInputs.nullifierIn2;
inputs[3] = _rawInputs.noteOut1;
inputs[4] = _rawInputs.noteOut2;
inputs[5] = _rawInputs.noteFooter1;
inputs[6] = _rawInputs.noteFooter2;
return inputs;
}
function _buildJoinInputs(
JoinRawInputs memory _rawInputs
) internal pure returns (bytes32[] memory) {
bytes32[] memory inputs = new bytes32[](5);
inputs[0] = _rawInputs.merkleRoot;
inputs[1] = _rawInputs.nullifierIn1;
inputs[2] = _rawInputs.nullifierIn2;
inputs[3] = _rawInputs.noteOut1;
inputs[4] = _rawInputs.noteFooter1;
return inputs;
}
function _buildSwapInputs(
SwapRawInputs memory _rawInputs
) internal pure returns (bytes32[] memory) {
bytes32[] memory inputs = new bytes32[](7);
inputs[0] = _rawInputs.merkleRoot;
inputs[1] = _rawInputs.aliceNullifier;
inputs[2] = _rawInputs.aliceOut;
inputs[3] = _rawInputs.aliceNoteFooter;
inputs[4] = _rawInputs.bobNullifier;
inputs[5] = _rawInputs.bobOut;
inputs[6] = _rawInputs.bobNoteFooter;
return inputs;
}
}
文件 7 的 18:IAssetPool.sol
pragma solidity >=0.8.20;
interface IAssetPool {
function setAssetManager(address assetManager,bool registered) external;
function release(address tokenOrNft, address to, uint256 amountOrNftId) external;
function release(address payable to, uint256 amount) external;
function getAssetManagerRegistration( address assetManager)
external view returns(bool);
}
文件 8 的 18:IComplianceManager.sol
pragma solidity >=0.8.20;
interface IComplianceManager {
function isAuthorized(address observer, address subject) external returns (bool);
}
文件 9 的 18:IERC20.sol
pragma solidity ^0.8.20;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
文件 10 的 18:IERC20Permit.sol
pragma solidity ^0.8.20;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
文件 11 的 18:IFeeManager.sol
pragma solidity >=0.8.20;
interface IFeeManager {
function calculateFee(
uint256 amount,
uint256 relayerRefund
) external view returns (uint256, uint256, uint256);
function calculateFee(
uint256[4] calldata amount,
uint256[4] calldata relayerRefund
) external view returns (uint256[4] memory, uint256[4] memory, uint256[4] memory);
function calculateFeeForFSN(
uint256[4] calldata amount,
uint256[4] calldata relayerRefund
) external view returns (uint256[] memory, uint256[4] memory, uint256[4] memory);
}
文件 12 的 18:IMerkleTreeOperator.sol
pragma solidity >=0.8.20;
interface IMerkleTreeOperator {
function appendMerkleLeaf(bytes32 leaf) external;
function setNoteCommitmentCreated(bytes32 commitment) external;
function setNullifierUsed(bytes32 nullifier) external;
function setNullifierLocked(bytes32 nullifier, bool locked) external;
function setNoteFooterUsed(bytes32 noteFooter) external;
function isRelayerRegistered(address _relayer) external view returns (bool);
function merkleRootIsAllowed(
bytes32 _merkleRoot
) external view returns (bool);
function nullifierIsNotUsed(
bytes32 _nullifier
) external view returns (bool);
function nullifierIsNotLocked(
bytes32 _nullifier
) external view returns (bool);
function noteIsNotCreated(
bytes32 _noteCommitment
) external view returns (bool);
function noteFooterIsNotUsed(
bytes32 _noteFooter
) external view returns (bool);
function getMerkleRoot() external view returns (bytes32);
function getMerklePath(
bytes32 _noteCommitment
) external view returns (bytes32[] memory, bool[] memory, bytes32);
}
文件 13 的 18:IMimc254.sol
pragma solidity >=0.8.20;
interface IMimc254 {
enum NoteDomainSeparator {
FUNGIBLE,
NON_FUNGIBLE
}
function mimcBn254(uint256[] memory array) external view returns (uint256);
}
文件 14 的 18:IRelayerHub.sol
pragma solidity >=0.8.20;
interface IRelayerHub {
function isRelayerRegistered(address _relayer) external view returns (bool);
}
文件 15 的 18:IVerifier.sol
pragma solidity >=0.8.20;
interface IVerifier {
function verify(
bytes calldata _proof,
bytes32[] calldata _publicInputs
) external view returns (bool);
}
文件 16 的 18:IVerifierHub.sol
pragma solidity ^0.8.20;
import {IVerifier} from "./IVerifier.sol";
interface IVerifierHub {
function setVerifier(string memory verifierName, address addr) external;
function getVerifierNames() external returns (string[] memory);
function getVerifier(
string memory verifierName
) external view returns (IVerifier);
}
文件 17 的 18:Ownable.sol
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
error OwnableUnauthorizedAccount(address account);
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 18 的 18:SafeERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
error SafeERC20FailedOperation(address token);
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}
{
"compilationTarget": {
"contracts/core/DarkpoolAssetManager.sol": "DarkpoolAssetManager"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 4000
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"assetPoolERC20","type":"address"},{"internalType":"address","name":"assetPoolERC721","type":"address"},{"internalType":"address","name":"assetPoolETH","type":"address"},{"internalType":"address","name":"verifierHub","type":"address"},{"internalType":"address","name":"relayerHub","type":"address"},{"internalType":"address","name":"feeManager","type":"address"},{"internalType":"address","name":"comlianceManager","type":"address"},{"internalType":"address","name":"merkleTreeOperator","type":"address"},{"internalType":"address","name":"mimc254","type":"address"},{"internalType":"address","name":"initialOwner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidNoteParameters","type":"error"},{"inputs":[],"name":"MerkleRootNotAllowed","type":"error"},{"inputs":[],"name":"NoteAlreadyCreated","type":"error"},{"inputs":[],"name":"NoteFooterDuplicated","type":"error"},{"inputs":[],"name":"NoteFooterUsed","type":"error"},{"inputs":[],"name":"NullifierLocked","type":"error"},{"inputs":[],"name":"NullifierUsed","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"RelayerMismatch","type":"error"},{"inputs":[],"name":"RelayerNotRegistered","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"bytes32","name":"noteOut","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"asset","type":"address"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"nullifierIn1","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"nullifierIn2","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"noteOut1","type":"bytes32"}],"name":"Join","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"nullifierIn1","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"nullifierIn2","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"noteOut1","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"noteOut2","type":"bytes32"}],"name":"JoinSplit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"nullifierIn","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"noteOut1","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"noteOut2","type":"bytes32"}],"name":"Split","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"nullifierIn","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"bytes32","name":"noteOut","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"noteFooter","type":"bytes32"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"nullifierIn","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"ASSET_ETH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ETH_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"P","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes32","name":"_noteCommitment","type":"bytes32"},{"internalType":"bytes32","name":"_noteFooter","type":"bytes32"},{"internalType":"bytes","name":"_proof","type":"bytes"}],"name":"depositERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_noteCommitment","type":"bytes32"},{"internalType":"bytes32","name":"_noteFooter","type":"bytes32"},{"internalType":"bytes","name":"_proof","type":"bytes"}],"name":"depositETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getAssetPoolERC20","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAssetPoolERC721","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAssetPoolETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getComplianceManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFeeManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMerkleTreeOperator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMimc254","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRelayerHub","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVerifierHub","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"},{"internalType":"bytes32","name":"_nullifierIn1","type":"bytes32"},{"internalType":"bytes32","name":"_nullifierIn2","type":"bytes32"},{"internalType":"bytes32","name":"_noteOut","type":"bytes32"},{"internalType":"bytes32","name":"_noteFooter","type":"bytes32"},{"internalType":"bytes","name":"_proof","type":"bytes"}],"name":"join","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"},{"internalType":"bytes32","name":"_nullifierIn1","type":"bytes32"},{"internalType":"bytes32","name":"_nullifierIn2","type":"bytes32"},{"internalType":"bytes32","name":"_noteOut1","type":"bytes32"},{"internalType":"bytes32","name":"_noteOut2","type":"bytes32"},{"internalType":"bytes32","name":"_noteFooter1","type":"bytes32"},{"internalType":"bytes32","name":"_noteFooter2","type":"bytes32"},{"internalType":"bytes","name":"_proof","type":"bytes"}],"name":"joinSplit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"releaseToAsssetPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"assetPoolERC20","type":"address"}],"name":"setAssetPoolERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"assetPoolERC721","type":"address"}],"name":"setAssetPoolERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"assetPoolETH","type":"address"}],"name":"setAssetPoolETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"complianceManager","type":"address"}],"name":"setComplianceManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"feeManager","type":"address"}],"name":"setFeeManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"relayerHub","type":"address"}],"name":"setRelayerHub","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"verifierHub","type":"address"}],"name":"setVerifierHub","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"},{"internalType":"bytes32","name":"_nullifierIn1","type":"bytes32"},{"internalType":"bytes32","name":"_noteOut1","type":"bytes32"},{"internalType":"bytes32","name":"_noteOut2","type":"bytes32"},{"internalType":"bytes32","name":"_noteFooter1","type":"bytes32"},{"internalType":"bytes32","name":"_noteFooter2","type":"bytes32"},{"internalType":"bytes","name":"_proof","type":"bytes"}],"name":"split","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"},{"internalType":"bytes32","name":"_nullifierIn","type":"bytes32"},{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes32","name":"_noteOut","type":"bytes32"},{"internalType":"bytes32","name":"_noteFooter","type":"bytes32"},{"internalType":"bytes","name":"_proof","type":"bytes"}],"name":"transfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"bytes","name":"_proof","type":"bytes"},{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"},{"internalType":"bytes32","name":"_nullifier","type":"bytes32"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"address","name":"_relayer","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_relayerGasFee","type":"uint256"}],"name":"withdrawERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_proof","type":"bytes"},{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"},{"internalType":"bytes32","name":"_nullifier","type":"bytes32"},{"internalType":"address payable","name":"_recipient","type":"address"},{"internalType":"address payable","name":"_relayer","type":"address"},{"internalType":"uint256","name":"_relayerGasFee","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]