Skip to main content

neo_devpack/
standards.rs

1// Copyright (c) 2025-2026 R3E Network
2// Licensed under the MIT License
3
4//! Reusable Neo N3 standard traits/constants for contract authors.
5
6use neo_runtime::NeoContractRuntime;
7use neo_types::{
8    NeoArray, NeoBoolean, NeoByteString, NeoContractManifest, NeoError, NeoInteger, NeoResult,
9    NeoString, NeoValue,
10};
11
12pub const NEP_11: &str = "NEP-11";
13pub const NEP_17: &str = "NEP-17";
14pub const NEP_22: &str = "NEP-22";
15pub const NEP_24: &str = "NEP-24";
16pub const NEP_26: &str = "NEP-26";
17pub const NEP_27: &str = "NEP-27";
18pub const NEP_29: &str = "NEP-29";
19pub const NEP_30: &str = "NEP-30";
20pub const NEP_31: &str = "NEP-31";
21
22// Backward-compatible aliases.
23pub const NEP11_STANDARD: &str = NEP_11;
24pub const NEP17_STANDARD: &str = NEP_17;
25pub const NEP22_STANDARD: &str = NEP_22;
26pub const NEP24_STANDARD: &str = NEP_24;
27pub const NEP26_STANDARD: &str = NEP_26;
28pub const NEP27_STANDARD: &str = NEP_27;
29pub const NEP29_STANDARD: &str = NEP_29;
30pub const NEP30_STANDARD: &str = NEP_30;
31pub const NEP31_STANDARD: &str = NEP_31;
32
33pub const LIFECYCLE_STANDARDS: &[&str] = &[NEP_22, NEP_29, NEP_30, NEP_31];
34pub const CALLBACK_STANDARDS: &[&str] = &[NEP_26, NEP_27];
35
36/// Basis-point denominator used by royalty calculations (`10000 == 100%`).
37pub const NEP_BPS_DENOMINATOR: u16 = 10_000;
38
39/// A single NEP-24 royalty payout entry.
40#[derive(Debug, Clone, PartialEq, Eq)]
41pub struct Nep24RoyaltyRecipient {
42    pub recipient: NeoByteString,
43    pub amount: NeoInteger,
44}
45
46/// Computes a royalty amount from sale price and basis points.
47pub fn compute_bps_royalty(sale_price: &NeoInteger, bps: u16) -> NeoResult<NeoInteger> {
48    if bps > NEP_BPS_DENOMINATOR {
49        return Err(NeoError::new("bps cannot exceed 10000"));
50    }
51    let numerator = sale_price.clone() * NeoInteger::from(u32::from(bps));
52    Ok(numerator / NeoInteger::from(u32::from(NEP_BPS_DENOMINATOR)))
53}
54
55/// Common standards list for token + callback + lifecycle contracts.
56pub fn common_supported_standards() -> Vec<&'static str> {
57    vec![
58        NEP17_STANDARD,
59        NEP11_STANDARD,
60        NEP24_STANDARD,
61        NEP26_STANDARD,
62        NEP27_STANDARD,
63        NEP22_STANDARD,
64        NEP29_STANDARD,
65        NEP30_STANDARD,
66        NEP31_STANDARD,
67    ]
68}
69
70/// NEP-17 fungible token standard trait.
71///
72/// Contracts implementing this trait are compliant with the NEP-17 token standard,
73/// which is the canonical fungible token interface on Neo N3.
74pub trait Nep17Token {
75    /// Returns the token symbol (e.g. "NEO", "GAS").
76    fn symbol(&self) -> NeoResult<NeoString>;
77
78    /// Returns the number of decimals the token uses.
79    fn decimals(&self) -> NeoResult<u8>;
80
81    /// Returns the total token supply.
82    fn total_supply(&self) -> NeoResult<NeoInteger>;
83
84    /// Returns the token balance of the given account.
85    fn balance_of(&self, account: &NeoByteString) -> NeoResult<NeoInteger>;
86
87    /// Transfers `amount` tokens from `from` to `to`.
88    ///
89    /// The implementation MUST:
90    /// - Verify `from` witness via `check_witness`
91    /// - Return `false` if the balance is insufficient
92    /// - Fire a `Transfer` event on success
93    /// - Call `onNEP17Payment` on `to` if it is a deployed contract
94    fn transfer(
95        &self,
96        from: &NeoByteString,
97        to: &NeoByteString,
98        amount: &NeoInteger,
99        data: &NeoValue,
100    ) -> NeoResult<bool>;
101}
102
103/// NEP-11 non-fungible token standard trait.
104///
105/// Contracts implementing this trait are compliant with the NEP-11 NFT standard on Neo N3.
106pub trait Nep11Token {
107    /// Returns the token symbol.
108    fn symbol(&self) -> NeoResult<NeoString>;
109
110    /// Returns the number of decimals (0 for indivisible NFTs).
111    fn decimals(&self) -> NeoResult<u8>;
112
113    /// Returns the total supply of issued tokens.
114    fn total_supply(&self) -> NeoResult<NeoInteger>;
115
116    /// Returns the token balance of the given account.
117    fn balance_of(&self, account: &NeoByteString) -> NeoResult<NeoInteger>;
118
119    /// Returns an iterator of token IDs owned by the account.
120    fn tokens_of(&self, account: &NeoByteString) -> NeoResult<NeoArray<NeoValue>>;
121
122    /// Transfers the NFT identified by `token_id` to `to`.
123    fn transfer(
124        &self,
125        to: &NeoByteString,
126        token_id: &NeoByteString,
127        data: &NeoValue,
128    ) -> NeoResult<bool>;
129
130    /// Returns the owner of the given token.
131    fn owner_of(&self, token_id: &NeoByteString) -> NeoResult<NeoByteString>;
132
133    /// Returns properties/metadata for the given token.
134    fn properties(&self, token_id: &NeoByteString) -> NeoResult<NeoArray<NeoValue>>;
135}
136
137/// Minimal NEP-24 royalty trait.
138pub trait Nep24Royalty {
139    fn royalty_info(
140        &self,
141        token_id: &NeoByteString,
142        royalty_token: &NeoByteString,
143        sale_price: &NeoInteger,
144    ) -> NeoResult<Vec<Nep24RoyaltyRecipient>>;
145}
146
147/// StackItem-oriented NEP-24 trait for low-level interoperability.
148pub trait Nep24RoyaltyStack {
149    fn royalty_info_stack(
150        &self,
151        token_id: NeoByteString,
152        royalty_token: NeoByteString,
153        sale_price: NeoInteger,
154    ) -> NeoResult<NeoArray<NeoValue>>;
155}
156
157/// Legacy lifecycle helper wrapping runtime update/destroy calls.
158pub trait Nep26Lifecycle {
159    fn update_contract(
160        &self,
161        script_hash: &NeoByteString,
162        nef_script: &NeoByteString,
163        manifest: &NeoContractManifest,
164    ) -> NeoResult<()> {
165        NeoContractRuntime::update(script_hash, nef_script, manifest)
166    }
167
168    fn destroy_contract(&self, script_hash: &NeoByteString) -> NeoResult<()> {
169        NeoContractRuntime::destroy(script_hash)
170    }
171}
172
173/// NEP-22 update interface.
174pub trait Nep22Update {
175    fn update(&self, nef_file: NeoByteString, manifest: NeoString, data: NeoValue)
176        -> NeoResult<()>;
177}
178
179/// NEP-26 NEP-11 payment callback.
180pub trait Nep26Receiver {
181    fn on_nep11_payment(
182        &self,
183        from: NeoByteString,
184        amount: NeoInteger,
185        token_id: NeoByteString,
186        data: NeoValue,
187    ) -> NeoResult<()>;
188}
189
190/// NEP-27 NEP-17 payment callback.
191pub trait Nep27Receiver {
192    fn on_nep17_payment(
193        &self,
194        from: NeoByteString,
195        amount: NeoInteger,
196        data: NeoValue,
197    ) -> NeoResult<()>;
198}
199
200/// NEP-29 deployment callback.
201pub trait Nep29Deploy {
202    fn deploy(&self, data: NeoValue, update: NeoBoolean) -> NeoResult<()>;
203}
204
205/// NEP-30 verification callback.
206pub trait Nep30Verify {
207    fn verify(&self) -> NeoResult<NeoBoolean>;
208}
209
210/// NEP-31 destroy interface.
211pub trait Nep31Destroy {
212    fn destroy(&self) -> NeoResult<()>;
213}