Skip to content

feat: v5 + Spoke#1481

Open
grasphoper wants to merge 8 commits into
masterfrom
if/v5-iter2
Open

feat: v5 + Spoke#1481
grasphoper wants to merge 8 commits into
masterfrom
if/v5-iter2

Conversation

@grasphoper

@grasphoper grasphoper commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator
  • spoke v5:
    • fill when path.executor(see v5 repo) is SpokePool (spoke-as-executor)
    • fill through ADAPTER_CALL command (spoke-as-adapter)
  • small addition to Hyperliquid contracts for easier reuse in v5 repo

fusmanii and others added 5 commits June 24, 2026 14:12
Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>
* feat: SpokePool V5 fill

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

* add gateway param to all contracts

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

* address feedback

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

* require gateway

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

* update deploy scripts

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

* add _fillRelayV5

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

* faactor out _recordFill

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

* refactor _transferTokensToRecipient

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

* update comments

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

* add executeAcrossV5 call

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

* add nonV5Fill guard to rest of functions

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

* check for msg.value

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

* missing error

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

* tests

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

* return outputToken and recipientToSend from _transferTokensToRecipient

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

* check relayer provided message

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

* udpate var naming

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

* update _fillRelayV5 param names

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

* add nonReentrant

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

---------

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>
* init commit: SpokePool as v5 adapter for deposits

Signed-off-by: Ihor Farion <ihor@umaproject.org>

* impl _resolveDynamicParams

Signed-off-by: Ihor Farion <ihor@umaproject.org>

* change constructors of all Spokes

Signed-off-by: Ihor Farion <ihor@umaproject.org>

* bind to pathId instead

Signed-off-by: Ihor Farion <ihor@umaproject.org>

* improve comments, remove one static call

Signed-off-by: Ihor Farion <ihor@umaproject.org>

* move things around a bit

Signed-off-by: Ihor Farion <ihor@umaproject.org>

* only active v5 flow

Signed-off-by: Ihor Farion <ihor@umaproject.org>

* remove comment

Signed-off-by: Ihor Farion <ihor@umaproject.org>

* fix after-merge build + move structs

Signed-off-by: Ihor Farion <ihor@umaproject.org>

---------

Signed-off-by: Ihor Farion <ihor@umaproject.org>
* feat: SpokePool fill as adapter

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

* udpate struct names

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

* restructure the functions

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

* reduce natspec length

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>

---------

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>
* update Spoke to match new fill logic

Signed-off-by: Ihor Farion <ihor@umaproject.org>

* adjust tests

Signed-off-by: Ihor Farion <ihor@umaproject.org>

---------

Signed-off-by: Ihor Farion <ihor@umaproject.org>
@grasphoper grasphoper marked this pull request as ready for review July 2, 2026 05:36
* foundry profile and sizes

Signed-off-by: Ihor Farion <ihor@umaproject.org>

* remove spoke-as-adapter functionality

Signed-off-by: Ihor Farion <ihor@umaproject.org>

* remove size snapshots

Signed-off-by: Ihor Farion <ihor@umaproject.org>

---------

Signed-off-by: Ihor Farion <ihor@umaproject.org>
@grasphoper grasphoper requested review from fusmanii and tbwebb22 July 3, 2026 06:43
Comment thread contracts/spoke-pools/SpokePool.sol Outdated

V3RelayData memory relayData = V3RelayData({
depositor: fillJit.depositor,
recipient: fillInput.recipient,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the recipient and outputToken an input, while other fields are JIT? Not saying that's wrong, just trying to understand the reasoning.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

user's money is tied to the witness, which in turn gets constructed (waves hands) from input

  • input.recipient makes sure that when a pathId is emitted => the funds went to the user (same as having TRANSFER cmd in the general tape)
  • input.token + input.minAmount makes sure that no one can spam-create pathId from a user order without first spending at least minAmount (this acts as a sort of BALANCE_REQ)

So these two make spoke-as-executor similar to:

[BALANCE_REQ, TRANSFER(recipient), optional-handleV3]

Let's say we didn't commit to input.recipient:

  • pathId could be emitted for an unrelated fill that spammer would just send to self

If we didn't commit to token, minAmount:

  • pathId could be emitted with 1 wei

Also, take another tape:

[ADAPTER_CALL, TRANSFER-or-actions-from-input]

ADAPTER_CALL gets BALANCE_REQ included in it basically for free, giving us the same pathId guarantees as in the spoke-as-executor case.

If we didn't have these, we'd have to have a BALANCE_REQ in this flow. (just in the spirit of making simple flows more lean)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. The minAmount ties it together. I missed that in my review.

Comment thread contracts/spoke-pools/SpokePool.sol Outdated
inputToken: fillJit.inputToken,
outputToken: fillInput.outputToken,
inputAmount: fillJit.inputAmount,
outputAmount: fillJit.outputAmount,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any concerns around the case where someone sends an invalid fill (0 output amount), but the indexer thinks this is complete because the rest of the actions don't care about the output amount of the fill?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what minAmount protection gives us (see above). Even if minAmount is static (e.g. with 5% slippage), whereas fill.outputAmount is dynamic, noone can "just emit a pathId for free"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. I missed that.

Signed-off-by: Faisal Usmani <faisal.of.usmani@gmail.com>
mrice32
mrice32 previously approved these changes Jul 5, 2026

@mrice32 mrice32 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Signed-off-by: Ihor Farion <ihor@umaproject.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants