Skip to content

Pc/hzn 2833 - Facilitator design#127

Open
paolocappelletti wants to merge 12 commits intodevfrom
pc/HZN-2833
Open

Pc/hzn 2833 - Facilitator design#127
paolocappelletti wants to merge 12 commits intodevfrom
pc/HZN-2833

Conversation

@paolocappelletti
Copy link
Copy Markdown
Contributor

No description provided.

@paolocappelletti paolocappelletti changed the title Pc/hzn 2833 Pc/hzn 2833 - Facilitator design Mar 27, 2026
- `maxFeeValue` **remains ETH-only**, paid via `msg.value`
- Claims replace pull payments: `claim(tokenAddress, payee)` is the generic, permissionless, asset-aware claim mechanism
- Pending claims are tracked by `(payee, tokenAddress)`
- Token allowlists (global + per-app) gate which tokens are accepted
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.

There is only the global allowlist

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed

#### New function: `submitRequestFor`

```solidity
function submitRequestFor(
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.

Should submitRequestFor support also Deploy requests?

An EIP-712 typed data signature over the request parameters, proving the user authorized this specific request:

```
RequestAuthorization {
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.

Considering that the ecrecover can recover a valid address from a signature, given a wrong message, maybe it is safer to add the sender address inside the RequestAuthorization, so the contract can verify that the address from the ecrecover is the one expected.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

good observation: added

│ nonces[user]++
├─ 4. If assetAmount > 0: validate token allowlists
│ require(globalAllowedTokens[tokenAddress])
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.

I suppose it should reject the request if the tokenAddress is ETH, maybe it is better to be explicit

├─ 4. If assetAmount > 0: validate token allowlists
│ require(globalAllowedTokens[tokenAddress])
│ require(appAllowedTokens[applicationId][tokenAddress])
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.

appAllowedTokens doens't exist anymore

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed


#### Core Facilitation Endpoints

- **`POST /submit`** — Generic gasless submission. Accepts the user's EIP-712 request signature, EIP-3009 deposit signature (if `assetAmount > 0`), and request parameters. Calls `submitRequestFor()` on-chain. Works for any request type (`ASSOCIATEKEY`, `DEPOSIT`, `WITHDRAWAL`, `PROCESS`, etc.).
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.

The only requestType supported are "ASSOCIATEKEY", "Process", "DEPLOY" and "Deanonymization"


#### ASSOCIATEKEY

Works naturally with the facilitator: the user signs a request authorization with their key payload (133 bytes). The recovered address from the EIP-712 signature is the user whose key is being associated. No special handling needed.
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.

the key payload is no more only 133 bytes (at least, not always)


#### DEANONYMIZATION

Deanonymization will not be covered by the facilitator feature.
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.

This means the facilitator would reject a DEANONYMIZATION request?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes, rejected


### 6.2. Signature Binding

The request authorization signs `payloadHash` (not the raw payload) to keep signature size manageable. The contract verifies `keccak256(payload) == payloadHash` to ensure the facilitator cannot alter the payload.
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.

So payloadHash is one of the parameter of submitRequestFor?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

explained better in 6.2


### 4.1. Why EIP-3009

EIP-3009 defines `transferWithAuthorization` — a standard that allows a token holder to authorize a transfer via off-chain signature. A third party (the facilitator) can then execute the transfer on-chain without the token holder spending gas.
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.

In the ERC-3009 it is suggested to use receiveWithAuthorization instead of transferWithAuthorization for avoid front-running attack

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.

2 participants