Helpful functions and macros for developing smart contracts on NEAR Protocol.

Overview

near-contract-tools

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:

  • Storage fee management
  • Ownership pattern (derive macro available)
  • Role-based access control
  • Pausable (derive macro available)
  • Derive macro for NEP-297 events

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.

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.

Example

Ownership

use near_contract_tools::{Ownable, ownership::OwnershipController};
use near_sdk::{AccountId, near_bindgen};

#[derive(Ownable)]
#[near_bindgen]
struct Contract {
    // ...
}

#[near_bindgen]
impl Contract {
    #[init]
    pub fn new(owner_id: AccountId) -> Self {
        let contract = Self {
            // ...
        };

        // Initialize the owner of the contract
        contract.init_owner(owner_id);

        contract
    }

    pub fn owner_only_method(&self) {
        self.require_owner();

        // ...
    }
}

This creates a smart contract which exposes the Ownable trait to the blockchain:

pub trait Ownable {
    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);
}

Events

use near_contract_tools::event::*;
use near_contract_tools::Event;
use serde::Serialize;

#[derive(Serialize)]
pub struct Nep171NftMintData {
    pub owner_id: String,
    pub token_ids: Vec<String>,
}

#[derive(Event, Serialize)]
#[event(standard = "nep171", version = "1.0.0")]
#[serde(untagged)]
pub enum Nep171 {
    #[event(name = "nft_mint")]
    NftMint(Vec<Nep171NftMintData>),
}

let my_event = Nep171::NftMint(vec![Nep171NftMintData {
    owner_id: "owner".to_string(),
    token_ids: vec!["token_1".to_string(), "token_2".to_string()],
}]);

my_event.emit(); // Emits event to the blockchain

Authors

Comments
  • Approval + Multisig(s)

    Approval + Multisig(s)

    This kind of implements the state-machine version of multisig, but the Approval construct is generic such that I think it could conceivably be used for any type of "multisig-like" process.

    enhancement 
    opened by encody 15
  • Multisig component

    Multisig component

    A few ways to implement multisig:

    1. Follow a preexisting pattern (e.g. copy/translate from core-contracts/multisig2).
      • Pros: Logic & structures predefined, pattern is somewhat well-known (at least, not new)
      • Cons: Code is not very well-maintained, large, complex (complexity = opportunity for error), not NEP-standardized, and such a standard would likely take a long time due to the complexity
    2. Implement our own: state machine (similar logic to core-contracts version)
      • Pros: We can clean up the logic from core-contracts a lot and simplify as necessary
      • Cons: Still relatively complex, and that comes with the same NEP approval difficulties.
    3. Implement our own: tx queue/approval. The idea is to accept an arbitrary transaction-like blob and simply sign&send when quorum is reached.
      • Pros: Simpler than state machine model, since we don't have to re-implement every possible action in our own custom data structures. Management actions (e.g. add member) could be implemented as normal #[private] functions which are called via normal, reflexive FUNCTION_CALL proposal blobs. Possibly easier to standardize as NEP since the logic is simpler.
      • Cons: Contract will have to do a little extra legwork (tx blob parsing) if it wants to implement any sort of limits on what sort of actions can be proposed, since this implementation would be written for generically signing opaque transaction blobs. I'm not aware if this pattern has been implemented before (on NEAR), so this would be new technology. Requires more testing, and I'm not even absolutely sure it's possible since I've not written a PoC.
    4. Implement our own: transaction signing protocol. Accept a transaction blob and an array of signatures (generated off-chain).
      • Pros: Probably the most straightforward implementation of multisig.
      • Cons: Suffers from the same lack of control as option 3 since it accepts an opaque blob. Requires some sort of off-chain mechanism for generating signatures.
    enhancement help wanted 
    opened by encody 15
  • basic `cargo fmt -- --check` pre-commit hook

    basic `cargo fmt -- --check` pre-commit hook

    @encody For https://near-foundation.atlassian.net/browse/ENG-149 , what do you think about this?

    Adding a server-side CI tool looked more complicated than it's worth (for our small team at this point, I think).

    opened by ryancwalsh 7
  • Add unchecked versions of functions with no side-effects or permissioning

    Add unchecked versions of functions with no side-effects or permissioning

    ~For example, ownership::Ownership::propose_owner_internal would not call require_owner or emit an OwnershipEvent::Propose event.~

    For Owner, it might make more sense to just have a non-event-emitting version of update_owner and update_proposed. For Pause, set_is_paused already doesn’t emit events or have any require! calls, so it wouldn’t require updating for this issue. I think the method names could use some work though, i.e. just by looking at the name of the method I should be able to tell whether it emits events & performs, for example, predecessor checks, and also the method that does perform those things should appear to the untrained eye as the “natural” choice. Hence, I had initially thought using names like update_owner_internal would be a good idea, but maybe update_owner_unchecked would be a better choice.

    enhancement 
    opened by encody 6
  • Specify crate in every macro

    Specify crate in every macro

    serde uses this nifty field on their macros to allow you to specify the actual crate it should be using as the "serde" crate:

    #[serde(crate = "path::to::serde")]
    

    Emulating this pattern is useful:

    • Currently there is an inconsistent use of leading colons :: in the macros
    • It's weird to try to use the near_contract_tools_macros in near_contract_tools for this reason
    • Some macros make use of other crates' types (near_sdk and serde, particularly). near_sdk reexports its own version of serde, so some users may wish to use that version (also we should discuss what the default serde crate should be @ryancwalsh @nearken).
    opened by encody 4
  • Simple multisig derive macro

    Simple multisig derive macro

    Writes a decent amount of the boilerplate per discussion with @nearken . Does not expose a public interface (difficult with generics + NEP requirement). Usage: see updated workspaces test.

    enhancement 
    opened by encody 4
  • Fuller examples

    Fuller examples

    Let's add (in a separate repo if necessary... and this one can link to it) complete examples of projects taking advantage of near-contract-tools.

    E.g. https://github.com/NEARFoundation/near-contract-tools/blob/01a64242717af71a27fa49197a96912d1c5aeedb/README.md#fungible-token isn't enough to get me started. Part (most?) of it is that I'm new to Rust, but I'm having trouble knowing where to put these lines, what Cargo.toml needs to contain, how to build the project, etc. So a full working example would be helpful.

    I looked at https://github.com/NEAR-Edu/near-certification-tools/blob/938255e1adbecbe0605c2749f9a7ebd9a9df317a/data-contract/src/contract.rs#L5 but couldn't figure it out. (Maybe certain types of macros are different from "derive" macros?

    opened by ryancwalsh 3
  • Improve events

    Improve events

    • cannot derive Display directly on Events, since Event is a trait and Display is a foreign trait
    • #[to_event] does a lot of the stuff you'd usually have to do when deriving Event
    opened by encody 1
  • Extract error strings to constants

    Extract error strings to constants

    For example, "Unauthorized" in https://github.com/NEARFoundation/near-contract-tools/blob/main/src/rbac.rs#L43 could be extracted to a constant called something like REQUIRE_ROLE_FAIL_MESSAGE or something like that.

    Alternatively, change the function signature (or add new functions) that accept a fail_message parameter to allow contract authors to customize the messages to their liking.

    enhancement 
    opened by encody 1
  • NEP-141 events are not in an array

    NEP-141 events are not in an array

    https://github.com/near/NEPs/blob/master/neps/nep-0141.md#event-interface

    Probably should just add a batch modifier to the event macro that makes it a Vec instead.

    bug 
    opened by encody 0
  • Should events use borrowed or owned values?

    Should events use borrowed or owned values?

    It's a bit inconvenient to use borrowed values everywhere, but they are technically more memory-efficient. However, since they're pretty volatile (i.e. probably never appear in smart contract storage), maybe it is better to use owned values, since they'd be easier to read and work with.

    question 
    opened by encody 0
  • WIT support

    WIT support

    We should have a discussion about supporting WebAssembly Interface Types (WIT). This would make near-contract-tools compatible with tools like the RAEN suite, which allows contracts to self-report ABI for use in tools like RAEN Admin.

    Relevant links:

    • https://github.com/bytecodealliance/wit-bindgen
    • https://github.com/bnjjj/witgen
    enhancement question 
    opened by encody 1
  • Multisig / Approval events

    Multisig / Approval events

    On proposal/request creation, approval (ensure there's something in the approval event that makes it clear when it is fully approved & can be executed), and execution.

    enhancement 
    opened by encody 0
  • Flags component

    Flags component

    Support multiple, binary state flags.

    Inspired by the functionality of the pause component in Aurora's NEAR plugins repo: https://github.com/aurora-is-near/near-plugins#pausable

    Discussion Points

    • No function decorators if the decorator would be equivalent to a simple function call (see Owner::require_owner). We're trying to stay away from Solidity-style implementations in favor of Rust.
    • Flags should be implemented as an enum, similar to how roles are for Rbac.
    • It is probably worth investigating whether bit packing (e.g. using bitflags) is as gas-efficient as checking for storage key existence. If flags are not purely binary, then this point is moot (bit packing is impossible). For example, bit packing would be impossible:
      enum MyFlags {
          PausedOne(u8),
          PausedTwo,
      }
      

    Proposed Usage

    (derives on MyFlags as of yet undetermined)

    enum MyFlags {
        PausedOne,
        PausedTwo,
    }
    
    #[derive(Flags)]
    #[flags(flags = "MyFlags", storage_key = "StorageKey::Flags")]
    struct Contract {
        // ...
    }
    
    impl Contract {
        fn one(&self) {
            Self::require_flag_unset(MyFlags::PausedOne);
            // ...
        }
    
        fn set_one(&self, on: bool) {
            if on {
                Self::set_flag(MyFlags::PausedOne);
            } else {
                Self::unset_flag(MyFlags::PausedOne);
            }
        }
    
        // similar for MyFlags::PausedTwo
    }
    
    enhancement 
    opened by encody 2
Releases(v0.6.1)
  • v0.6.1(Sep 22, 2022)

    What's Changed

    • Fix FT events & NEP-297 API improvements by @encody in https://github.com/NEARFoundation/near-contract-tools/pull/63

    Full Changelog: https://github.com/NEARFoundation/near-contract-tools/compare/v0.6.0...v0.6.1

    Source code(tar.gz)
    Source code(zip)
  • v0.6.0(Sep 20, 2022)

    What's Changed

    • basic cargo fmt -- --check pre-commit hook by @ryancwalsh in https://github.com/NEARFoundation/near-contract-tools/pull/20
    • Workspaces tests by @encody in https://github.com/NEARFoundation/near-contract-tools/pull/19
    • implemented prohibit_role by @nearken in https://github.com/NEARFoundation/near-contract-tools/pull/23
    • Improved the error message and comments in hooks/pre-commit, and the … by @ryancwalsh in https://github.com/NEARFoundation/near-contract-tools/pull/21
    • Fix formatting by @encody in https://github.com/NEARFoundation/near-contract-tools/pull/24
    • Eng 150 improve documentation for near contract tools by @ryancwalsh in https://github.com/NEARFoundation/near-contract-tools/pull/28
    • Migrate hooks by @encody in https://github.com/NEARFoundation/near-contract-tools/pull/29
    • adding unchecked function versions for owner by @nearken in https://github.com/NEARFoundation/near-contract-tools/pull/33
    • re-implementing checked functions and adding unit tests by @nearken in https://github.com/NEARFoundation/near-contract-tools/pull/34
    • Extract error strings to constants by @nearken in https://github.com/NEARFoundation/near-contract-tools/pull/37
    • standardizing naming convention between unchecked and internal functions by @nearken in https://github.com/NEARFoundation/near-contract-tools/pull/36
    • adding ext_contract to all external traits by @nearken in https://github.com/NEARFoundation/near-contract-tools/pull/38
    • Require clippy linting by @encody in https://github.com/NEARFoundation/near-contract-tools/pull/40
    • Use associated type for Rbac Role type by @encody in https://github.com/NEARFoundation/near-contract-tools/pull/43
    • Approval + Multisig(s) by @encody in https://github.com/NEARFoundation/near-contract-tools/pull/39
    • Simple multisig derive macro by @encody in https://github.com/NEARFoundation/near-contract-tools/pull/42
    • Action::execute takes mutable contract reference by @encody in https://github.com/NEARFoundation/near-contract-tools/pull/46
    • Remove unnecessary &self parameter from NEP-141 functions by @encody in https://github.com/NEARFoundation/near-contract-tools/pull/47
    • Testing README.md examples, rustdoc warnings, update dependencies by @encody in https://github.com/NEARFoundation/near-contract-tools/pull/52
    • Improve events by @encody in https://github.com/NEARFoundation/near-contract-tools/pull/55
    • Remove unsafe from Slot, nicer doc links by @encody in https://github.com/NEARFoundation/near-contract-tools/pull/58
    • Cache cargo in GH Actions & run workspaces-tests as GH Action by @encody in https://github.com/NEARFoundation/near-contract-tools/pull/60
    • Specify crate in every macro by @encody in https://github.com/NEARFoundation/near-contract-tools/pull/57

    New Contributors

    • @ryancwalsh made their first contribution in https://github.com/NEARFoundation/near-contract-tools/pull/20
    • @nearken made their first contribution in https://github.com/NEARFoundation/near-contract-tools/pull/23

    Full Changelog: https://github.com/NEARFoundation/near-contract-tools/compare/v0.5.0...v0.6.0

    Source code(tar.gz)
    Source code(zip)
  • v0.5.0(Aug 11, 2022)

    What's Changed

    • Default Struct Migration by @encody in https://github.com/NEARFoundation/near-contract-tools/pull/14
    • Token Standard: NEP-141 (Fungible Token) by @encody in https://github.com/NEARFoundation/near-contract-tools/pull/13

    Full Changelog: https://github.com/NEARFoundation/near-contract-tools/compare/v0.4.0...v0.5.0

    Source code(tar.gz)
    Source code(zip)
  • v0.4.0(Jul 11, 2022)

    What's Changed

    • Storage Slots by @encody in https://github.com/encody/near-contract-tools/pull/9
    • Public interface traits by @encody in https://github.com/encody/near-contract-tools/pull/10

    Full Changelog: https://github.com/encody/near-contract-tools/compare/v0.3.5...v0.4.0

    Source code(tar.gz)
    Source code(zip)
Minimal Substrate node configured for smart contracts via pallet-contracts.

substrate-contracts-node This repository contains Substrate's node-template configured to include Substrate's pallet-contracts ‒ a smart contract modu

Parity Technologies 59 Sep 9, 2022
Smart contracts powering Spectrum Protocol on Terra

Spectrum Core Contracts This monorepository contains the source code for the core smart contracts implementing Spectrum Protocol on the Terra blockcha

Spectrum Protocol 37 Sep 17, 2022
Rust client to Opensea's APIs and Ethereum smart contracts

opensea.rs Rust bindings & CLI to the Opensea API and Contracts CLI Usage Run cargo r -- --help to get the top level help menu: opensea-cli 0.1.0 Choo

Georgios Konstantopoulos 213 Sep 25, 2022
A framework for creating PoC's for Solana Smart Contracts in a painless and intuitive way

Solana PoC Framework DISCLAIMER: any illegal usage of this framework is heavily discouraged. Most projects on Solana offer a more than generous bug bo

Neodyme 152 Sep 26, 2022
Smart contracts for Ref Finance

Ref Finance Contracts This mono repo contains the source code for the smart contracts of Ref Finance on NEAR. Contracts Contract Reference Description

Ref Finance 87 Sep 18, 2022
Skyward Finance smart-contracts

Build and Init ./build.sh near dev-deploy res/skyward.was export CONTRACT_ID=skyward.testnet near call $CONTRACT_ID new --account_id=$CONTRACT_ID Regi

Skyward Finance 779 Sep 16, 2022
My code for the terra.academy course on CosmWasm smart contracts

CosmWasm Starter Pack This is a template to build smart contracts in Rust to run inside a Cosmos SDK module on all chains that enable it. To understan

Alex Incerti 0 Nov 7, 2021
A template to build smart contracts in Rust to run inside a Cosmos SDK module on all chains that enable it.

CosmWasm Starter Pack This is a template to build smart contracts in Rust to run inside a Cosmos SDK module on all chains that enable it. To understan

null 1 Mar 7, 2022
Create your personal token with rust smart contracts

Solana Rust Token ?? This application written Rust using Anchor ⚓

Ritesh 4 May 17, 2022
This is a node implementation of Thippy, a Substrate parachain for smart contracts

Thippy ‒- A Smart Contracts Parachain This is a node implementation of Thippy, a Substrate parachain for smart contracts. Developing Smart Contracts f

Arthur·Thomas 15 Mar 16, 2022
Rust library for build smart contracts on Internet Computer, by the Spinner.Cash team.

Spinner Rust library for building smart contracts on the Internet Computer. More specifically it is used by Spinner.Cash, a decentralized layer-2 prot

Spinner 6 May 31, 2022
Rust implementation for Thippy -- a Substrate parachain for smart contracts.

Thippy ‒- A Smart Contracts Parachain This is a node implementation of Thippy, a Substrate parachain for smart contracts. Developing Smart Contracts f

Arthur·Thomas 15 Mar 16, 2022
🖨 Template for Rust applications & smart contracts @okp4.

Rust Template Template for Rust projects @okp4. Purpose & Philosophy This repository holds the template for building Rust projects with a consistent s

OKP4 – Open Knowledge Protocol For 4 Aug 24, 2022
CLI for Stellar Smart Contracts.

stellar-contract-cli CLI for running Stellar contracts locally in a test VM. Executes WASM files built using the rs-stellar-contract-sdk. Install carg

Stellar 10 Aug 29, 2022
A gRPC-based scripting library for interacting with CosmWasm smart-contracts.

Cosmos Rust Script Smart contract scripting library to ease CosmWasm smart contract development and deployment. cosm-script is inspired by terra-rust-

null 11 Aug 25, 2022
Confidential credit scores and loan disbursal, powered by zkSNARKs and NEAR Protocol

zkLoans zkLoans brings confidential Credit Scores. It proves to a counterparty if you meet threshold requirements for a credit score without revealing

Anirudha Bose 2 Sep 13, 2022
A tutorial for an NFT Market Place Built with Near Protocol and React.js

nft-marketplace-part-1 A tutorial for an NFT Market Place built using Near Protocol and React.js. Preview To run this app locally, follow below steps:

Kohwo Orien 5 Jun 29, 2022
Reference client for NEAR Protocol

Reference implementation of NEAR Protocol About NEAR NEAR's purpose is to enable community-driven innovation to benefit people around the world. To ac

NEAR 1.8k Sep 17, 2022
A PoC backbone for NFT Marketplaces on NEAR Protocol

NFT Market Reference Implementation A PoC backbone for NFT Marketplaces on NEAR Protocol. Reference Changelog Changelog Progress: basic purchase of NF

null 9 May 26, 2022