- Category: token_interface
- Severity: Medium
- Rule name:
sep41_interface_deviation
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.
transferrecipient must beMuxedAddress,balancemust returni128). - AuthorizationMismatch — a state-mutating function authorizes the wrong parameter or none at all (
approve/transfer/burnmust authorizefrom;transfer_from/burn_frommust authorizespender).
A contract is treated as a token candidate when it has ≥2 core functions, or ≥1 core function plus ≥2 metadata functions.
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.
#![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();
// ...
}
}#![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 ...
}
}- 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.
- Implement all 10 required SEP-41 functions with the exact parameter types, order, and return types.
- Use
MuxedAddressfor thetransferrecipient. - Authorize the correct principal in each mutating function:
fromforapprove/transfer/burn,spenderfortransfer_from/burn_from. - Add integration tests against the standard via a generated
ContractClient.