Conversation
contracts/usdfree/Interfaces.sol
Outdated
| - token is used to inform the final user action. The action is made with (tokenReq.token, balanceOf(tokenReq.token, address(this))) on the executor | ||
| */ | ||
| bytes tokenReq; // (token, amount) | ||
| // NOTE: if an order is sponsored, this is forced by the API to be one of the trusted relayers, to prevent self- |
There was a problem hiding this comment.
how does the API enforce this?
There was a problem hiding this comment.
For sponsored orders, API is fully responsible for keeping it's own database of orderId => sponsorshipAmount, so when submitterReq is not one of the trusted entities, the API just doesn't put the orderId into the DB
contracts/usdfree/Interfaces.sol
Outdated
|
|
||
| // The struct that the user signs/submits. Contains all of the user's preferences | ||
| struct Order { | ||
| // NOTE: there's no (token, amount) here that the user submits. That's provided separately at the time of the submit.. call |
There was a problem hiding this comment.
I think your comment is incomplete here?
There was a problem hiding this comment.
It is complete. submit.. here just means OrderGateway.submit or OrderGateway.submitWithAuction
When submission is direct by the user, it's an approval-based flow and relies on approvals and (token, amount) decoded from funding argument.
If submission is gasless, funding still holds the relevant information, e.g. in IPermit2.PermitTransferFrom:
struct TokenPermissions {
address token;
uint256 amount;
}
struct PermitTransferFrom {
TokenPermissions permitted;
uint256 nonce;
uint256 deadline;
}
contracts/usdfree/Interfaces.sol
Outdated
| - amount == 0 means no enforccement | ||
| - token is used to inform the final user action. The action is made with (tokenReq.token, balanceOf(tokenReq.token, address(this))) on the executor | ||
| */ | ||
| bytes tokenReq; // (token, amount) |
There was a problem hiding this comment.
What's the thinking here that this is type bytes if this is always going to be abi.encode(address, uint256)? I guess i'm just wondering why not just explicitly require amount and token instead of squashing them into bytes
There was a problem hiding this comment.
To make this extensible without changing the format of the ExecutionStep. I think the idea is more so make it
(tokenReqTypeEnum, someOtherData)
Which, to start can be something like (0, (token, amount))
But also could be something like an onchain dutch auction: (1, (startingPrice, startingTime, endPrice))
This is interpreted and checked by the internal function on the Executor contract, so as we expand it's functionality, we can add more types to the token requirement
contracts/usdfree/Interfaces.sol
Outdated
| // A struct that represents some change in user requirement as a result of the auction | ||
| struct Change { | ||
| // enum for: token, deadline, submitter or custom | ||
| uint8 typ; |
There was a problem hiding this comment.
type?
| uint8 typ; | |
| uint8 type; |
There was a problem hiding this comment.
Can't use type, it's a reserved keyword
contracts/usdfree/Interfaces.sol
Outdated
| struct Change { | ||
| // enum for: token, deadline, submitter or custom | ||
| uint8 typ; | ||
| // NOTE: if a type is custom, data can inlcude an index of the otherStaticReqs that the auction wants to change. The |
There was a problem hiding this comment.
| // NOTE: if a type is custom, data can inlcude an index of the otherStaticReqs that the auction wants to change. The | |
| // NOTE: if a type is custom, data can include an index of the otherStaticReqs that the auction wants to change. The |
contracts/usdfree/Interfaces.sol
Outdated
| // enum for: token, deadline, submitter or custom | ||
| uint8 typ; | ||
| // NOTE: if a type is custom, data can inlcude an index of the otherStaticReqs that the auction wants to change. The | ||
| // funtion to apply the change has to be implemented on the OrderGateway for this to work |
There was a problem hiding this comment.
| // funtion to apply the change has to be implemented on the OrderGateway for this to work | |
| // function to apply the change has to be implemented on the OrderGateway for this to work |
contracts/usdfree/Interfaces.sol
Outdated
| // NOTE: only approval-based token pulls are supported from submitters | ||
| TokenAmount[] extraFunding; | ||
| bytes actions; // MulticallHandler.Instructions or weiroll (support can be expanded to any format) | ||
| bytes deobfuscation; // if user's finalAction is obfuscated |
There was a problem hiding this comment.
how would deobfuscation bytes work?
There was a problem hiding this comment.
The OrderStore handles the deobfuscation. If length hashOrUserAction is 32 bytes, safe to assume it's a hash. Or we could just add a single byte at the start to specify whether this is obfuscated to start with.
Then the OrderStore receives deobfuscated data as a part of submitter data, checks against the hash and propagates to Executor. So the Executor never deals with deobfusaction
contracts/usdfree/Interfaces.sol
Outdated
| function execute( | ||
| // `ExecutionStep.tokenReq.token` | ||
| address token, | ||
| // `balanceOf(address(IExecutor), ExecutionStep.tokenReq.token)` |
There was a problem hiding this comment.
isn't the balanceOf step vulnerable to someone dropping tokens on to the contract?
There was a problem hiding this comment.
Is it a problem? Executor contract is not at all suitable for escrowing any funds (it allows submitter to do anything with the funds on the contract as long as the tokenReq is met). Seems fine
contracts/usdfree/README.md
Outdated
| - Checks requirements after submitter actions complete | ||
| - Calls IUserActionExecutor with token, amount, params, and remaining steps | ||
|
|
||
| **IUserActionExecutor** - Final action interface |
There was a problem hiding this comment.
Why is this called an I-contract, and what's the reasoning behind the naming? The executor/userActionExecutor names aren't the most intuitive to me
There was a problem hiding this comment.
I-contract to show that it's an interface and there are many implementations possible, in contrast to something like an Executor, which is a single contract.
As for name intuitiveness, these are open to change, open to suggestions!
contracts/usdfree/README.md
Outdated
| 2. **OrderGateway** applies auction changes if present (signed by auctionAuthority) | ||
| 3. **Executor** runs submitter actions | ||
| 4. **Executor** checks all requirements are met (token balance, submitter, deadline, etc.) | ||
| 5. **Executor** calls **IUserActionExecutor** with current step's action |
There was a problem hiding this comment.
So you keep mentioning in the docs that the Executor executes a single step. This implies that an action might have multiple steps. How would the execution flow look like for a multi step action? And what would a multi step action even do, in practice?
There was a problem hiding this comment.
Single step is executed on one chain. A step is:
- submitter actions
- check user reqs
- user action
What could 2 steps do?
For example, mint-burn + deposit into Hyperliquid:
[srcStep, dstStep]
- srcStep: tokenReq == input amount (so no submitter actions needed). user action = deposit into CCTP
- dstStep: check tokenReq (e.g. input from source - a few bps) + call
HyperliquidDepositHandler.depositToHypercore
Alternatively, a single-step similar thing could be:
[srcStep]
tokenReq == input amount, user action == deposit into spokepool such that message = HyperliquidDepositHandler interaction
In the case where there are 2 actions, mint-burn dst contracts are interacting with OrderStore. OrderStore on dst is analogous to OrderGateway on src, expect it doesn't apply auction changes and doesn't calculate orderId
Signed-off-by: Ihor Farion <ihor@umaproject.org>
Signed-off-by: Ihor Farion <ihor@umaproject.org>
Signed-off-by: Ihor Farion <ihor@umaproject.org>
Signed-off-by: Ihor Farion <ihor@umaproject.org>
Signed-off-by: Ihor Farion <ihor@umaproject.org>
Signed-off-by: Ihor Farion <ihor@umaproject.org>
Signed-off-by: Ihor Farion <ihor@umaproject.org>
Signed-off-by: Ihor Farion <ihor@umaproject.org>
Signed-off-by: Ihor Farion <ihor@umaproject.org>
Signed-off-by: Ihor Farion <ihor@umaproject.org>
Signed-off-by: Ihor Farion <ihor@umaproject.org>
Signed-off-by: Ihor Farion <ihor@umaproject.org>
a2e8692 to
0db06cc
Compare
Signed-off-by: Ihor Farion <ihor@umaproject.org>
Signed-off-by: Ihor Farion <ihor@umaproject.org>
Signed-off-by: Ihor Farion <ihor@umaproject.org>
Signed-off-by: Ihor Farion <ihor@umaproject.org>
Signed-off-by: Ihor Farion <ihor@umaproject.org>
Signed-off-by: Ihor Farion <ihor@umaproject.org>
Project overview
Why:
Improve sponsored system: the current iteration of the sponsored bridging system is limited to a specific use case: sponsored stable bridging into HyperLiquid using mint/burn bridges.
Unify Across product: mint/burn, Across, sponsored Phase0 are currently different parts of the stack that could benefit from unification in terms of both operational and UX sides.
Goals:
bridge tokens to other chain in a mechanism-agnostic way: CCTP, OFT, Across etc.
use a single upgradeable entry point for order submission so that the users don't ever have to re-approve and integrators don't have to maintain complicated mappings
support gasless
support best-path swapping on either source or destination or both
support user action after the desired amount of tokens is received on destination (like AAVE deposits or deposits to Hyperliquid Core etc.)
support sponsoring transactions to cover the bridge and / or swap fee partially or in full
support operation chaining: allow performing multiple cross-chain actions in a row
mitigate abuse of destination-side actions (e.g. by using obfuscation)
Outcomes:
Architecture for contracts, API and relayer, showing how the system would function together
Implementation of the above system
Closes ACP-10