Skip to content
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ This script will:

#### Ethena Deposit flow

Look at [function _doDeposit()](test/BaseIntegrationMorpho.t.sol#L1000) for a reference implementation of the flow.
Look at [function _doDeposit()](test/BaseMorphoUSDC.t.sol#L1000) for a reference implementation of the flow.

1. Website User (called Client in contracts) calls Backend with its (User's) Ethereum address and some Merchant info.

Expand Down Expand Up @@ -96,7 +96,7 @@ Look at [function _doDeposit()](test/BaseIntegrationMorpho.t.sol#L1000) for a re

#### Ethena Withdrawal flow

Look at [function _doWithdraw()](test/BaseIntegrationMorpho.t.sol#L1024) for a reference implementation of the flow.
Look at [function _doWithdraw()](test/BaseMorphoUSDC.t.sol#L1024) for a reference implementation of the flow.

1. Client-side JS code prepares all the necessary data for the Ethena `cooldownShares` function.

Expand Down
117 changes: 117 additions & 0 deletions script/RunTestDepositNativeOptimism.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// SPDX-FileCopyrightText: 2025 P2P Validator <[email protected]>
// SPDX-License-Identifier: MIT

pragma solidity 0.8.27;

import "../lib/forge-std/src/Vm.sol";
import "../src/adapters/superform/p2pSuperformProxyFactory/P2pSuperformProxyFactory.sol";
import {Script} from "forge-std/Script.sol";
import {PermitHash} from "../src/@permit2/libraries/PermitHash.sol";

contract RunTestDepositNativeOptimism is Script {
using SafeERC20 for IERC20;

address constant SuperformRouter = 0xa195608C2306A26f727d5199D5A382a4508308DA;
address constant SuperPositions = 0x01dF6fb6a28a89d6bFa53b2b3F20644AbF417678;
address constant P2pTreasury = 0x641ca805C75cC5D1ffa78C0181Aba1F77BD17904;

address constant USDT = 0x94b008aA00579c1307B0EF2c499aD98a8ce58e58;
uint256 constant SigDeadline = 1746420983;
uint48 constant ClientBasisPointsOfProfit = 8700; // 13% fee
uint48 constant ClientBasisPointsOfDeposit = 10000; // 0% fee
uint256 constant DepositAmount = 12340000000000000;

P2pSuperformProxyFactory factory;
address proxyAddress;

function run()
external
{
uint256 deployerKey = vm.envUint("PRIVATE_KEY");
Vm.Wallet memory wallet = vm.createWallet(deployerKey);

factory = P2pSuperformProxyFactory(0xEF3c3034FD8E396b11713183C7080811E6cFD026);
proxyAddress = factory.predictP2pYieldProxyAddress(
wallet.addr,
ClientBasisPointsOfDeposit,
ClientBasisPointsOfProfit
);

IAllowanceTransfer.PermitSingle memory permitSingleForP2pYieldProxy;
bytes memory permit2SignatureForP2pYieldProxy;
bytes memory p2pSignerSignature = _getP2pSignerSignature(
wallet.addr,
ClientBasisPointsOfDeposit,
ClientBasisPointsOfProfit,
SigDeadline
);

bytes memory superformCalldata = hex'b19dcc3300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000a00000001b8138fff124dd7f91abf412b73be453fb140568c00000000000000000000000000000000000000000000000000248238191b12ce00000000000000000000000000000000000000000000000000247a8437f408dc00000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b3055ebe6b9c43c86fb684d512123fd88f8a6f19000000000000000000000000b3055ebe6b9c43c86fb684d512123fd88f8a6f190000000000000000000000000000000000000000000000000000000000000c2000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000065000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000002bd72a2487400000000000000000000000000000000000000000000000000000000000000009a44630a0d8f8cf2c5ebadc417dcbfbeb1f04438e7bbf259fee0d2d9c72f870d72eba1fc7a300000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000b8138fff124dd7f91abf412b73be453fb140568c0000000000000000000000000000000000000000000000000022aee87e401eaa0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000d7375706572666f726d2e78797a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a30783030303030303030303030303030303030303030303030303030303030303030303030303030303000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000006131b5fae19ea4f9d964eac0408e4408b66337b50000000000000000000000006131b5fae19ea4f9d964eac0408e4408b66337b500000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f32b1c2345538c0c6f582fcb022739c4a194ebb000000000000000000000000000000000000000000000000002bd72a2487400000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000006e4e21fd0e90000000000000000000000000000000000000000000000000000000000000020000000000000000000000000c7d3ab410d49b664d03fe5b1038852ac852b1b29000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000164010300000048000000ba12222222228d8ba445958a75a0704d566bf2c839965c9dab5448482cf7e002f583c812ceb53046000100000000000000000003020000000000000000002bd72a248740000b00000039000000ba12222222228d8ba445958a75a0704d566bf2c89da11ff60bfc5af527f58fd61679c3ac98d040d900000000000000000000010000010b0000002e02000000ee1bac98527a9fdd57fccf967817215b083ce1f001010000000000000000000000000000000100eed0b40aeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1f32b1c2345538c0c6f582fcb022739c4a194ebb1231deb6f5749ef6ce6943a275a1d3e7486f4eae0000000000000000000000006809faee00000054000000000000000000000000000000000000000000000000000000000000000000000000000000000000000264838984000000000000000000248238191b12ce4f82e73edb06d29ff62c91ec8f5ff06571bdeb2900000000000000000000000000000000000000000000000000000000000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000000000000000001f32b1c2345538c0c6f582fcb022739c4a194ebb0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000001231deb6f5749ef6ce6943a275a1d3e7486f4eae000000000000000000000000000000000000000000000000002bd72a248740000000000000000000000000000000000000000000000000000022aee87e401eaa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025d7b22536f75726365223a226c692e6669222c22416d6f756e74496e555344223a2232312e353635373136363038383835303538222c22416d6f756e744f7574555344223a2232312e3533303838303233373730393835222c22526566657272616c223a22222c22466c616773223a302c22416d6f756e744f7574223a223130323736323736363132353637373538222c2254696d657374616d70223a313734353438333332362c22526f7574654944223a2263326437633637662d356338622d343961312d613232652d616164613631383065386234222c22496e74656772697479496e666f223a7b224b65794944223a2231222c225369676e6174757265223a224d34424131515533726935564b424148616e443250687435567130654654314c6e7056354c542f50474a364259514379714e7838744855412b6a486633414a64454c74625378635658544e6e56763349317a3431746c68774f524c576475596664426e394a55446b4373624f5a58474e543644335554694e636c47485032356170415035465950706164624c6c34377653616c59676d78795565585a3946704d49686944446442737431344e53472f4c596a6e345a5a6e697276697770776835534b6c74396d7074674538436c432f456b35594351636c424b64337765697767316b546c436e36573543553547786b643742634b544a76504e4a6c70496a307962674a523742384848472b574f535865686c4d3865635a4d762b7242675570504c756e4b4552644f7942492f48584b4343506c4654324144775171367957394e67725249386e5557524a37544e4554513150334e33413d3d227d7d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'; //abi.encodeCall(IBaseRouter.singleDirectSingleVaultDeposit, (req));

vm.startBroadcast(deployerKey);
if (IERC20(USDT).allowance(wallet.addr, address(Permit2Lib.PERMIT2)) == 0) {
IERC20(USDT).safeApprove(address(Permit2Lib.PERMIT2), type(uint256).max);
}
factory.deposit{value: (12340000000000000) * 113 / 100}(
permitSingleForP2pYieldProxy,
permit2SignatureForP2pYieldProxy,

superformCalldata,

ClientBasisPointsOfDeposit,
ClientBasisPointsOfProfit,
SigDeadline,
p2pSignerSignature
);
vm.stopBroadcast();
}

function _getPermitSingleForP2pYieldProxy() private returns(IAllowanceTransfer.PermitSingle memory) {
uint256 deployerKey = vm.envUint("PRIVATE_KEY");
Vm.Wallet memory wallet = vm.createWallet(deployerKey);
(, , uint48 nonce) = IAllowanceTransfer(0x000000000022D473030F116dDEE9F6B43aC78BA3).allowance(wallet.addr, USDT, proxyAddress);

IAllowanceTransfer.PermitDetails memory permitDetails = IAllowanceTransfer.PermitDetails({
token: USDT,
amount: uint160(DepositAmount),
expiration: uint48(SigDeadline),
nonce: nonce
});

// data for factory
IAllowanceTransfer.PermitSingle memory permitSingleForP2pYieldProxy = IAllowanceTransfer.PermitSingle({
details: permitDetails,
spender: proxyAddress,
sigDeadline: SigDeadline
});

return permitSingleForP2pYieldProxy;
}

function _getPermit2SignatureForP2pYieldProxy(IAllowanceTransfer.PermitSingle memory permitSingleForP2pYieldProxy) private view returns(bytes memory) {
bytes32 permitSingleForP2pYieldProxyHash = factory.getPermit2HashTypedData(PermitHash.hash(permitSingleForP2pYieldProxy));
(uint8 v1, bytes32 r1, bytes32 s1) = vm.sign(vm.envUint("PRIVATE_KEY"), permitSingleForP2pYieldProxyHash);
bytes memory permit2SignatureForP2pYieldProxy = abi.encodePacked(r1, s1, v1);
return permit2SignatureForP2pYieldProxy;
}

function _getP2pSignerSignature(
address _clientAddress,
uint48 _clientBasisPointsOfDeposit,
uint48 _clientBasisPointsOfProfit,
uint256 _sigDeadline
) private view returns(bytes memory) {
// p2p signer signing
bytes32 hashForP2pSigner = factory.getHashForP2pSigner(
_clientAddress,
_clientBasisPointsOfDeposit,
_clientBasisPointsOfProfit,
_sigDeadline
);
bytes32 ethSignedMessageHashForP2pSigner = ECDSA.toEthSignedMessageHash(hashForP2pSigner);
(uint8 v2, bytes32 r2, bytes32 s2) = vm.sign(vm.envUint("PRIVATE_KEY"), ethSignedMessageHashForP2pSigner);
bytes memory p2pSignerSignature = abi.encodePacked(r2, s2, v2);
return p2pSignerSignature;
}
}

40 changes: 40 additions & 0 deletions script/RunTestWithdrawNativeOptimism.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// SPDX-FileCopyrightText: 2025 P2P Validator <[email protected]>
// SPDX-License-Identifier: MIT

pragma solidity 0.8.27;

import "../lib/forge-std/src/Vm.sol";
import "../src/adapters/superform/p2pSuperformProxyFactory/P2pSuperformProxyFactory.sol";
import {Script} from "forge-std/Script.sol";
import {PermitHash} from "../src/@permit2/libraries/PermitHash.sol";

contract RunTestWithdrawNativeOptimism is Script {
using SafeERC20 for IERC20;

uint48 constant ClientBasisPointsOfProfit = 8700; // 13% fee
uint48 constant ClientBasisPointsOfDeposit = 10000; // 0% fee

P2pSuperformProxyFactory factory;
address proxyAddress;

function run()
external
{
uint256 deployerKey = vm.envUint("PRIVATE_KEY");
Vm.Wallet memory wallet = vm.createWallet(deployerKey);

factory = P2pSuperformProxyFactory(0xEF3c3034FD8E396b11713183C7080811E6cFD026);
proxyAddress = factory.predictP2pYieldProxyAddress(
wallet.addr,
ClientBasisPointsOfDeposit,
ClientBasisPointsOfProfit
);

bytes memory superformCalldata = hex'407c7b1d00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000a00000001b8138fff124dd7f91abf412b73be453fb140568c00000000000000000000000000000000000000000000000000246bce0022c1630000000000000000000000000000000000000000000000000024737ec621e13800000000000000000000000000000000000000000000000000000000000013880000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000076000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b3055ebe6b9c43c86fb684d512123fd88f8a6f19000000000000000000000000b3055ebe6b9c43c86fb684d512123fd88f8a6f19000000000000000000000000000000000000000000000000000000000000078000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000065000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005044630a0d83e20e4c98c0e7de0d36b81a9b48d0c4a88617f17c0d65659ae71752f4c62daba00000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000b3055ebe6b9c43c86fb684d512123fd88f8a6f190000000000000000000000000000000000000000000000000015d983e600aeef0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000d7375706572666f726d2e78797a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a3078303030303030303030303030303030303030303030303030303030303030303030303030303030300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000060e8c01e8e39b10202e39e62001f08092cc03ca000000000000000000000000060e8c01e8e39b10202e39e62001f08092cc03ca0000000000000000000000001f32b1c2345538c0c6f582fcb022739c4a194ebb00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024737ec621e13800000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000002442646478b0000000000000000000000001f32b1c2345538c0c6f582fcb022739c4a194ebb0000000000000000000000000000000000000000000000000024737ec621e138000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000000000000000000000000000000000000000000015d983e600aeef0000000000000000000000001231deb6f5749ef6ce6943a275a1d3e7486f4eae00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000014c021f32b1c2345538c0c6f582fcb022739c4a194ebb0395550104f6c85a1b00f6d9b75f91fd23835974cc07e65c01060e8c01e8e39b10202e39e62001f08092cc03ca66660195d7d146ae40d4822c2750276b54b6eed530d37401060e8c01e8e39b10202e39e62001f08092cc03caffff01766854992bd5363ebeeff0113f5a5795796befab01060e8c01e8e39b10202e39e62001f08092cc03ca017f5c764cbc14f9669b88837ca1490cca17c3160701ffff0185149247691df622eaf1a8bd0cafd40bc45154a900060e8c01e8e39b10202e39e62001f08092cc03ca0194b008aa00579c1307b0ef2c499ad98a8ce58e5801ffff01c858a329bf053be78d6239c4a4343b8fbd21472b00060e8c01e8e39b10202e39e62001f08092cc03ca01420000000000000000000000000000000000000601ffff02001231deb6f5749ef6ce6943a275a1d3e7486f4eae0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000';

vm.startBroadcast(deployerKey);
P2pSuperformProxy(payable(proxyAddress)).withdraw(superformCalldata);
vm.stopBroadcast();
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@

pragma solidity 0.8.27;
import "../../../@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import "../../../p2pYieldProxy/IP2pYieldProxy.sol";

interface IP2pSuperformProxy is IERC1155Receiver {
interface IP2pSuperformProxy is IP2pYieldProxy, IERC1155Receiver {
event P2pSuperformProxy__Claimed(
address indexed _token,
uint256 _totalAmount,
Expand Down
16 changes: 7 additions & 9 deletions src/adapters/superform/p2pSuperformProxy/P2pSuperformProxy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ error P2pSuperformProxy__ReceiverAddressSPShouldBeP2pSuperformProxy(
);
error P2pSuperformProxy__AssetShouldNotBeZeroAddress();
error P2pSuperformProxy__NotClaimed(address _token);
error P2pSuperformProxy__WrongFundingAssetAmountsCount();
error P2pSuperformProxy__IncorrectNativeFundingAssetAmount();


contract P2pSuperformProxy is P2pYieldProxy, IP2pSuperformProxy {
Expand Down Expand Up @@ -68,7 +66,7 @@ contract P2pSuperformProxy is P2pYieldProxy, IP2pSuperformProxy {
IAllowanceTransfer.PermitSingle calldata _permitSingleForP2pYieldProxy,
bytes calldata _permit2SignatureForP2pYieldProxy,
bytes calldata _superformCalldata
) external override payable {
) external override(P2pYieldProxy, IP2pYieldProxy) payable {
require (_superformCalldata.length > 4, P2pSuperformProxy__SuperformCalldataTooShort());

bytes4 selector = bytes4(_superformCalldata[:4]);
Expand Down Expand Up @@ -119,12 +117,6 @@ contract P2pSuperformProxy is P2pYieldProxy, IP2pSuperformProxy {
isNative,
nativeAmountToDepositAfterFee
);

IERC1155A(i_superPositions).increaseAllowance(
i_yieldProtocolAddress,
req.superformData.superformId,
req.superformData.outputAmount
);
}

function withdraw(
Expand Down Expand Up @@ -159,6 +151,12 @@ contract P2pSuperformProxy is P2pYieldProxy, IP2pSuperformProxy {
}
require (asset != address(0), P2pSuperformProxy__AssetShouldNotBeZeroAddress());

IERC1155A(i_superPositions).increaseAllowance(
i_yieldProtocolAddress,
req.superformData.superformId,
req.superformData.amount
);

_withdraw(
req.superformData.superformId,
asset,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@

pragma solidity 0.8.27;
import "../../../@permit2/interfaces/IAllowanceTransfer.sol";
import "../../../p2pYieldProxyFactory/IP2pYieldProxyFactory.sol";

/// @dev External interface of P2pSuperformProxyFactory
interface IP2pSuperformProxyFactory {
interface IP2pSuperformProxyFactory is IP2pYieldProxyFactory {
/// @dev Checks if the claim is valid
/// @param _p2pOperatorToCheck The P2pOperator to check
function checkClaim(
Expand Down
Loading