MPP.Methods.Tempo (mpp v0.6.1)

Copy Markdown View Source

Tempo payment method — verifies payment via on-chain TIP-20 token transfer.

Tempo supports two credential types:

  • type="hash" — Client already broadcast the transaction; server verifies the receipt via RPC (eth_getTransactionReceipt).
  • type="transaction" — Client sends a signed Tempo Transaction (0x76); server decodes, optionally adds fee payer signature, broadcasts, and verifies.

Configuration

Pass Tempo-specific config via :method_config in MPP.Plug opts:

plug MPP.Plug,
  secret_key: "hmac-secret",
  realm: "api.example.com",
  method: MPP.Methods.Tempo,
  amount: "1000000",
  currency: "0x20c0000000000000000000000000000000000000",
  method_config: %{
    "rpc_url" => "https://rpc.moderato.tempo.xyz",
    "chain_id" => 42431,
    "fee_payer" => false
  }

Config Keys

  • "rpc_url" — (required) Tempo RPC endpoint URL
  • "chain_id" — (optional) network chain ID, defaults to 42431 (Moderato testnet)
  • "fee_payer" — (optional) enable server-side fee sponsorship, defaults to false. When true, the server co-signs client transactions with domain 0x78 to pay transaction fees. Requires "fee_payer_private_key" and "fee_token".
  • "fee_payer_private_key" — (required when fee_payer: true) hex-encoded 32-byte secp256k1 private key for the fee payer account
  • "fee_token" — (required when fee_payer: true) hex address of a USD-denominated TIP-20 token to use for fee payment (e.g., pathUSD)
  • "fee_payer_policy" — (optional, fee_payer: true only) map of sponsor ceilings overriding the per-chain defaults: "max_gas", "max_fee_per_gas", "max_priority_fee_per_gas", "max_total_fee" (wei), and "max_validity_window_seconds" (seconds). Bounds the client-supplied gas fields and validity window before the server co-signs so a malicious client cannot drain the fee-payer wallet via inflated gas price, total fee budget, or a padded access list, nor hold a co-signed sponsorship broadcastable far into the future. See MPP.Methods.Tempo.FeePayerPolicy.
  • "memo" — (optional) bytes32 hex memo for transferWithMemo
  • "wait_for_confirmation" — (optional) when false, broadcasts without waiting for on-chain confirmation. Pre-simulates the full co-signed transaction via eth_simulateV1 first (same guard as the default path) to reject a tx that would revert before broadcast, then broadcasts async and returns an optimistic receipt. Default true.
  • "store" — (optional) module implementing MPP.Tempo.Store behaviour for transaction dedup, or {MPP.Tempo.ConCacheStore, opts} to configure the built-in ConCache store (for example a custom cache :name). Prevents replay by tracking used tx hashes. When nil (default), no dedup is performed — library stays stateless.

Credential Payload

The credential payload map must contain one of:

  • "type" => "hash", "hash" => "0x..." — transaction hash for receipt verification
  • "type" => "transaction", "signature" => "..." — RLP-serialized signed Tempo Transaction

Dependencies

Requires the onchain and onchain_tempo packages (optional dependencies) for RPC calls, transfer log parsing, and 0x76 Tempo transaction handling. The method checks availability at init time via validate_config!/1.

API Functions

FunctionArityDescriptionParam Kinds
challenge_method_details1Return Tempo-specific fields (chainId, feePayer, memo) for the 402 challenge.charge: value
verify2Verify a Tempo credential by checking on-chain settlement.payload: value, charge: value
validate_config!1Validate Tempo method_config at init time. Raises on missing rpc_url or unavailable onchain / onchain_tempo dependencies.config: value
method_name0Return the payment method identifier for Tempo.-

Summary

Functions

Return Tempo-specific fields (chainId, feePayer, memo) for the 402 challenge.

Return the payment method identifier for Tempo.

Validate Tempo method_config at init time. Raises on missing rpc_url or unavailable onchain / onchain_tempo dependencies.

Verify a Tempo credential by checking on-chain settlement.

Functions

challenge_method_details(charge)

@spec challenge_method_details(MPP.Intents.Charge.t()) :: map() | nil
@spec challenge_method_details(MPP.Intents.Charge.t()) :: map()

Return Tempo-specific fields (chainId, feePayer, memo) for the 402 challenge.

Parameters

  • charge - Charge struct with method_details containing chain_id, fee_payer, and optionally memo (value)

Returns

Map with chainId (default 42431), feePayer (default false), and optional memo (map)

# descripex:contract
%{
  params: %{
    charge: %{
      description: "Charge struct with method_details containing `chain_id`, `fee_payer`, and optionally `memo`",
      kind: :value
    }
  },
  returns: %{
    type: :map,
    description: "Map with `chainId` (default 42431), `feePayer` (default false), and optional `memo`"
  }
}

method_name()

@spec method_name() :: String.t()

Return the payment method identifier for Tempo.

# descripex:contract
%{}

validate_config!(config)

@spec validate_config!(map()) :: :ok
@spec validate_config!(map()) :: :ok

Validate Tempo method_config at init time. Raises on missing rpc_url or unavailable onchain / onchain_tempo dependencies.

Parameters

  • config - method_config map to validate (value)

Returns

:ok on success, raises ArgumentError on missing keys (atom)

# descripex:contract
%{
  params: %{
    config: %{description: "method_config map to validate", kind: :value}
  },
  returns: %{
    type: :atom,
    description: "`:ok` on success, raises `ArgumentError` on missing keys"
  }
}

verify(payload, charge)

@spec verify(map(), MPP.Intents.Charge.t()) ::
  {:ok, MPP.Receipt.t()} | {:error, MPP.Errors.t()}
@spec verify(map(), MPP.Intents.Charge.t()) ::
  {:ok, MPP.Receipt.t()} | {:error, MPP.Errors.t()}
@spec verify(map(), MPP.Intents.Charge.t()) :: {:error, MPP.Errors.t()}

Verify a Tempo credential by checking on-chain settlement.

Parameters

  • payload - Credential payload map with "type" ("hash" or "transaction") and corresponding proof field (value)
  • charge - Charge intent struct with amount, currency, and method_details (including rpc_url) (value)

Returns

{:ok, receipt} on success, {:error, error} on failure (tagged_tuple)

Errors

  • :invalid_payload
  • :verification_failed
# descripex:contract
%{
  params: %{
    payload: %{
      description: "Credential payload map with `\"type\"` (`\"hash\"` or `\"transaction\"`) and corresponding proof field",
      kind: :value
    },
    charge: %{
      description: "Charge intent struct with amount, currency, and method_details (including `rpc_url`)",
      kind: :value
    }
  },
  errors: [:invalid_payload, :verification_failed],
  returns: %{
    type: :tagged_tuple,
    description: "`{:ok, receipt}` on success, `{:error, error}` on failure"
  }
}