Skip to content

core-sdk: support fallback / empty entries in token-transfer-authorization queues (BPIP-12) #1032

Description

@levalleux-ludo

Summary

@bosonprotocol/core-sdk's erc20.handler.encodeTransferAuthorizationEntry and
metaTx.handler.executeMetaTransactionWithTokenTransferAuthorization cannot
express empty / fallback entries (0x) inside a token-transfer-authorization
queue. The on-chain
MetaTransactionsHandlerFacet.executeMetaTransactionWithTokenTransferAuthorization

  • TokenTransferAuthorizationLib.loadQueue accept 0x as a shortcut for "no
    auth — fall back to ERC-20 allowance", and several commit-time flows
    require at least one empty leading slot. The SDK gap forces downstream
    consumers to bypass the handler and hand-roll the queue + outer calldata.

Where the gap is

In packages/contracts-sdk/src/erc20/handler.ts (and the corresponding
meta-tx/handler.ts), the public type is:

export type UnsignedTransferAuthorization =
  | { strategy: "ERC3009"; data: { ... } }
  | { strategy: "EIP2612"; data: { ... } }
  | { strategy: "Permit2";  data: { ... } }
  | { strategy: "DAIPermit"; data: { ... } };

encodeTransferAuthorizationEntry is an exhaustive switch over these four
strategies — every element of transferAuthorizations: TransferAuthorization[]
must carry a strategy id + signature. There is no representation for
bytes("") (the empty entry the on-chain queue accepts as a placeholder).

metaTx.handler.executeMetaTransactionWithTokenTransferAuthorization then
maps the input array via .map(encodeTransferAuthorizationEntry) and passes
the result to the meta-tx handler's executeMetaTransactionWithTokenTransferAuthorization(..., bytes[]) ABI member — so the same restriction applies end-to-end.

Why it matters (BPIP-12 / commit-time flows)

The protocol's commit-time meta-transactions
(createOfferAndCommit, createOfferCommitAndRedeem) emit multiple
transferFundsIn calls in sequence — one for the zero-amount seller
deposit, one for the buyer's price. TokenTransferAuthorizationLib.loadQueue
consumes one queue entry per transferFundsIn site via discardNext(). For
these flows the queue must have a leading empty entry so the zero-amount
seller-deposit transferFundsIn advances past 0x (no auth needed for a
zero-value pull) and the buyer's strategy-typed auth lands on the next slot.

Today, downstream consumers that want to drive BPIP-12 meta-txes have to:

  • Hand-roll the outer envelope ABI (or import it from @bosonprotocol/common's
    IBosonMetaTransactionsHandlerABI),
  • Hand-roll the per-entry abi.encode(uint8 strategy, bytes data) layout,
  • Hand-pin the on-chain TokenTransferAuthorizationStrategy enum values
    (ERC3009=1, EIP2612=2, Permit2=3, DAIPermit=4),
  • And manage the leading-empty-slot insertion themselves.

That's exactly what the SDK is supposed to encapsulate. The current shape
forces a separate code path for every consumer that needs the empty-slot
queue.

Proposed change

Add an explicit fallback variant, called "None".

export type UnsignedTransferAuthorization =
  | { strategy: "None" }
  | { strategy: "ERC3009"; data: { ... } }
  | { strategy: "EIP2612"; data: { ... } }
  | { strategy: "Permit2";  data: { ... } }
  | { strategy: "DAIPermit"; data: { ... } };

encodeTransferAuthorizationEntry returns "0x" for the "None" case.
No signature fields required. Cleanly typed; callers can build queues
declaratively.

metaTx.handler.executeMetaTransactionWithTokenTransferAuthorization
should accept the same shape transparently.

Reference

  • On-chain semantics: boson-protocol-contracts
    TokenTransferAuthorizationLib.loadQueue / discardNext / consumeForTransfer.
  • On-chain enum: BosonTypes.TokenTransferAuthorizationStrategy (None=0,
    ERC3009=1, EIP2612=2, Permit2=3, DAIPermit=4).
  • Downstream motivation: the @bosonprotocol/x402-facilitator package in
    bosonprotocol/x402B currently
    ships typescript/packages/facilitator/src/internal/build-bpip12-calldata.ts
    as a local workaround. Closing this issue would let us delete that helper
    and route the BPIP-12 commit path through
    metaTx.handler.executeMetaTransactionWithTokenTransferAuthorization({ returnTxInfo: true }).

Acceptance

  • UnsignedTransferAuthorization (or the queue array shape) can express an
    empty / fallback entry without consumers reaching into ABI primitives.
  • A test that round-trips a queue like
    [fallback, erc3009Auth] through
    executeMetaTransactionWithTokenTransferAuthorization and asserts the
    encoded bytes[] matches the protocol's expectation ([ "0x", <strategy-typed entry> ]).

Metadata

Metadata

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions