[Announcement] near-contract-tools - functions and macros for developing Rust smart contracts on NEAR
- jacobOP 5
Introducing:
near-contract-toolsHelpful functions and macros for developing smart contracts on NEAR Protocol.
The goal of
near-contract-toolsis to provide secure-by-default, drop-in components to compose smart contracts for NEAR Protocol.near-contract-toolsis a collection of common tools and patterns for NEAR smart contract development which make source code cleaner, easier to read, and more flexible.Projects using
near-contract-toolscan:- write an NEP-141 fungible token in two lines of code,
- fearlessly manage storage keys,
- create NEP-297 events with a single macro invocation,
- easily implement role-based permissioning, contract ownership, and pausability,
- add highly customizable multisig functionality,
- and more!
THIS IS STILL EARLY SOFTWARE: WE ARE LOOKING FOR PEOPLE WILLING TO TEST THIS LIBRARY IN PREPARATION FOR ITS 1.0 RELEASE.
Background
The NEAR Foundation formed the new Engineering team to provide in-house software developmentto accelerate the NEAR ecosystem. The Engineering team has been hard at work on
near-contract-toolsto support a wide-range of smart contract needs.If
near-sdkis the atoms of your smart contract,near-contract-toolsis the molecules.Design Principles
- Developer experience. This library is written by Rust developers, for Rust developers, so the patterns are implemented in the way most natural for Rust.
- “Just Works.” Sane defaults; extra options are there if you want to dive deeper.
- Modular. Although there is a
FungibleTokencomposite macro, each standard (NEP-141, NEP-148) is implemented completely independently. - Non-invasive. You can add
near-contract-toolsto your project and just use one of the components: it doesn’t require that you use, for example, theOwnercomponent in order to use theMigratecomponent. However, if you do want this functionality, it is simple to get the components to work together. - Concise. Macro usage is optional, but preferred.
Core Components
- Approval
- Multisig
- NEP Standards
- NEP-141 (Fungible Token Core)
- NEP-148 (Fungible Token Metadata)
- NEP-297 (Events)
- State migration
- Upgradability
- Ownership
- Pausability
- Role-based access control
- Storage slots calculated at compile time
- (miscellaneous other utilities)
Installation
Add
near-contract-toolsto your Rust smart contract usingcargo:$ cargo add near-contract-toolsExamples
Fungible Token 2-liner
// add these lines: #[derive(near_contract_tools::FungibleToken)] #[fungible_token(name = "My Fungible Token", symbol = "MYFT", decimals = 24, no_hooks)] // that's it! #[near_sdk::near_bindgen] struct MyFungibleTokenContract { } // no need to put anything in the default structUse it:
#[near_sdk::near_bindgen] impl MyFungibleTokenContract { pub fn send_half_my_balance_to(&mut self, account_id: near_sdk::AccountId) { // Nep141 functions are available to the public blockchain use near_contract_tools::standard::nep141::Nep141; // ft_* functions are defined! let balance: u128 = self.ft_balance_of(account_id.clone()).into(); let send = balance / 2; near_sdk::require!(send > 0, "You don't have enough money!"); self.ft_transfer( account_id, send.into(), Some("Half my balance!".to_string()), ); } pub fn double_my_balance(&mut self) { // Nep141Controller functions are not available to the public blockchain use near_contract_tools::standard::nep141::{Nep141, Nep141Controller}; let predecessor = near_sdk::env::predecessor_account_id(); let balance = self.ft_balance_of(predecessor.clone()); // Here's one of those non-public functions self.mint(&predecessor, balance.into(), Some("Doubling my balance!")); } }NEP-297 Events
use near_contract_tools::{event, standard::nep297::Event}; use near_sdk::{AccountId, json_types::U128}; // Definition #[event(standard = "ft_event", version = "1.0.0")] pub struct FtMint { pub owner_id: AccountId, pub amount: U128, } #[event(standard = "ft_event", version = "1.0.0")] pub struct FtTransfer { pub old_owner_id: AccountId, pub new_owner_id: AccountId, pub amount: U128, } // ...Use it:
FtMint { owner_id: "owner".parse().unwrap(), amount: 100.into(), } .emit();
Build contracts fast with
near-contract-tools!near-contract-toolsimproves the smart contract development experience on NEAR Protocol. It comes with macros that work out-of-the-box, providing developers with patterns that are often copy-pasted across projects.near-contract-toolsis highly modular, and each component is opt-in. Developers can extend the components with custom functionality and use them alongside the rest of the library.This is one more tool to help you build without limits!
- kenjon 1
Hey @encody great work on this project!
Can you talk about the differences between the multisig used in near-contract-tools as opposed to: core-contracts/multisig2 at master · near/core-contracts · GitHub.
Also could you explain storage slots being calculated at compile time. What are the major benefits and are there any security risks that developers should be aware of when using this storage slot pattern?
- sandoche 2
The OpenZeppelin for the NEAR Dapps! Congrats @jacob !
- Ryan.Walsh 1
@jacob This looks great! I think you could copy most or all of this post and put it in the Readme, too.
- jacob 1
The multisig implementation in
near-contract-toolsis split into a few parts. First, there’s theApprovalcomponent, which manages the approval process for and execution of actions. This makes it easy to write different approval schemes (e.g. n of m (provided), governance token holding, etc.) and different action types, which can then be mixed-and-matched. For the typical multisig wallet, an action would simply be any arbitrary transaction, and since this is a common use-case,near-contract-toolsprovidesNativeTransactionAction, which is a thin wrapper around the native transaction action kinds.Storage slots are a way to increase storage efficiency by calculating storage keys instead of storing them. You can explore the differences between these two contracts:
-
Fungible Token with
near-contract-standards(note that this also implements the storage management standard, so it is not exactly a apples-to-apples comparison) -
Fungible Token with
near-contract-tools
The benefits of using storage slots:
- Reduces storage I/O cycles, since
STATEdeserialization is not necessary - Reduces the amount of data put in storage
- It is easier to find potential key collisions since all of the information needed to calculate a key is in the contract code and not split across the code and the storage
-
Fungible Token with