A contract to lock fungible tokens with a given vesting schedule including cliffs.

Overview

Fungible Token Lockup contract

Features

  • A reusable lockup contract for a select fungible token.
  • Lockup schedule can be set as a list of checkpoints with time and balance.
  • Supports multiple lockups per account ID.
  • Ability to create a lockup that can be terminated
    • A single lockup can be only terminated by a specific account ID.
    • Supports custom vesting schedule that should be ahead of the lockup schedule
    • The vesting schedule can be hidden behind a hash, so it only needs to be revealed in case of termnation.
  • Automatic rollbacks if a FT transfer fails.
  • Claiming all account's lockups in a single transaction.
  • Ability to add new lockups.
  • Whitelist for the accounts that can create new lockups.
Comments
  • Terminating vesting & consequent unlocking

    Terminating vesting & consequent unlocking

    Let's say I have vesting schedule for 1 year and then 3 year following linear unlocking. But I terminate vesting in the middle.

    I use this test code
    #[test]
    fn test_123_team_terminate() {
        let e = Env::init(None);
        let users = Users::init(&e);
        let amount = d(60000, TOKEN_DECIMALS);
        e.set_time_sec(GENESIS_TIMESTAMP_SEC);
        let lockups = e.get_account_lockups(&users.alice);
        assert!(lockups.is_empty());
        
        let vesting_schedule = Schedule(vec![
            Checkpoint {
                timestamp: GENESIS_TIMESTAMP_SEC,
                balance: 0,
            },
            Checkpoint {
                timestamp: GENESIS_TIMESTAMP_SEC + ONE_YEAR_SEC,
                balance: amount,
            },
        ]);
    
        let lockup = Lockup {
            account_id: users.alice.valid_account_id(),
            schedule: Schedule(vec![
                Checkpoint {
                    timestamp: GENESIS_TIMESTAMP_SEC + ONE_YEAR_SEC,
                    balance: 0,
                },
                Checkpoint {
                    timestamp: GENESIS_TIMESTAMP_SEC + 4 * ONE_YEAR_SEC,
                    balance: amount,
                },
            ]),
            claimed_balance: 0,
            termination_config: Some(TerminationConfig {
                terminator_id: users.eve.valid_account_id(),
                vesting_schedule: Some(HashOrSchedule::Schedule(vesting_schedule)),
            }),
        };
        
        let balance: WrappedBalance = e.add_lockup(&e.owner, amount, &lockup).unwrap_json();
        assert_eq!(balance.0, amount);
    
        let lockups = e.get_account_lockups(&users.alice);
        assert_eq!(lockups.len(), 1);
        assert_eq!(lockups[0].1.total_balance, amount);
        assert_eq!(lockups[0].1.claimed_balance, 0);
        assert_eq!(lockups[0].1.unclaimed_balance, 0);
        println!("πŸ•° TGE -> {} ", lockups[0].1.unclaimed_balance / 1e18 as u128);
    
        e.set_time_sec(GENESIS_TIMESTAMP_SEC + ONE_MONTH_SEC);
        let lockups = e.get_account_lockups(&users.alice);
        assert_eq!(lockups.len(), 1);
        assert_eq!(lockups[0].1.total_balance, amount);
        assert_eq!(lockups[0].1.claimed_balance, 0);
        assert_eq!(lockups[0].1.unclaimed_balance, 0);
        println!("πŸ•° 1 month latter -> {} ", lockups[0].1.unclaimed_balance / 1e18 as u128);
    
        e.set_time_sec(GENESIS_TIMESTAMP_SEC + ONE_YEAR_SEC / 2);
        let lockups = e.get_account_lockups(&users.alice);
        let lockup_index = lockups[0].0;
        assert_eq!(lockups.len(), 1);
        assert_eq!(lockups[0].1.total_balance, amount);
        assert_eq!(lockups[0].1.claimed_balance, 0);
        assert_eq!(lockups[0].1.unclaimed_balance, 0);
        println!("πŸ•° half year latter -> {} ", lockups[0].1.unclaimed_balance / 1e18 as u128);
    
        // TERMINATE employee half-year after vesting had started
        ft_storage_deposit(&users.eve, TOKEN_ID, &users.eve.account_id);
        let res: WrappedBalance = e.terminate(&users.eve, lockup_index).unwrap_json();
        println!("❀️‍πŸ”₯ terminator gets {} ", res.0 / 1e18 as u128);
        assert_eq!(res.0, amount / 2);
        let terminator_balance = e.ft_balance_of(&users.eve);
        println!("❀️‍πŸ”₯ terminator gets {} ", terminator_balance / 1e18 as u128);
        assert_eq!(terminator_balance, amount / 2);
    
        let lockups = e.get_account_lockups(&users.alice);
        assert_eq!(lockups.len(), 1);
        assert_eq!(lockups[0].1.total_balance, amount / 2);
        assert_eq!(lockups[0].1.claimed_balance, 0);
        assert_eq!(lockups[0].1.unclaimed_balance, 0);
        println!("πŸ•° available after termination (1/2y) -> {} ", lockups[0].1.total_balance / 1e18 as u128);
        println!("πŸ•° available after termination (1/2y) -> {} ", lockups[0].1.unclaimed_balance / 1e18 as u128);
    
        e.set_time_sec(GENESIS_TIMESTAMP_SEC + ONE_YEAR_SEC + 1);
        let lockups = e.get_account_lockups(&users.alice);
        println!("πŸ•° 1 year + 1s latter -> {} ", lockups[0].1.total_balance / 1e18 as u128);
        println!("πŸ•° 1 year + 1s year latter -> {} ", lockups[0].1.claimed_balance / 1e18 as u128);
        println!("πŸ•° 1 year + 1s year latter -> {} ", lockups[0].1.unclaimed_balance / 1e18 as u128);
    
        e.set_time_sec(GENESIS_TIMESTAMP_SEC + 5 * ONE_YEAR_SEC / 2);
        let lockups = e.get_account_lockups(&users.alice);
        println!("πŸ•° 2.5 year latter -> {} ", lockups[0].1.total_balance / 1e18 as u128);
        println!("πŸ•° 2.5 year latter -> {} ", lockups[0].1.claimed_balance / 1e18 as u128);
        println!("πŸ•° 2.5 year latter -> {} ", lockups[0].1.unclaimed_balance / 1e18 as u128);
    
        e.set_time_sec(GENESIS_TIMESTAMP_SEC + 4 * ONE_YEAR_SEC );
        let lockups = e.get_account_lockups(&users.alice);
        println!("πŸ•° 4 year latter -> {} ", lockups[0].1.total_balance / 1e18 as u128);
        println!("πŸ•° 4 year latter -> {} ", lockups[0].1.claimed_balance / 1e18 as u128);
        println!("πŸ•° 4 year latter -> {} ", lockups[0].1.unclaimed_balance / 1e18 as u128);
    }
    

    After termination, half tokens goes to terminator, half already vested and thats OK. However why after termination unlocking works like it would work with full amount? I expected 2.5 years latter I can claim only half of the vested tokens, - 15k, and only at 4 years latter - all of them which is 30k. Is it possible to setup this way? (like it's % rather than absolute numbers?)

     TGE -> 0 
    πŸ•° 1 month latter -> 0 
    πŸ•° half year latter -> 0 
    ❀️‍πŸ”₯ terminator gets 30000 
    ❀️‍πŸ”₯ terminator gets 30000 
    πŸ•° available after termination (1/2y) -> 30000 
    πŸ•° available after termination (1/2y) -> 0 
    
    πŸ•° 2.5 year latter -> 30000 
    πŸ•° 2.5 year latter -> 0 
    πŸ•° 2.5 year latter -> 30000 /// ❗️HERE IT SHOULD BE 15000 ❓
    
    πŸ•° 4 year latter -> 30000 
    πŸ•° 4 year latter -> 0 
    πŸ•° 4 year latter -> 30000 
    
    
    opened by intmainreturn00 5
  • Add draft groups

    Add draft groups

    Implement draft groups new_draft_group get_draft_groups_paged new_draft get_draft get_drafts add new message type for ft_token_receiver add convert_draft method add new_drafts (batch method) add convert_drafts (batch method)

    opened by alexaunter 4
  • Custom termination date

    Custom termination date

    Added ability to terminate contract not "as of now" but in any specific moment in the future. Motivation: for legal implications, we need to be precise when terminating lockups.

    If the termination timestamp is in the future, the schedule will be truncated in that moment in the future If the termination timestamp is in the past - current timestamp will be used for schedule truncation

    opened by alexaunter 3
  • Consider adding support to delete lockup contract account

    Consider adding support to delete lockup contract account

    This might be useful when the account was created by mistake or it has already served its purpose.

    We discussed adding a new function which will add FULL ACCESS key and mark the contract immutable, but there is a risk that malicious actor will deploy an intermediate contract, alter the state (delete the immutability marker), and deploy lockup contract back again now having FULL control over the account.

    Probably it is not worth the trouble, but I still wanted to discuss it anyway.

    cc @evgenykuzyakov @alexaunter

    opened by frol 2
  • Fix static view method calls

    Fix static view method calls

    Seems like near sdk doesn't generate the correct code for static view methods, See error in https://github.com/galactic3/ft-lockup-contract/commit/bb607fd93d9d3a5d96482f4ca395827b1d4961d8

    Solution: add &self as first argument.

    I found some examples of methods not using contract but still having it in signature in https://github.com/near/near-sdk-rs/blame/master/examples/cross-contract-high-level/src/lib.rs

    opened by alexaunter 2
  • Allow deleting draft groups

    Allow deleting draft groups

    Sometimes people will make errors while creating draft groups. It's impossible to modify the drafts themselves, so the only way to fix the error is to create another draft group. This might cause significant storage overhead. To overcome this issue new methods are created, allowing to mark draft group as discarded and then delete drafts from it.

    opened by alexaunter 1
  • feat: add option to try converting drafts when funding group

    feat: add option to try converting drafts when funding group

    Usability improvement. After the draft group has been funded, spend the remaining gas trying to convert drafts.

    If the convert succeeds, user can skip one step in the lockup creation flow. If the convert fails - transaction still succeeds, but user lost some amount of NEAR on gas.

    Discussed previously with @frol

    opened by alexaunter 0
  • Preserve schedule on terminate before cliff

    Preserve schedule on terminate before cliff

    Currently when terminating lockup with zero vested balance, the schedule is replaced with lockup with two checkpoints:

    [
      { timestamp: 0, balance: "0" },
      { timestamp: 1, amount: "0" },
    ]
    

    This is a bit surprising change to the schedule. It was discussed with @frolvlad that it's better to keep the starting timestamp, and add finish timestamp as the moment of termination. It will make the result less surprising and eliminate necessity of handling such lockups with a custom logic on frontend.

    Another case - terminating lockup when the payer doesn't have storage_deposit, and thus the ft transfer fails. Same as before, it's better to create lockup unlocked now for transparency.

    opened by alexaunter 0
  • Add draft operator role

    Add draft operator role

    Purpose: more flexible user permissions separation.

    The original problem we wanted to solve was to give less privileged users ability to manage draft groups, while being unable to create and terminate lockups, fund draft groups.

    The solution is to have two roles in the contract, operator(called deposit previously) and draft_operator

    Highlights:

    1. introduction of draft_operator role. The role can perform all actions on drafts that require authorization: create_draft_group, create_draft, discard_draft_group
    2. current deposit role is an admin role, as before, it can perform deposit operations add_lockup, fund_draft_group, as well as all actions draft_operator can do, plus user permissions management.
    3. any user with deposit role can trigger terminate on the contract, while user with only draft_operator role cannot.
    4. add_to_deposit_whitelist, remove_from_deposit_whitelist method now accepts multiple account_ids,

    Proposal: since deposit role is more of an admin role, it might be better to rename it accordingly, for example to operator role.

    opened by alexaunter 0
  • fix: disallow creating lockups and drafts with zero balance

    fix: disallow creating lockups and drafts with zero balance

    Minor fix. When lockup was created directly via ft-transfer-call it was impossible to create a lockup with zero amount due to validations in This was not checked when implementing draft groups. As the payment is done later, and now it's possible to create a lockup with zero balance this way. Zero amount lockups are impossible to claim and delete, and this problem was addressed in #3, #4.

    This MR closes possibility to create such lockups through a draft group.

    opened by alexaunter 0
  • Tests fails at Linux πŸ™

    Tests fails at Linux πŸ™

    When I run tests from 404bc2c06f144a5dda729e34dd1c66903fbdbd24 at ubuntu it stuck forever and does not work:

    owl@linux-box:~/ft-lockup-contract$ cargo test
       Compiling librocksdb-sys v6.17.3
        Building [=======================> ] 420/430: librocksdb-sys(build) 
    
    

    I have rust, make, clang installed(maybe we could specify what's needed to run tests somehow?). Build works fine:

    owl@linux-box:~/ft-lockup-contract$ ./build.sh 
    ~/ft-lockup-contract ~/ft-lockup-contract
        Finished release [optimized] target(s) in 0.08s
    ~/ft-lockup-contract
    
    opened by intmainreturn00 0
  • How can I see vesting working?

    How can I see vesting working?

    Let's say I have vesting schedule for 1 year and then 3 year following linear unlocking.

    I use this test code
    #[test]
    fn test_vesting_and_unlock() {
        let e = Env::init(None);
        let users = Users::init(&e);
        let amount = d(60000, TOKEN_DECIMALS);
        e.set_time_sec(GENESIS_TIMESTAMP_SEC);
        let lockups = e.get_account_lockups(&users.alice);
        assert!(lockups.is_empty());
        
        let vesting_schedule = Schedule(vec![
            Checkpoint {
                timestamp: GENESIS_TIMESTAMP_SEC,
                balance: 0,
            },
            Checkpoint {
                timestamp: GENESIS_TIMESTAMP_SEC + ONE_YEAR_SEC,
                balance: amount,
            },
        ]);
    
        let lockup = Lockup {
            account_id: users.alice.valid_account_id(),
            schedule: Schedule(vec![
                Checkpoint {
                    timestamp: GENESIS_TIMESTAMP_SEC + ONE_YEAR_SEC,
                    balance: 0,
                },
                Checkpoint {
                    timestamp: GENESIS_TIMESTAMP_SEC + 4 * ONE_YEAR_SEC,
                    balance: amount,
                },
            ]),
            claimed_balance: 0,
            termination_config: Some(TerminationConfig {
                terminator_id: users.eve.valid_account_id(),
                vesting_schedule: Some(HashOrSchedule::Schedule(vesting_schedule)),
            }),
        };
        
        let balance: WrappedBalance = e.add_lockup(&e.owner, amount, &lockup).unwrap_json();
        assert_eq!(balance.0, amount);
    
        let lockups = e.get_account_lockups(&users.alice);
        assert_eq!(lockups.len(), 1);
        assert_eq!(lockups[0].1.total_balance, amount);
        assert_eq!(lockups[0].1.claimed_balance, 0);
        assert_eq!(lockups[0].1.unclaimed_balance, 0);
        println!("πŸ•° TGE total -> {} ", lockups[0].1.total_balance / 1e18 as u128);
        println!("πŸ•° TGE unclaimed -> {} ", lockups[0].1.unclaimed_balance / 1e18 as u128);
    
        e.set_time_sec(GENESIS_TIMESTAMP_SEC + ONE_MONTH_SEC);
        let lockups = e.get_account_lockups(&users.alice);
        assert_eq!(lockups.len(), 1);
        assert_eq!(lockups[0].1.total_balance, amount);
        assert_eq!(lockups[0].1.claimed_balance, 0);
        assert_eq!(lockups[0].1.unclaimed_balance, 0);
        println!("πŸ•° 1 month latter total -> {} ", lockups[0].1.total_balance / 1e18 as u128);
        println!("πŸ•° 1 month latter unclaimed -> {} ", lockups[0].1.unclaimed_balance / 1e18 as u128);
    
        e.set_time_sec(GENESIS_TIMESTAMP_SEC + 2 * ONE_MONTH_SEC);
        let lockups = e.get_account_lockups(&users.alice);
        assert_eq!(lockups.len(), 1);
        assert_eq!(lockups[0].1.total_balance, amount);
        assert_eq!(lockups[0].1.claimed_balance, 0);
        assert_eq!(lockups[0].1.unclaimed_balance, 0);
        println!("πŸ•° 2 month latter total -> {} ", lockups[0].1.total_balance / 1e18 as u128);
        println!("πŸ•° 2 month latter unclaimed -> {} ", lockups[0].1.unclaimed_balance / 1e18 as u128);
    
        e.set_time_sec(GENESIS_TIMESTAMP_SEC + 12 * ONE_MONTH_SEC);
        let lockups = e.get_account_lockups(&users.alice);
        assert_eq!(lockups.len(), 1);
        assert_eq!(lockups[0].1.total_balance, amount);
        assert_eq!(lockups[0].1.claimed_balance, 0);
        assert_eq!(lockups[0].1.unclaimed_balance, 0);
        println!("πŸ•° 12 month latter total -> {} ", lockups[0].1.total_balance / 1e18 as u128);
        println!("πŸ•° 12 month latter unclaimed -> {} ", lockups[0].1.unclaimed_balance / 1e18 as u128);
        
        e.set_time_sec(GENESIS_TIMESTAMP_SEC + 13 * ONE_MONTH_SEC);
        let lockups = e.get_account_lockups(&users.alice);
        println!("πŸ•° 13 month latter total -> {} ", lockups[0].1.total_balance / 1e18 as u128);
        println!("πŸ•° 13 month latter unclaimed -> {} ", lockups[0].1.unclaimed_balance / 1e18 as u128);
    
        e.set_time_sec(GENESIS_TIMESTAMP_SEC + 2 * ONE_YEAR_SEC);
        let lockups = e.get_account_lockups(&users.alice);
        assert_eq!(lockups.len(), 1);
        assert_eq!(lockups[0].1.total_balance, amount);
        assert_eq!(lockups[0].1.claimed_balance, 0);
        assert_eq!(lockups[0].1.unclaimed_balance, 1 * amount / 3);
        println!("πŸ•° 2 year latter total -> {} ", lockups[0].1.total_balance / 1e18 as u128);
        println!("πŸ•° 2 year latter unclaimed -> {} ", lockups[0].1.unclaimed_balance / 1e18 as u128);
    
        e.set_time_sec(GENESIS_TIMESTAMP_SEC + 4 * ONE_YEAR_SEC);
        let lockups = e.get_account_lockups(&users.alice);
        assert_eq!(lockups.len(), 1);
        assert_eq!(lockups[0].1.total_balance, amount);
        assert_eq!(lockups[0].1.claimed_balance, 0);
        assert_eq!(lockups[0].1.unclaimed_balance, amount);
        println!("πŸ•° 4 year latter total -> {} ", lockups[0].1.total_balance / 1e18 as u128);
        println!("πŸ•° 4 year latter unclaimed -> {} ", lockups[0].1.unclaimed_balance / 1e18 as u128);
    }
    

    I can see the progress of unlocking by checking unclaimed_balance

    πŸ•° A total -> 60000 
    πŸ•° A unclaimed -> 0 
    
    πŸ•° 1 month latter total -> 60000 
    πŸ•° 1 month latter unclaimed -> 0 
    
    πŸ•° 2 month latter total -> 60000 
    πŸ•° 2 month latter unclaimed -> 0 
    
    πŸ•° B total -> 60000 
    πŸ•° B unclaimed -> 0 
    
    πŸ•° 13 month latter total -> 60000 
    πŸ•° 13 month latter unclaimed -> 1369 
    
    πŸ•° 2 year latter total -> 60000 
    πŸ•° 2 year latter unclaimed -> 20000 
    
    πŸ•° C total -> 60000 
    πŸ•° C unclaimed -> 60000 
    

    , but how to see the progress of vesting happening?

    opened by intmainreturn00 1
  • Tests fails at M1 πŸ™

    Tests fails at M1 πŸ™

    When I run tests from 404bc2c06f144a5dda729e34dd1c66903fbdbd24 at M1 it fails

    cargo test -- --nocapture test_lockup_claim_logic
        Finished test [unoptimized + debuginfo] target(s) in 0.15s
         Running unittests (target/debug/deps/ft_lockup-f3e113e050fc0ef1)
    
    running 0 tests
    
    test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
    
         Running tests/main.rs (target/debug/deps/main-a9d217f01e79e5ba)
    
    running 1 test
    thread 'test_lockup_claim_logic' panicked at 'AVX support is required in order to run Wasmer VM Singlepass backend.', /Users/owl/.cargo/registry/src/github.com-1ecc6299db9ec823/near-vm-runner-4.0.0-pre.1/src/wasmer_runner.rs:194:9
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    test test_lockup_claim_logic ... FAILED
    
    failures:
    
    failures:
        test_lockup_claim_logic
    
    test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 7 filtered out; finished in 0.11s
    
    error: test failed, to rerun pass '--test main'
    
    

    Is it possible to run tests on M1 ?

    opened by intmainreturn00 1
Owner
null
Token management program (vesting and mining) implemented in Anchor

Deep Dive into Anchor by Implementing Token Management Program Author: @ironaddicteddog, @emersonliuuu [Updated at 2022.5.21] You can find the full co

Jim 31 Jun 13, 2023
NFT & Marketplace Contracts with royalties and fungible token support. Sample React app included.

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

NEAR App Examples 156 Apr 28, 2022
Bespoke toolkit for Non-fungible token (NFT) technology πŸš€

Bespoke toolkit for Non-fungible token (NFT) technology ?? What is Onft? Instead of forcing a consensus algorithm or peer networking on you, Onft prov

Owez 5 Jan 9, 2022
Dfinity's fungible token standard. Any PRs and comments are welcome,collaborate with us to build this standard

Dfinity's fungible token standard. Any PRs and comments are welcome,collaborate with us to build this standard

Deland Labs 46 Nov 7, 2022
DIP721 - An Internet Computer Non-fungible Token Standard

DIP721 - Introduction DIP721 is an ERC-721 style non-fungible token standard built mirroring its Ethereum counterpart and adapting it to the Internet

Psychedelic 48 Nov 24, 2022
ARYA Network is a polkadot/substrate based chain for Non-fungible Token platform on which we can own sell and buy the NFT's on polkadot network.

ARYA Network ARYA Network is a polkadot/substrate based chain for Non-fungible Token platform on which we can own sell and buy the NFT's on polkadot n

Pankaj Chaudhary 6 Dec 20, 2022
An all-in-one IBC protocol providing fungible token transfer, interchain account, and async query functionalities

ICS-999 An all-in-one IBC protocol providing fungible token transfer, interchain account (ICA), and query (ICQ) functionalities, implemented in CosmWa

larry 9 Apr 1, 2023
Dank - The Internet Computer Decentralized Bank - A collection of Open Internet Services - Including the Cycles Token (XTC)

Dank - The Internet Computer Decentralized Bank Dank is a collection of Open Internet Services for users and developers on the Internet Computer. In t

Psychedelic 56 Nov 12, 2022
Audit Cargo.lock files for dependencies with security vulnerabilities

RustSec Crates ?? ??️ ?? The RustSec Advisory Database is a repository of security advisories filed against Rust crates published via crates.io. The a

RustSec 1.2k Dec 30, 2022
Open source Rust implementation of the Witnet decentralized oracle protocol, including full node and wallet backend πŸ‘οΈπŸ¦€

witnet-rust is an open source implementation of the Witnet Decentralized Oracle Network protocol written in Rust. Components witnet-rust implements ma

The Witnet Project 155 Nov 21, 2022
Rust library for practical time-lock encryption using `drand` threshold network

tlock-rs: Practical Timelock Encryption/Decryption in Rust This repo contains pure Rust implementation of drand/tlock scheme. It provides time-based e

Timofey 32 Jan 8, 2023
Rust encryption library for practical time-lock encryption.

tlock_age: Hybrid Timelock Encryption/Decryption in Rust tlock_age is a library to encrypt and decrypt age filekey using tlock scheme. It provides an

Thibault 5 Mar 29, 2023
Arkworks circuits for verifiable time-lock encryption

zk-timelock This repo contains arithmetic circuits for verifiable time-lock encryption made using arkworks-rs toolkit. For more details on such an enc

Timofey 68 Apr 5, 2023
πŸŽ™οΈ Catalyst Voices provides a unified experience and platform including production-ready liquid democracy

??️ Catalyst Voices provides a unified experience and platform including production-ready liquid democracy, meaningful collaboration opportunities & data-driven context for better onboarding & decisions.

Input Output 6 Oct 11, 2023
Example implementation for Biscuit tokens cryptography

example implementation for Biscuit token cryptography To aid in the implementation of Biscuit tokens in various languages, this repository contains an

Clever Cloud 6 May 25, 2021
Helper library for interacting with Terra assets (SDK coins and CW20 tokens)

terra-asset Helpers for interacting with Terra assets, including native coins and CW20 tokens Usage This crate contains two struct types: AssetInfo st

larry 9 Jan 3, 2022
Example of a SC coded in RUST that can safely perform any swaps of tokens (NFT, SFT, ESDT, MetaESDT)

Elrond-NFT-Trading Example of a Smart Contract (SC) coded in RUST, that can perform any swaps of tokens (NFT, SFT, ESDT, MetaESDT) The idea P2P swaps

Sia 3 May 17, 2022
Simple PoC to issue JSON Web Tokens (JWTs) with a canister on the Internet Computer.

JWT Issuer Proof of Concept Overview Simple PoC to issue JSON Web Tokens (JWTs) with a canister on the Internet Computer. It allows the issuance of tw

Dominic WΓΆrner 7 Oct 13, 2022
Extends cargo to execute the given command on multiple crates - upstream is at

cargo-multi GitLab CI: master: develop: Travis: master: develop: Extends cargo to execute the given command on multiple crates. Inspired by git multi.

Cyril Plisko 6 Feb 27, 2022