Let's implement a simple fungible token contract. This contract will manage user balances and mint new tokens.
Start by introducing a service that initializes the token name during contract deployment. The service will also include a method to return the specified name.
Here's the step-by-step explanation:
State
structure stores the token name.STATE
is None
, allowing for the possibility of the storage being uninitialized.State
struct has a get
method that returns a reference to the storage.Token
struct is marked as a service with the #[service]
attribute.
init
method): Takes a String
parameter name
and initializes the static storage with this name.name
method): Returns the name stored in the static storage.Self
are treated as application constructors and are called once at the beginning of the application’s lifetime when the application is loaded onto the network.
new
method): Initializes the token with the specified name by calling Token::init
and returns an instance of MyProgram
.token
method): Returns a default instance of the Token
struct.#[route]
attribute applied to associated public functions. Message routing is about rules for dispatching an incoming request message to a specific service's method using service and method names. If the #[route("token")]
attribute was not used above the application constructor of the token service, then the service is exposed as TokenSvc
. With the #[route("token")]
macro, it is exposed as Token
.#![no_std]
use sails_rs::{prelude::*};
pub struct State {
name: String,
}
static mut STATE: Option<State> = None;
impl State {
pub fn get() -> &'static Self {
unsafe { STATE.as_ref().expect("State is not initialized") }
}
}
#[derive(Default)]
pub struct Token;
#[service]
impl Token {
pub fn init(name: String) {
unsafe {
STATE = Some(State {
name,
});
}
}
pub fn name(&self) -> &'static str {
let state = State::get();
&state.name
}
}
pub struct MyProgram;
#[program]
impl MyProgram {
pub fn new(name: String) -> Self {
Token::init(name);
Self
}
#[route("token")]
pub fn token_svc(&self) -> Token {
Token::default()
}
}
Let's implement a simple fungible token contract. This contract will manage user balances and mint new tokens.
Start by introducing a service that initializes the token name during contract deployment. The service will also include a method to return the specified name.
Here's the step-by-step explanation:
State
structure stores the token name.STATE
is None
, allowing for the possibility of the storage being uninitialized.State
struct has a get
method that returns a reference to the storage.Token
struct is marked as a service with the #[service]
attribute.
init
method): Takes a String
parameter name
and initializes the static storage with this name.name
method): Returns the name stored in the static storage.Self
are treated as application constructors and are called once at the beginning of the application’s lifetime when the application is loaded onto the network.
new
method): Initializes the token with the specified name by calling Token::init
and returns an instance of MyProgram
.token
method): Returns a default instance of the Token
struct.#[route]
attribute applied to associated public functions. Message routing is about rules for dispatching an incoming request message to a specific service's method using service and method names. If the #[route("token")]
attribute was not used above the application constructor of the token service, then the service is exposed as TokenSvc
. With the #[route("token")]
macro, it is exposed as Token
.#![no_std]
use sails_rs::{prelude::*};
pub struct State {
name: String,
}
static mut STATE: Option<State> = None;
impl State {
pub fn get() -> &'static Self {
unsafe { STATE.as_ref().expect("State is not initialized") }
}
}
#[derive(Default)]
pub struct Token;
#[service]
impl Token {
pub fn init(name: String) {
unsafe {
STATE = Some(State {
name,
});
}
}
pub fn name(&self) -> &'static str {
let state = State::get();
&state.name
}
}
pub struct MyProgram;
#[program]
impl MyProgram {
pub fn new(name: String) -> Self {
Token::init(name);
Self
}
#[route("token")]
pub fn token_svc(&self) -> Token {
Token::default()
}
}