Helpful functions and macros for developing smart contracts on NEAR Protocol.
This package is a collection of common tools and patterns in NEAR smart contract development:
Not to be confused with near-contract-standards
, which contains official implementations of standardized NEPs. This crate is intended to be a complement to near-contract-standards
.
You can think of this collection of common tools and patterns (mostly in the form of derive macros) as a sort of OpenZeppelin for NEAR.
WARNING: This is still early software, and there may be breaking changes between versions. I'll try my best to keep the docs & changelogs up-to-date. Don't hesitate to create an issue if find anything wrong.
bash
cargo add near-sdk-contract-tools
See also: the full integration tests.
```rust use nearsdk::{nearbindgen, AccountId}; use nearsdkcontract_tools::{owner::Owner, Owner};
struct Contract { // ... }
impl Contract { #[init] pub fn new(owner_id: AccountId) -> Self { let mut contract = Self { // ... };
Owner::init(&mut contract, &owner_id);
contract
}
pub fn owner_only(&self) {
Self::require_owner();
// ...
}
} ```
The Owner
derive macro exposes the following methods to the blockchain:
rust, ignore
fn own_get_owner(&self) -> Option<AccountId>;
fn own_get_proposed_owner(&self) -> Option<AccountId>;
fn own_renounce_owner(&mut self);
fn own_propose_owner(&mut self, account_id: Option<AccountId>);
fn own_accept_owner(&mut self);
The #[event]
macro can be applied to structs or enums.
```rust use nearsdkcontract_tools::{event, standard::nep297::Event};
pub struct MintEvent { pub ownerid: String, pub tokenid: String, }
let e = MintEvent { ownerid: "account".tostring(), tokenid: "token1".to_string(), };
// Emits the event to the blockchain e.emit(); ```
To create a contract that is compatible with the NEP-141 and NEP-148 standards, that emits standard-compliant (NEP-141, NEP-297) events.
```rust use nearsdkcontracttools::FungibleToken; use nearsdk::near_bindgen;
name = "My Fungible Token",
symbol = "MYFT",
decimals = 18,
no_hooks
)]
struct FungibleToken { // ... } ```
Standalone macros for each individual standard also exist.
Use the NonFungibleToken
derive macro to implement NEP-171, NEP-177, NEP-178, and NEP-181, with NEP-297 events.
```rust use nearsdk::{ borsh::{self, BorshSerialize, BorshDeserialize}, PanicOnDefault, nearbindgen, }; use nearsdkcontract_tools::nft::*;
pub struct MyNft {} ```
One may wish to combine the features of multiple macros in one contract. All of the macros are written such that they will work in a standalone manner, so this should largely work without issue. However, sometimes it may be desirable for the macros to work in combination with each other. For example, to make a fungible token pausable, use the fungible token hooks to require that a contract be unpaused before making a token transfer:
```rust use nearsdkcontracttools::{ pause::Pause, standard::nep141::{Nep141Hook, Nep141Transfer}, FungibleToken, Pause, }; use nearsdk::near_bindgen;
struct Contract {}
impl Nep141Hook for Contract { fn beforetransfer(&mut self, _transfer: &Nep141Transfer) { Contract::requireunpaused(); } } ```
Note: Hooks can be disabled using #[nep141(no_hooks)]
or #[fungible_token(no_hooks)]
.
If you are a library developer, have modified a crate that one of the near-sdk-contract-tools
macros uses (like serde
or near-sdk
), or are otherwise using a crate under a different name, you can specify crate names in macros like so:
```rust, ignore
// ...
crate = "near_sdk_contract_tools",
macros = "near_sdk_contract_tools_macros",
serde = "serde",
)] // ...
// ...
near_sdk = "near_sdk",
)] ```
Internal methods are not available to be callable via the blockchain. External ones are public and can be called by other contracts.
Proposing ownership (rather than transferring directly) is a generally good practice because it prevents you from accidentally transferring ownership to an account that nobody has access to, bricking the contract.
cargo expand
will generate one huge Rust file with all of the macros have been processed:
text
cargo install cargo-expand
cargo expand > expanded.rs
See src/slot.rs
. Slots are thin wrappers over a storage key.
assert_one_yocto()
near_sdk::assert_one_yocto()
is a function that requires a full access key (by requiring a deposit of one yoctonear, the smallest possible unit of NEAR).
If a user connects their NEAR account to a dapp, the dapp will still not be able to call functions that call assert_one_yocto()
, since function call access keys are not allowed to transfer native tokens. These function will require a signature from a full access key, usually involving a confirmation screen in the user's wallet.
Run git config core.hooksPath hooks/
to set up commit hooks.
Install cargo-make
if it is not installed already:
text
cargo install cargo-make
Run tests:
text
cargo test
cd workspaces-tests
cargo make test
This library has been audited by Kudelski Security.
(Formerly known as near-contract-tools
.)