XSC-0002: Permit Authorizer
XSC-0002 standardizes signature-based token approvals through a standalone authorizer contract. The authorizer verifies the owner's signed permit and then calls the target token's approval hook.
Canonical Function
@export
def permit(
token_contract: str,
owner: str,
spender: str,
value: Any,
deadline: str,
nonce: int,
signature: str,
):
...The authorizer stores nonces[owner] and only accepts the owner's current nonce. A successful permit increments that nonce.
Token Compatibility
Tokens that support XSC-0002 expose:
@export
def approve_from_authorizer(owner: str, spender: str, amount: float):
...That hook should restrict callers to the configured permit authorizer, write the allowance into the token's own approval state, and emit the token's normal approval event.
Message Construction
The owner signs this exact newline-separated message:
xian-permit-v2
chain_id:{chain_id}
authorizer:{authorizer_contract}
token_contract:{token_contract}
owner:{owner}
spender:{spender}
amount:{canonical_amount}
deadline:{deadline}
nonce:{nonce}canonical_amount is the decimal value after contract-side normalization with decimal(str(value)). For example, 100, 100.0, and "100.000" all sign as 100.
The authorizer hashes the complete message with hashlib.sha3_text(message) and stores permits[permit_hash] = True after a successful approval. The nonce is the primary replay guard; the stored permit hash gives indexers and auditors a stable record of the exact signed approval that was consumed.
Expected Behavior
- reject expired permits
- reject negative values
- reject non-current nonces
- verify the owner's signature over the structured message
- increment
nonces[owner]only after a successful verification - call the target token's
approve_from_authorizer(...)
deadline is checked against contract now, which means finalized block time. Permit validity depends on the timestamp of the block that includes the transaction, not on local wallet clock time or mempool arrival time.
Event Expectations
The authorizer itself does not need a separate approval event. The compatible token should emit its normal approval event when the allowance is written.