Skip to content

Latest commit

 

History

History
93 lines (67 loc) · 3.7 KB

File metadata and controls

93 lines (67 loc) · 3.7 KB

S012 — SEP-41 Interface Deviation

  • Category: token_interface
  • Severity: Medium
  • Rule name: sep41_interface_deviation

What it detects

S012 verifies that token contracts implement the SEP-41 (Stellar Token Standard) interface correctly. For contracts identified as token candidates, it reports three deviation types:

  • MissingFunction — a required SEP-41 function (allowance, approve, balance, transfer, transfer_from, burn, burn_from, decimals, name, symbol) is absent.
  • SignatureMismatch — a function exists but its parameter types, parameter order, or return type don't match the spec (e.g. transfer recipient must be MuxedAddress, balance must return i128).
  • AuthorizationMismatch — a state-mutating function authorizes the wrong parameter or none at all (approve/transfer/burn must authorize from; transfer_from/burn_from must authorize spender).

A contract is treated as a token candidate when it has ≥2 core functions, or ≥1 core function plus ≥2 metadata functions.

Why it matters

SEP-41 is the contract that wallets, DEXes, and other protocols rely on to integrate with your token. A deviating signature or missing function means wallets reject your token or call it incorrectly; an authorization mismatch can let the wrong party move funds. Aligning exactly with the standard is what makes the token interoperable and safe to integrate.

Vulnerable example

#![no_std]
use soroban_sdk::{contract, contractimpl, Address, Env};

#[contract]
pub struct Token;

#[contractimpl]
impl Token {
    // S012 SignatureMismatch: recipient should be MuxedAddress, not Address.
    pub fn transfer(env: Env, from: Address, to: Address, amount: i128) {
        from.require_auth();
        // ...
    }

    // S012 AuthorizationMismatch: must authorize `spender`, not `from`.
    pub fn transfer_from(env: Env, spender: Address, from: Address, to: Address, amount: i128) {
        from.require_auth();
        // ...
    }
}

Safe example

#![no_std]
use soroban_sdk::{contract, contractimpl, Address, Env, MuxedAddress};

#[contract]
pub struct Token;

#[contractimpl]
impl Token {
    pub fn transfer(env: Env, from: Address, to: MuxedAddress, amount: i128) {
        from.require_auth();
        // ...
    }

    pub fn transfer_from(env: Env, spender: Address, from: Address, to: Address, amount: i128) {
        // Authorize the spender, per SEP-41.
        spender.require_auth();
        // ... verify and decrement allowance, then move the balance ...
    }
}

CVSS-style risk rating

  • Vector: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:L
  • Base score: 5.9
  • Rating: Medium

Most deviations cause integration failures; an authorization mismatch can additionally let the wrong principal move funds (high integrity impact) under specific conditions, keeping the realized risk at Medium.

How to fix

  1. Implement all 10 required SEP-41 functions with the exact parameter types, order, and return types.
  2. Use MuxedAddress for the transfer recipient.
  3. Authorize the correct principal in each mutating function: from for approve/transfer/burn, spender for transfer_from/burn_from.
  4. Add integration tests against the standard via a generated ContractClient.

Related rules

Related rules: S001, S011

References