├── .gitignore ├── Cargo.toml ├── .github ├── dependabot.yml ├── ISSUE_TEMPLATE │ ├── backlog-item.md │ ├── feature-request-or-epic.md │ └── bug_report.md ├── pull_request_template.md └── workflows │ └── tests.yml ├── scripts ├── init.sh └── ci.sh ├── example-erc721 ├── Cargo.toml └── src │ ├── mock.rs │ ├── tests.rs │ └── lib.rs ├── chainbridge ├── Cargo.toml └── src │ ├── mock.rs │ ├── tests.rs │ └── lib.rs ├── example-pallet ├── Cargo.toml └── src │ ├── lib.rs │ ├── mock.rs │ └── tests.rs ├── README.md ├── LICENSE └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | target/ 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "chainbridge", 4 | "example-erc721", 5 | "example-pallet" 6 | ] -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "cargo" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | -------------------------------------------------------------------------------- /scripts/init.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eux 4 | 5 | RUST_TOOLCHAIN="${RUST_TOOLCHAIN:-nightly}" 6 | 7 | echo "*** Initializing WASM build environment" 8 | 9 | rustup update $RUST_TOOLCHAIN 10 | rustup update stable 11 | 12 | rustup toolchain install $RUST_TOOLCHAIN 13 | rustup default $RUST_TOOLCHAIN 14 | 15 | rustup target add wasm32-unknown-unknown --toolchain $RUST_TOOLCHAIN 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/backlog-item.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Template For Internal Use 3 | about: Speccing out the details of development for specific features/epics 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | ## Implementation details 13 | 14 | 15 | ## Testing details 16 | 17 | 18 | ## Acceptance Criteria 19 | 20 | -------------------------------------------------------------------------------- /scripts/ci.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eux 4 | 5 | RUST_TOOLCHAIN="${RUST_TOOLCHAIN:-nightly}" 6 | 7 | # Enable warnings about unused extern crates 8 | export RUSTFLAGS=" -W unused-extern-crates" 9 | 10 | # Install rustup and the specified rust toolchain. 11 | curl https://sh.rustup.rs -sSf | sh -s -- -y 12 | 13 | # Load cargo environment. Specifically, put cargo into PATH. 14 | source ~/.cargo/env 15 | 16 | sudo apt-get -y update 17 | sudo apt-get install -y cmake pkg-config libssl-dev 18 | 19 | ./scripts/init.sh 20 | 21 | rustc --version 22 | rustup --version 23 | cargo --version 24 | 25 | case $TARGET in 26 | "build") 27 | cargo build --release --locked "$@" 28 | ;; 29 | 30 | "runtime-test") 31 | cargo test -p chainbridge 32 | ;; 33 | 34 | "fmt") 35 | rustup component add rustfmt 36 | cargo fmt --all -- --check 37 | ;; 38 | esac 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request-or-epic.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request or epic 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Story 11 | As a 12 | I want 13 | So that I can 14 | 15 | ## Background 16 | 17 | 18 | ## Details 19 | 20 | 21 | ## Scenarios 22 | Scenario: 23 | Given I am 24 | When 25 | And 26 | Then 27 | 28 | ## Implementation details 29 | 30 | 31 | ## Testing details 32 | 33 | 34 | ## Acceptance criteria 35 | 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | ## Expected Behavior 13 | 14 | 15 | 16 | ## Current Behavior 17 | 18 | 19 | 20 | ## Possible Solution 21 | 22 | 23 | 24 | ## Steps to Reproduce (for bugs) 25 | 26 | 27 | 1. 28 | 2. 29 | 3. 30 | 4. 31 | 32 | ## Versions 33 | ChainBridge commit (or docker tag): 34 | chainbridge-solidity version: 35 | chainbridge-substrate version: 36 | Go version: 37 | -------------------------------------------------------------------------------- /example-erc721/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = 'example-erc721' 3 | version = '0.0.1' 4 | authors = ['david@chainsafe.io'] 5 | edition = '2018' 6 | 7 | [dependencies] 8 | # third-party dependencies 9 | codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } 10 | serde = { version = "1.0.101", optional = true } 11 | 12 | # primitives 13 | sp-std = { version = "3.0.0", default-features = false } 14 | sp-runtime = { version = "3.0.0", default-features = false } 15 | sp-io = { version = "3.0.0", default-features = false } 16 | sp-core = { version = "3.0.0", default-features = false } 17 | 18 | # frame dependencies 19 | frame-support = { version = "3.0.0", default-features = false } 20 | frame-system = { version = "3.0.0", default-features = false } 21 | 22 | chainbridge = { path = "../chainbridge" , default-features = false } 23 | 24 | [dev-dependencies] 25 | pallet-balances = { version = "3.0.0",default-features = false } 26 | 27 | [build-dependencies] 28 | wasm-builder-runner = { version = "2.0.0", package = "substrate-wasm-builder-runner"} 29 | [features] 30 | default = ["std"] 31 | std = [ 32 | "codec/std", 33 | "serde", 34 | "sp-std/std", 35 | "sp-runtime/std", 36 | "sp-io/std", 37 | "sp-core/std", 38 | "frame-support/std", 39 | "frame-system/std", 40 | "chainbridge/std" 41 | ] 42 | -------------------------------------------------------------------------------- /chainbridge/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = 'chainbridge' 3 | version = '0.0.2' 4 | authors = ['david@chainsafe.io'] 5 | edition = '2018' 6 | 7 | [dependencies] 8 | # third-party dependencies 9 | codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } 10 | serde = { version = "1.0.101", optional = true } 11 | 12 | # primitives 13 | sp-std = { version = "3.0.0", default-features = false } 14 | sp-runtime = { version = "3.0.0", default-features = false } 15 | sp-io = { version = "3.0.0", default-features = false } 16 | sp-core = { version = "3.0.0", default-features = false } 17 | 18 | # frame dependencies 19 | frame-support = { version = "3.0.0", default-features = false } 20 | frame-system = { version = "3.0.0", default-features = false } 21 | 22 | pallet-balances = { version = "3.0.0", default-features = false } 23 | 24 | [build-dependencies] 25 | wasm-builder-runner = { version = "2.0.0", package = "substrate-wasm-builder-runner"} 26 | [features] 27 | default = ["std"] 28 | std = [ 29 | "codec/std", 30 | "serde", 31 | "sp-std/std", 32 | "sp-runtime/std", 33 | "sp-io/std", 34 | "sp-core/std", 35 | "frame-support/std", 36 | "frame-system/std", 37 | "pallet-balances/std", 38 | ] 39 | runtime-benchmarks = [ 40 | "frame-system/runtime-benchmarks", 41 | "frame-support/runtime-benchmarks" 42 | ] 43 | -------------------------------------------------------------------------------- /example-pallet/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = 'example-pallet' 3 | version = '0.0.1' 4 | authors = ['david@chainsafe.io'] 5 | edition = '2018' 6 | 7 | [dependencies] 8 | # third-party dependencies 9 | codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } 10 | serde = { version = "1.0.101", optional = true } 11 | 12 | # primitives 13 | sp-std = { version = "3.0.0", default-features = false } 14 | sp-runtime = { version = "3.0.0", default-features = false } 15 | sp-io = { version = "3.0.0", default-features = false } 16 | sp-core = { version = "3.0.0", default-features = false } 17 | sp-arithmetic = { version = "3.0.0", default-features = false } 18 | 19 | # frame dependencies 20 | frame-support = { version = "3.0.0", default-features = false } 21 | frame-system = { version = "3.0.0", default-features = false } 22 | 23 | chainbridge = { path = "../chainbridge" , default-features = false} 24 | example-erc721 = { path = "../example-erc721", default-features = false } 25 | 26 | [dev-dependencies] 27 | pallet-balances = { version = "3.0.0", default-features = false } 28 | 29 | [build-dependencies] 30 | wasm-builder-runner = { version = "2.0.0", package = "substrate-wasm-builder-runner" } 31 | [features] 32 | default = ["std"] 33 | std = [ 34 | "codec/std", 35 | "serde", 36 | "sp-std/std", 37 | "sp-runtime/std", 38 | "sp-io/std", 39 | "sp-core/std", 40 | "sp-arithmetic/std", 41 | "frame-support/std", 42 | "frame-system/std", 43 | "chainbridge/std", 44 | "example-erc721/std" 45 | ] 46 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description 4 | 5 | 6 | ## Related Issue Or Context 7 | 8 | 9 | 10 | 11 | Closes: # 12 | 13 | ## How Has This Been Tested? Testing details. 14 | 15 | 16 | 17 | 18 | ## Types of changes 19 | 20 | - [ ] Bug fix (non-breaking change which fixes an issue) 21 | - [ ] New feature (non-breaking change which adds functionality) 22 | - [ ] Breaking change (fix or feature that would cause existing functionality to change) 23 | - [ ] Documentation 24 | 25 | ## Checklist: 26 | 27 | 28 | - [ ] I have commented my code, particularly in hard-to-understand areas. 29 | - [ ] I have ensured that all acceptance criteria (or expected behavior) from issue are met 30 | - [ ] I have updated the documentation locally and in chainbridge-docs. 31 | - [ ] I have added tests to cover my changes. 32 | - [ ] I have ensured that all the checks are passing and green, I've signed the CLA bot 33 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | 2 | name: Tests 3 | 4 | on: 5 | pull_request: 6 | types: [ opened, synchronize, reopened ] 7 | 8 | jobs: 9 | build: 10 | name: Build 11 | runs-on: ubuntu-latest 12 | strategy: 13 | matrix: 14 | target: 15 | - x86_64-unknown-linux-gnu 16 | steps: 17 | - uses: actions/checkout@v2 18 | - uses: actions-rs/toolchain@v1 19 | with: 20 | toolchain: nightly-2020-11-30 21 | target: ${{ matrix.target }} 22 | override: true 23 | - name: Build 24 | uses: actions-rs/cargo@v1 25 | with: 26 | use-cross: true 27 | command: build 28 | args: --release --target=${{ matrix.target }} 29 | 30 | test: 31 | name: Test 32 | runs-on: ubuntu-latest 33 | strategy: 34 | matrix: 35 | target: 36 | - x86_64-unknown-linux-gnu 37 | steps: 38 | - uses: actions/checkout@v2 39 | - uses: actions-rs/toolchain@v1 40 | with: 41 | toolchain: nightly-2020-10-06 42 | target: ${{ matrix.target }} 43 | override: true 44 | - name: Build 45 | uses: actions-rs/cargo@v1 46 | with: 47 | use-cross: true 48 | command: test 49 | 50 | fmt: 51 | name: Cargo fmt 52 | runs-on: ubuntu-latest 53 | strategy: 54 | matrix: 55 | target: 56 | - x86_64-unknown-linux-gnu 57 | steps: 58 | - uses: actions/checkout@v2 59 | - uses: actions-rs/toolchain@v1 60 | with: 61 | toolchain: nightly-2020-10-06 62 | target: ${{ matrix.target }} 63 | components: rustfmt 64 | override: true 65 | - name: Build 66 | uses: actions-rs/cargo@v1 67 | with: 68 | use-cross: true 69 | command: fmt 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Archiving notice: 2 | 3 | This library is no longer in use and maintenance. All further development related to chainbridge will happen in the **[new](https://github.com/ChainSafe/chainbridge-core)** repo. More detailed information about chainbridge-core you can find in its readme or [Discussions](https://github.com/ChainSafe/chainbridge-core/discussions). 4 | 5 | If you already running an old ChainBridge version please consider checking **[chainbridge-migration](https://github.com/ChainSafe/chainbridge-migration)** scripts that allow migrating to a newer version of chainbridge. 6 | 7 | # chainbridge-substrate 8 | 9 | [![Build Status](https://travis-ci.com/ChainSafe/chainbridge-substrate.svg?branch=master)](https://travis-ci.com/ChainSafe/chainbridge-substrate) 10 | 11 | Substrate implementation for [ChainBridge](https://github.com/ChainSafe/ChainBridge). 12 | 13 | This repo contains two pallets: 14 | 15 | ## chainbridge 16 | 17 | The core bridge logic. This handles voting and execution of proposals, administration of the relayer set and signaling transfers. 18 | 19 | 20 | ## example-pallet 21 | 22 | This pallet demonstrates how the chainbridge pallet can be integrated in to a substrate chain. It implements calls that can be executed through proposal only and to initiate a basic transfer across the bridge. 23 | 24 | ## example-erc721 25 | 26 | This pallet mimics an ERC721 token contract. It allows for minting, burning and transferring of tokens that consist of a token ID (`U256`) and some metadata (`Vec`). This is also integrated into `example-pallet` to demonstrate how non-fungibles can be transferred across the bridge. 27 | 28 | # ChainSafe Security Policy 29 | 30 | ## Reporting a Security Bug 31 | 32 | We take all security issues seriously, if you believe you have found a security issue within a ChainSafe 33 | project please notify us immediately. If an issue is confirmed, we will take all necessary precautions 34 | to ensure a statement and patch release is made in a timely manner. 35 | 36 | Please email us a description of the flaw and any related information (e.g. reproduction steps, version) to 37 | [security at chainsafe dot io](mailto:security@chainsafe.io). 38 | -------------------------------------------------------------------------------- /example-erc721/src/mock.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | use frame_support::{ord_parameter_types, parameter_types, weights::Weight}; 4 | use frame_system::{self as system}; 5 | use sp_core::hashing::blake2_128; 6 | use sp_core::H256; 7 | use sp_runtime::{ 8 | testing::Header, 9 | traits::{BlakeTwo256, IdentityLookup}, 10 | BuildStorage, Perbill, 11 | }; 12 | 13 | use crate::{self as erc721, Config}; 14 | use chainbridge as bridge; 15 | pub use pallet_balances as balances; 16 | 17 | parameter_types! { 18 | pub const BlockHashCount: u64 = 250; 19 | pub const MaximumBlockWeight: Weight = 1024; 20 | pub const MaximumBlockLength: u32 = 2 * 1024; 21 | pub const AvailableBlockRatio: Perbill = Perbill::one(); 22 | pub const MaxLocks: u32 = 100; 23 | } 24 | 25 | impl frame_system::Config for Test { 26 | type BaseCallFilter = (); 27 | type Origin = Origin; 28 | type Call = Call; 29 | type Index = u64; 30 | type BlockNumber = u64; 31 | type Hash = H256; 32 | type Hashing = BlakeTwo256; 33 | type AccountId = u64; 34 | type Lookup = IdentityLookup; 35 | type Header = Header; 36 | type Event = Event; 37 | type BlockHashCount = BlockHashCount; 38 | type DbWeight = (); 39 | type Version = (); 40 | type AccountData = pallet_balances::AccountData; 41 | type OnNewAccount = (); 42 | type OnKilledAccount = (); 43 | type SystemWeightInfo = (); 44 | type PalletInfo = PalletInfo; 45 | type BlockWeights = (); 46 | type BlockLength = (); 47 | type SS58Prefix = (); 48 | } 49 | 50 | parameter_types! { 51 | pub const ExistentialDeposit: u64 = 1; 52 | } 53 | 54 | ord_parameter_types! { 55 | pub const One: u64 = 1; 56 | } 57 | 58 | impl pallet_balances::Config for Test { 59 | type Balance = u64; 60 | type DustRemoval = (); 61 | type Event = Event; 62 | type ExistentialDeposit = ExistentialDeposit; 63 | type AccountStore = System; 64 | type MaxLocks = MaxLocks; 65 | type WeightInfo = (); 66 | } 67 | 68 | parameter_types! { 69 | pub Erc721Id: bridge::ResourceId = bridge::derive_resource_id(1, &blake2_128(b"NFT")); 70 | } 71 | 72 | impl Config for Test { 73 | type Event = Event; 74 | type Identifier = Erc721Id; 75 | } 76 | 77 | pub type Block = sp_runtime::generic::Block; 78 | pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; 79 | 80 | frame_support::construct_runtime!( 81 | pub enum Test where 82 | Block = Block, 83 | NodeBlock = Block, 84 | UncheckedExtrinsic = UncheckedExtrinsic 85 | { 86 | System: system::{Module, Call, Event}, 87 | Balances: balances::{Module, Call, Storage, Config, Event}, 88 | Erc721: erc721::{Module, Call, Storage, Event}, 89 | } 90 | ); 91 | 92 | pub const USER_A: u64 = 0x1; 93 | pub const USER_B: u64 = 0x2; 94 | pub const USER_C: u64 = 0x3; 95 | pub const ENDOWED_BALANCE: u64 = 100_000_000; 96 | 97 | pub fn new_test_ext() -> sp_io::TestExternalities { 98 | GenesisConfig { 99 | balances: Some(balances::GenesisConfig { 100 | balances: vec![(USER_A, ENDOWED_BALANCE)], 101 | }), 102 | } 103 | .build_storage() 104 | .unwrap() 105 | .into() 106 | } 107 | -------------------------------------------------------------------------------- /example-erc721/src/tests.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | use super::mock::{new_test_ext, Erc721, Origin, Test, USER_A, USER_B, USER_C}; 4 | use super::*; 5 | use frame_support::{assert_noop, assert_ok}; 6 | use sp_core::U256; 7 | 8 | #[test] 9 | fn mint_burn_tokens() { 10 | new_test_ext().execute_with(|| { 11 | let id_a: U256 = 1.into(); 12 | let id_b: U256 = 2.into(); 13 | let metadata_a: Vec = vec![1, 2, 3]; 14 | let metadata_b: Vec = vec![4, 5, 6]; 15 | 16 | assert_ok!(Erc721::mint( 17 | Origin::root(), 18 | USER_A, 19 | id_a, 20 | metadata_a.clone() 21 | )); 22 | assert_eq!( 23 | Erc721::tokens(id_a).unwrap(), 24 | Erc721Token { 25 | id: id_a, 26 | metadata: metadata_a.clone() 27 | } 28 | ); 29 | assert_eq!(Erc721::token_count(), 1.into()); 30 | assert_noop!( 31 | Erc721::mint(Origin::root(), USER_A, id_a, metadata_a.clone()), 32 | Error::::TokenAlreadyExists 33 | ); 34 | 35 | assert_ok!(Erc721::mint( 36 | Origin::root(), 37 | USER_A, 38 | id_b, 39 | metadata_b.clone() 40 | )); 41 | assert_eq!( 42 | Erc721::tokens(id_b).unwrap(), 43 | Erc721Token { 44 | id: id_b, 45 | metadata: metadata_b.clone() 46 | } 47 | ); 48 | assert_eq!(Erc721::token_count(), 2.into()); 49 | assert_noop!( 50 | Erc721::mint(Origin::root(), USER_A, id_b, metadata_b.clone()), 51 | Error::::TokenAlreadyExists 52 | ); 53 | 54 | assert_ok!(Erc721::burn(Origin::root(), id_a)); 55 | assert_eq!(Erc721::token_count(), 1.into()); 56 | assert!(!::contains_key(&id_a)); 57 | assert!(!>::contains_key(&id_a)); 58 | 59 | assert_ok!(Erc721::burn(Origin::root(), id_b)); 60 | assert_eq!(Erc721::token_count(), 0.into()); 61 | assert!(!::contains_key(&id_b)); 62 | assert!(!>::contains_key(&id_b)); 63 | }) 64 | } 65 | 66 | #[test] 67 | fn transfer_tokens() { 68 | new_test_ext().execute_with(|| { 69 | let id_a: U256 = 1.into(); 70 | let id_b: U256 = 2.into(); 71 | let metadata_a: Vec = vec![1, 2, 3]; 72 | let metadata_b: Vec = vec![4, 5, 6]; 73 | 74 | assert_ok!(Erc721::mint( 75 | Origin::root(), 76 | USER_A, 77 | id_a, 78 | metadata_a.clone() 79 | )); 80 | assert_ok!(Erc721::mint( 81 | Origin::root(), 82 | USER_A, 83 | id_b, 84 | metadata_b.clone() 85 | )); 86 | 87 | assert_ok!(Erc721::transfer(Origin::signed(USER_A), USER_B, id_a)); 88 | assert_eq!(Erc721::owner_of(id_a).unwrap(), USER_B); 89 | 90 | assert_ok!(Erc721::transfer(Origin::signed(USER_A), USER_C, id_b)); 91 | assert_eq!(Erc721::owner_of(id_b).unwrap(), USER_C); 92 | 93 | assert_ok!(Erc721::transfer(Origin::signed(USER_B), USER_A, id_a)); 94 | assert_eq!(Erc721::owner_of(id_a).unwrap(), USER_A); 95 | 96 | assert_ok!(Erc721::transfer(Origin::signed(USER_C), USER_A, id_b)); 97 | assert_eq!(Erc721::owner_of(id_b).unwrap(), USER_A); 98 | }) 99 | } 100 | -------------------------------------------------------------------------------- /example-erc721/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Ensure we're `no_std` when compiling for Wasm. 2 | #![cfg_attr(not(feature = "std"), no_std)] 3 | 4 | use codec::{Decode, Encode}; 5 | use frame_support::{ 6 | decl_error, decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure, 7 | traits::Get, 8 | }; 9 | use frame_system::{self as system, ensure_root, ensure_signed}; 10 | use sp_core::U256; 11 | use sp_runtime::RuntimeDebug; 12 | use sp_std::prelude::*; 13 | 14 | mod mock; 15 | mod tests; 16 | 17 | type TokenId = U256; 18 | 19 | #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] 20 | pub struct Erc721Token { 21 | pub id: TokenId, 22 | pub metadata: Vec, 23 | } 24 | 25 | pub trait Config: system::Config { 26 | type Event: From> + Into<::Event>; 27 | 28 | /// Some identifier for this token type, possibly the originating ethereum address. 29 | /// This is not explicitly used for anything, but may reflect the bridge's notion of resource ID. 30 | type Identifier: Get<[u8; 32]>; 31 | } 32 | 33 | decl_event! { 34 | pub enum Event 35 | where 36 | ::AccountId, 37 | { 38 | /// New token created 39 | Minted(AccountId, TokenId), 40 | /// Token transfer between two parties 41 | Transferred(AccountId, AccountId, TokenId), 42 | /// Token removed from the system 43 | Burned(TokenId), 44 | } 45 | } 46 | 47 | decl_error! { 48 | pub enum Error for Module { 49 | /// ID not recognized 50 | TokenIdDoesNotExist, 51 | /// Already exists with an owner 52 | TokenAlreadyExists, 53 | /// Origin is not owner 54 | NotOwner, 55 | } 56 | } 57 | 58 | decl_storage! { 59 | trait Store for Module as TokenStorage { 60 | /// Maps tokenId to Erc721 object 61 | Tokens get(fn tokens): map hasher(opaque_blake2_256) TokenId => Option; 62 | /// Maps tokenId to owner 63 | TokenOwner get(fn owner_of): map hasher(opaque_blake2_256) TokenId => Option; 64 | /// Total number of tokens in existence 65 | TokenCount get(fn token_count): U256 = U256::zero(); 66 | } 67 | } 68 | 69 | decl_module! { 70 | pub struct Module for enum Call where origin: T::Origin { 71 | type Error = Error; 72 | fn deposit_event() = default; 73 | 74 | /// Creates a new token with the given token ID and metadata, and gives ownership to owner 75 | #[weight = 195_000_000] 76 | pub fn mint(origin, owner: T::AccountId, id: TokenId, metadata: Vec) -> DispatchResult { 77 | ensure_root(origin)?; 78 | 79 | Self::mint_token(owner, id, metadata)?; 80 | 81 | Ok(()) 82 | } 83 | 84 | /// Changes ownership of a token sender owns 85 | #[weight = 195_000_000] 86 | pub fn transfer(origin, to: T::AccountId, id: TokenId) -> DispatchResult { 87 | let sender = ensure_signed(origin)?; 88 | 89 | Self::transfer_from(sender, to, id)?; 90 | 91 | Ok(()) 92 | } 93 | 94 | /// Remove token from the system 95 | #[weight = 195_000_000] 96 | pub fn burn(origin, id: TokenId) -> DispatchResult { 97 | ensure_root(origin)?; 98 | 99 | let owner = Self::owner_of(id).ok_or(Error::::TokenIdDoesNotExist)?; 100 | 101 | Self::burn_token(owner, id)?; 102 | 103 | Ok(()) 104 | } 105 | } 106 | } 107 | 108 | impl Module { 109 | /// Creates a new token in the system. 110 | pub fn mint_token(owner: T::AccountId, id: TokenId, metadata: Vec) -> DispatchResult { 111 | ensure!(!Tokens::contains_key(id), Error::::TokenAlreadyExists); 112 | 113 | let new_token = Erc721Token { id, metadata }; 114 | 115 | ::insert(&id, new_token); 116 | >::insert(&id, owner.clone()); 117 | let new_total = ::get().saturating_add(U256::one()); 118 | ::put(new_total); 119 | 120 | Self::deposit_event(RawEvent::Minted(owner, id)); 121 | 122 | Ok(()) 123 | } 124 | 125 | /// Modifies ownership of a token 126 | pub fn transfer_from(from: T::AccountId, to: T::AccountId, id: TokenId) -> DispatchResult { 127 | // Check from is owner and token exists 128 | let owner = Self::owner_of(id).ok_or(Error::::TokenIdDoesNotExist)?; 129 | ensure!(owner == from, Error::::NotOwner); 130 | // Update owner 131 | >::insert(&id, to.clone()); 132 | 133 | Self::deposit_event(RawEvent::Transferred(from, to, id)); 134 | 135 | Ok(()) 136 | } 137 | 138 | /// Deletes a token from the system. 139 | pub fn burn_token(from: T::AccountId, id: TokenId) -> DispatchResult { 140 | let owner = Self::owner_of(id).ok_or(Error::::TokenIdDoesNotExist)?; 141 | ensure!(owner == from, Error::::NotOwner); 142 | 143 | ::remove(&id); 144 | >::remove(&id); 145 | let new_total = ::get().saturating_sub(U256::one()); 146 | ::put(new_total); 147 | 148 | Self::deposit_event(RawEvent::Burned(id)); 149 | 150 | Ok(()) 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /chainbridge/src/mock.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | use super::*; 4 | 5 | use frame_support::{assert_ok, ord_parameter_types, parameter_types, weights::Weight}; 6 | use frame_system::{self as system}; 7 | use sp_core::H256; 8 | use sp_runtime::{ 9 | testing::Header, 10 | traits::{AccountIdConversion, BlakeTwo256, IdentityLookup}, 11 | Perbill, 12 | }; 13 | 14 | use crate::{self as bridge, Config}; 15 | pub use pallet_balances as balances; 16 | 17 | parameter_types! { 18 | pub const BlockHashCount: u64 = 250; 19 | pub const MaximumBlockWeight: Weight = 1024; 20 | pub const MaximumBlockLength: u32 = 2 * 1024; 21 | pub const AvailableBlockRatio: Perbill = Perbill::one(); 22 | pub const MaxLocks: u32 = 100; 23 | } 24 | 25 | impl frame_system::Config for Test { 26 | type BaseCallFilter = (); 27 | type Origin = Origin; 28 | type Call = Call; 29 | type Index = u64; 30 | type BlockNumber = u64; 31 | type Hash = H256; 32 | type Hashing = BlakeTwo256; 33 | type AccountId = u64; 34 | type Lookup = IdentityLookup; 35 | type Header = Header; 36 | type Event = Event; 37 | type BlockHashCount = BlockHashCount; 38 | type DbWeight = (); 39 | type Version = (); 40 | type AccountData = pallet_balances::AccountData; 41 | type OnNewAccount = (); 42 | type OnKilledAccount = (); 43 | type SystemWeightInfo = (); 44 | type PalletInfo = PalletInfo; 45 | type BlockWeights = (); 46 | type BlockLength = (); 47 | type SS58Prefix = (); 48 | } 49 | 50 | parameter_types! { 51 | pub const ExistentialDeposit: u64 = 1; 52 | } 53 | 54 | ord_parameter_types! { 55 | pub const One: u64 = 1; 56 | } 57 | 58 | impl pallet_balances::Config for Test { 59 | type Balance = u64; 60 | type DustRemoval = (); 61 | type Event = Event; 62 | type ExistentialDeposit = ExistentialDeposit; 63 | type AccountStore = System; 64 | type MaxLocks = MaxLocks; 65 | type WeightInfo = (); 66 | } 67 | 68 | parameter_types! { 69 | pub const TestChainId: u8 = 5; 70 | pub const ProposalLifetime: u64 = 50; 71 | } 72 | 73 | impl Config for Test { 74 | type Event = Event; 75 | type AdminOrigin = frame_system::EnsureRoot; 76 | type Proposal = Call; 77 | type ChainId = TestChainId; 78 | type ProposalLifetime = ProposalLifetime; 79 | } 80 | 81 | pub type Block = sp_runtime::generic::Block; 82 | pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; 83 | 84 | frame_support::construct_runtime!( 85 | pub enum Test where 86 | Block = Block, 87 | NodeBlock = Block, 88 | UncheckedExtrinsic = UncheckedExtrinsic 89 | { 90 | System: system::{Module, Call, Event}, 91 | Balances: balances::{Module, Call, Storage, Config, Event}, 92 | Bridge: bridge::{Module, Call, Storage, Event}, 93 | } 94 | ); 95 | 96 | // pub const BRIDGE_ID: u64 = 97 | pub const RELAYER_A: u64 = 0x2; 98 | pub const RELAYER_B: u64 = 0x3; 99 | pub const RELAYER_C: u64 = 0x4; 100 | pub const ENDOWED_BALANCE: u64 = 100_000_000; 101 | pub const TEST_THRESHOLD: u32 = 2; 102 | 103 | pub fn new_test_ext() -> sp_io::TestExternalities { 104 | let bridge_id = ModuleId(*b"cb/bridg").into_account(); 105 | let mut t = frame_system::GenesisConfig::default() 106 | .build_storage::() 107 | .unwrap(); 108 | pallet_balances::GenesisConfig:: { 109 | balances: vec![(bridge_id, ENDOWED_BALANCE)], 110 | } 111 | .assimilate_storage(&mut t) 112 | .unwrap(); 113 | let mut ext = sp_io::TestExternalities::new(t); 114 | ext.execute_with(|| System::set_block_number(1)); 115 | ext 116 | } 117 | 118 | pub fn new_test_ext_initialized( 119 | src_id: ChainId, 120 | r_id: ResourceId, 121 | resource: Vec, 122 | ) -> sp_io::TestExternalities { 123 | let mut t = new_test_ext(); 124 | t.execute_with(|| { 125 | // Set and check threshold 126 | assert_ok!(Bridge::set_threshold(Origin::root(), TEST_THRESHOLD)); 127 | assert_eq!(Bridge::relayer_threshold(), TEST_THRESHOLD); 128 | // Add relayers 129 | assert_ok!(Bridge::add_relayer(Origin::root(), RELAYER_A)); 130 | assert_ok!(Bridge::add_relayer(Origin::root(), RELAYER_B)); 131 | assert_ok!(Bridge::add_relayer(Origin::root(), RELAYER_C)); 132 | // Whitelist chain 133 | assert_ok!(Bridge::whitelist_chain(Origin::root(), src_id)); 134 | // Set and check resource ID mapped to some junk data 135 | assert_ok!(Bridge::set_resource(Origin::root(), r_id, resource)); 136 | assert_eq!(Bridge::resource_exists(r_id), true); 137 | }); 138 | t 139 | } 140 | 141 | // Checks events against the latest. A contiguous set of events must be provided. They must 142 | // include the most recent event, but do not have to include every past event. 143 | pub fn assert_events(mut expected: Vec) { 144 | let mut actual: Vec = system::Module::::events() 145 | .iter() 146 | .map(|e| e.event.clone()) 147 | .collect(); 148 | 149 | expected.reverse(); 150 | 151 | for evt in expected { 152 | let next = actual.pop().expect("event expected"); 153 | assert_eq!(next, evt.into(), "Events don't match (actual,expected)"); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /example-pallet/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Ensure we're `no_std` when compiling for Wasm. 2 | #![cfg_attr(not(feature = "std"), no_std)] 3 | 4 | use chainbridge as bridge; 5 | use example_erc721 as erc721; 6 | use frame_support::traits::{Currency, EnsureOrigin, ExistenceRequirement::AllowDeath, Get}; 7 | use frame_support::{decl_error, decl_event, decl_module, dispatch::DispatchResult, ensure}; 8 | use frame_system::{self as system, ensure_signed}; 9 | use sp_arithmetic::traits::SaturatedConversion; 10 | use sp_core::U256; 11 | use sp_std::prelude::*; 12 | 13 | mod mock; 14 | mod tests; 15 | 16 | type ResourceId = bridge::ResourceId; 17 | 18 | type BalanceOf = 19 | <::Currency as Currency<::AccountId>>::Balance; 20 | 21 | pub trait Config: system::Config + bridge::Config + erc721::Config { 22 | type Event: From> + Into<::Event>; 23 | /// Specifies the origin check provided by the bridge for calls that can only be called by the bridge pallet 24 | type BridgeOrigin: EnsureOrigin; 25 | 26 | /// The currency mechanism. 27 | type Currency: Currency; 28 | 29 | /// Ids can be defined by the runtime and passed in, perhaps from blake2b_128 hashes. 30 | type HashId: Get; 31 | type NativeTokenId: Get; 32 | type Erc721Id: Get; 33 | } 34 | 35 | decl_event! { 36 | pub enum Event where 37 | ::Hash, 38 | { 39 | Remark(Hash), 40 | } 41 | } 42 | 43 | decl_error! { 44 | pub enum Error for Module{ 45 | InvalidTransfer, 46 | } 47 | } 48 | 49 | decl_module! { 50 | pub struct Module for enum Call where origin: T::Origin { 51 | const HashId: ResourceId = T::HashId::get(); 52 | const NativeTokenId: ResourceId = T::NativeTokenId::get(); 53 | const Erc721Id: ResourceId = T::Erc721Id::get(); 54 | 55 | fn deposit_event() = default; 56 | 57 | // 58 | // Initiation calls. These start a bridge transfer. 59 | // 60 | 61 | /// Transfers an arbitrary hash to a (whitelisted) destination chain. 62 | #[weight = 195_000_000] 63 | pub fn transfer_hash(origin, hash: T::Hash, dest_id: bridge::ChainId) -> DispatchResult { 64 | ensure_signed(origin)?; 65 | 66 | let resource_id = T::HashId::get(); 67 | let metadata: Vec = hash.as_ref().to_vec(); 68 | >::transfer_generic(dest_id, resource_id, metadata) 69 | } 70 | 71 | /// Transfers some amount of the native token to some recipient on a (whitelisted) destination chain. 72 | #[weight = 195_000_000] 73 | pub fn transfer_native(origin, amount: BalanceOf, recipient: Vec, dest_id: bridge::ChainId) -> DispatchResult { 74 | let source = ensure_signed(origin)?; 75 | ensure!(>::chain_whitelisted(dest_id), Error::::InvalidTransfer); 76 | let bridge_id = >::account_id(); 77 | T::Currency::transfer(&source, &bridge_id, amount.into(), AllowDeath)?; 78 | 79 | let resource_id = T::NativeTokenId::get(); 80 | >::transfer_fungible(dest_id, resource_id, recipient, U256::from(amount.saturated_into::())) 81 | } 82 | 83 | /// Transfer a non-fungible token (erc721) to a (whitelisted) destination chain. 84 | #[weight = 195_000_000] 85 | pub fn transfer_erc721(origin, recipient: Vec, token_id: U256, dest_id: bridge::ChainId) -> DispatchResult { 86 | let source = ensure_signed(origin)?; 87 | ensure!(>::chain_whitelisted(dest_id), Error::::InvalidTransfer); 88 | match >::tokens(&token_id) { 89 | Some(token) => { 90 | >::burn_token(source, token_id)?; 91 | let resource_id = T::Erc721Id::get(); 92 | let tid: &mut [u8] = &mut[0; 32]; 93 | token_id.to_big_endian(tid); 94 | >::transfer_nonfungible(dest_id, resource_id, tid.to_vec(), recipient, token.metadata) 95 | } 96 | None => Err(Error::::InvalidTransfer)? 97 | } 98 | } 99 | 100 | // 101 | // Executable calls. These can be triggered by a bridge transfer initiated on another chain 102 | // 103 | 104 | /// Executes a simple currency transfer using the bridge account as the source 105 | #[weight = 195_000_000] 106 | pub fn transfer(origin, to: T::AccountId, amount: BalanceOf, r_id: ResourceId) -> DispatchResult { 107 | let source = T::BridgeOrigin::ensure_origin(origin)?; 108 | ::Currency::transfer(&source, &to, amount.into(), AllowDeath)?; 109 | Ok(()) 110 | } 111 | 112 | /// This can be called by the bridge to demonstrate an arbitrary call from a proposal. 113 | #[weight = 195_000_000] 114 | pub fn remark(origin, hash: T::Hash, r_id: ResourceId) -> DispatchResult { 115 | T::BridgeOrigin::ensure_origin(origin)?; 116 | Self::deposit_event(RawEvent::Remark(hash)); 117 | Ok(()) 118 | } 119 | 120 | /// Allows the bridge to issue new erc721 tokens 121 | #[weight = 195_000_000] 122 | pub fn mint_erc721(origin, recipient: T::AccountId, id: U256, metadata: Vec, r_id: ResourceId) -> DispatchResult { 123 | T::BridgeOrigin::ensure_origin(origin)?; 124 | >::mint_token(recipient, id, metadata)?; 125 | Ok(()) 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /example-pallet/src/mock.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | use super::*; 4 | 5 | use frame_support::{ord_parameter_types, parameter_types, weights::Weight}; 6 | use frame_system::{self as system}; 7 | use sp_core::hashing::blake2_128; 8 | use sp_core::H256; 9 | use sp_runtime::{ 10 | testing::Header, 11 | traits::{AccountIdConversion, BlakeTwo256, IdentityLookup}, 12 | ModuleId, Perbill, 13 | }; 14 | 15 | use crate::{self as example, Config}; 16 | use chainbridge as bridge; 17 | pub use pallet_balances as balances; 18 | 19 | parameter_types! { 20 | pub const BlockHashCount: u64 = 250; 21 | pub const MaximumBlockWeight: Weight = 1024; 22 | pub const MaximumBlockLength: u32 = 2 * 1024; 23 | pub const AvailableBlockRatio: Perbill = Perbill::one(); 24 | pub const MaxLocks: u32 = 100; 25 | } 26 | 27 | impl frame_system::Config for Test { 28 | type BaseCallFilter = (); 29 | type Origin = Origin; 30 | type Call = Call; 31 | type Index = u64; 32 | type BlockNumber = u64; 33 | type Hash = H256; 34 | type Hashing = BlakeTwo256; 35 | type AccountId = u64; 36 | type Lookup = IdentityLookup; 37 | type Header = Header; 38 | type Event = Event; 39 | type BlockHashCount = BlockHashCount; 40 | type DbWeight = (); 41 | type Version = (); 42 | type AccountData = pallet_balances::AccountData; 43 | type OnNewAccount = (); 44 | type OnKilledAccount = (); 45 | type SystemWeightInfo = (); 46 | type PalletInfo = PalletInfo; 47 | type BlockWeights = (); 48 | type BlockLength = (); 49 | type SS58Prefix = (); 50 | } 51 | 52 | parameter_types! { 53 | pub const ExistentialDeposit: u64 = 1; 54 | } 55 | 56 | ord_parameter_types! { 57 | pub const One: u64 = 1; 58 | } 59 | 60 | impl pallet_balances::Config for Test { 61 | type Balance = u64; 62 | type DustRemoval = (); 63 | type Event = Event; 64 | type ExistentialDeposit = ExistentialDeposit; 65 | type AccountStore = System; 66 | type MaxLocks = MaxLocks; 67 | type WeightInfo = (); 68 | } 69 | 70 | parameter_types! { 71 | pub const TestChainId: u8 = 5; 72 | pub const ProposalLifetime: u64 = 100; 73 | } 74 | 75 | impl bridge::Config for Test { 76 | type Event = Event; 77 | type AdminOrigin = frame_system::EnsureRoot; 78 | type Proposal = Call; 79 | type ChainId = TestChainId; 80 | type ProposalLifetime = ProposalLifetime; 81 | } 82 | 83 | parameter_types! { 84 | pub HashId: bridge::ResourceId = bridge::derive_resource_id(1, &blake2_128(b"hash")); 85 | pub NativeTokenId: bridge::ResourceId = bridge::derive_resource_id(1, &blake2_128(b"DAV")); 86 | pub Erc721Id: bridge::ResourceId = bridge::derive_resource_id(1, &blake2_128(b"NFT")); 87 | } 88 | 89 | impl erc721::Config for Test { 90 | type Event = Event; 91 | type Identifier = Erc721Id; 92 | } 93 | 94 | impl Config for Test { 95 | type Event = Event; 96 | type BridgeOrigin = bridge::EnsureBridge; 97 | type Currency = Balances; 98 | type HashId = HashId; 99 | type NativeTokenId = NativeTokenId; 100 | type Erc721Id = Erc721Id; 101 | } 102 | 103 | pub type Block = sp_runtime::generic::Block; 104 | pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; 105 | 106 | frame_support::construct_runtime!( 107 | pub enum Test where 108 | Block = Block, 109 | NodeBlock = Block, 110 | UncheckedExtrinsic = UncheckedExtrinsic 111 | { 112 | System: system::{Module, Call, Event}, 113 | Balances: balances::{Module, Call, Storage, Config, Event}, 114 | Bridge: bridge::{Module, Call, Storage, Event}, 115 | Erc721: erc721::{Module, Call, Storage, Event}, 116 | Example: example::{Module, Call, Event} 117 | } 118 | ); 119 | 120 | pub const RELAYER_A: u64 = 0x2; 121 | pub const RELAYER_B: u64 = 0x3; 122 | pub const RELAYER_C: u64 = 0x4; 123 | pub const ENDOWED_BALANCE: u64 = 100_000_000; 124 | 125 | pub fn new_test_ext() -> sp_io::TestExternalities { 126 | let bridge_id = ModuleId(*b"cb/bridg").into_account(); 127 | let mut t = frame_system::GenesisConfig::default() 128 | .build_storage::() 129 | .unwrap(); 130 | pallet_balances::GenesisConfig:: { 131 | balances: vec![(bridge_id, ENDOWED_BALANCE), (RELAYER_A, ENDOWED_BALANCE)], 132 | } 133 | .assimilate_storage(&mut t) 134 | .unwrap(); 135 | let mut ext = sp_io::TestExternalities::new(t); 136 | ext.execute_with(|| System::set_block_number(1)); 137 | ext 138 | } 139 | 140 | fn last_event() -> Event { 141 | system::Module::::events() 142 | .pop() 143 | .map(|e| e.event) 144 | .expect("Event expected") 145 | } 146 | 147 | pub fn expect_event>(e: E) { 148 | assert_eq!(last_event(), e.into()); 149 | } 150 | 151 | // Asserts that the event was emitted at some point. 152 | pub fn event_exists>(e: E) { 153 | let actual: Vec = system::Module::::events() 154 | .iter() 155 | .map(|e| e.event.clone()) 156 | .collect(); 157 | let e: Event = e.into(); 158 | let mut exists = false; 159 | for evt in actual { 160 | if evt == e { 161 | exists = true; 162 | break; 163 | } 164 | } 165 | assert!(exists); 166 | } 167 | 168 | // Checks events against the latest. A contiguous set of events must be provided. They must 169 | // include the most recent event, but do not have to include every past event. 170 | pub fn assert_events(mut expected: Vec) { 171 | let mut actual: Vec = system::Module::::events() 172 | .iter() 173 | .map(|e| e.event.clone()) 174 | .collect(); 175 | 176 | expected.reverse(); 177 | 178 | for evt in expected { 179 | let next = actual.pop().expect("event expected"); 180 | assert_eq!(next, evt.into(), "Events don't match"); 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /example-pallet/src/tests.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | use super::mock::{ 4 | assert_events, balances, event_exists, expect_event, new_test_ext, Balances, Bridge, Call, 5 | Erc721, Erc721Id, Event, Example, HashId, NativeTokenId, Origin, ProposalLifetime, Test, 6 | ENDOWED_BALANCE, RELAYER_A, RELAYER_B, RELAYER_C, 7 | }; 8 | use super::*; 9 | use frame_support::dispatch::DispatchError; 10 | use frame_support::{assert_noop, assert_ok}; 11 | 12 | use codec::Encode; 13 | use example_erc721::Erc721Token; 14 | use sp_core::{blake2_256, H256}; 15 | 16 | const TEST_THRESHOLD: u32 = 2; 17 | 18 | fn make_remark_proposal(hash: H256) -> Call { 19 | let resource_id = HashId::get(); 20 | Call::Example(crate::Call::remark(hash, resource_id)) 21 | } 22 | 23 | fn make_transfer_proposal(to: u64, amount: u64) -> Call { 24 | let resource_id = HashId::get(); 25 | Call::Example(crate::Call::transfer(to, amount.into(), resource_id)) 26 | } 27 | 28 | #[test] 29 | fn transfer_hash() { 30 | new_test_ext().execute_with(|| { 31 | let dest_chain = 0; 32 | let resource_id = HashId::get(); 33 | let hash: H256 = "ABC".using_encoded(blake2_256).into(); 34 | 35 | assert_ok!(Bridge::set_threshold(Origin::root(), TEST_THRESHOLD,)); 36 | 37 | assert_ok!(Bridge::whitelist_chain(Origin::root(), dest_chain.clone())); 38 | assert_ok!(Example::transfer_hash( 39 | Origin::signed(1), 40 | hash.clone(), 41 | dest_chain, 42 | )); 43 | 44 | expect_event(bridge::RawEvent::GenericTransfer( 45 | dest_chain, 46 | 1, 47 | resource_id, 48 | hash.as_ref().to_vec(), 49 | )); 50 | }) 51 | } 52 | 53 | #[test] 54 | fn transfer_native() { 55 | new_test_ext().execute_with(|| { 56 | let dest_chain = 0; 57 | let resource_id = NativeTokenId::get(); 58 | let amount: u64 = 100; 59 | let recipient = vec![99]; 60 | 61 | assert_ok!(Bridge::whitelist_chain(Origin::root(), dest_chain.clone())); 62 | assert_ok!(Example::transfer_native( 63 | Origin::signed(RELAYER_A), 64 | amount.clone(), 65 | recipient.clone(), 66 | dest_chain, 67 | )); 68 | 69 | expect_event(bridge::RawEvent::FungibleTransfer( 70 | dest_chain, 71 | 1, 72 | resource_id, 73 | amount.into(), 74 | recipient, 75 | )); 76 | }) 77 | } 78 | 79 | #[test] 80 | fn transfer_erc721() { 81 | new_test_ext().execute_with(|| { 82 | let dest_chain = 0; 83 | let resource_id = Erc721Id::get(); 84 | let token_id: U256 = U256::from(100); 85 | let token_id_slice: &mut [u8] = &mut [0; 32]; 86 | token_id.to_big_endian(token_id_slice); 87 | let metadata: Vec = vec![1, 2, 3, 4]; 88 | let recipient = vec![99]; 89 | 90 | // Create a token 91 | assert_ok!(Erc721::mint( 92 | Origin::root(), 93 | RELAYER_A, 94 | token_id, 95 | metadata.clone() 96 | )); 97 | assert_eq!( 98 | Erc721::tokens(token_id).unwrap(), 99 | Erc721Token { 100 | id: token_id, 101 | metadata: metadata.clone() 102 | } 103 | ); 104 | 105 | // Whitelist destination and transfer 106 | assert_ok!(Bridge::whitelist_chain(Origin::root(), dest_chain.clone())); 107 | assert_ok!(Example::transfer_erc721( 108 | Origin::signed(RELAYER_A), 109 | recipient.clone(), 110 | token_id, 111 | dest_chain, 112 | )); 113 | 114 | expect_event(bridge::RawEvent::NonFungibleTransfer( 115 | dest_chain, 116 | 1, 117 | resource_id, 118 | token_id_slice.to_vec(), 119 | recipient.clone(), 120 | metadata, 121 | )); 122 | 123 | // Ensure token no longer exists 124 | assert_eq!(Erc721::tokens(token_id), None); 125 | 126 | // Transfer should fail as token doesn't exist 127 | assert_noop!( 128 | Example::transfer_erc721( 129 | Origin::signed(RELAYER_A), 130 | recipient.clone(), 131 | token_id, 132 | dest_chain, 133 | ), 134 | Error::::InvalidTransfer 135 | ); 136 | }) 137 | } 138 | 139 | #[test] 140 | fn execute_remark() { 141 | new_test_ext().execute_with(|| { 142 | let hash: H256 = "ABC".using_encoded(blake2_256).into(); 143 | let proposal = make_remark_proposal(hash.clone()); 144 | let prop_id = 1; 145 | let src_id = 1; 146 | let r_id = bridge::derive_resource_id(src_id, b"hash"); 147 | let resource = b"Example.remark".to_vec(); 148 | 149 | assert_ok!(Bridge::set_threshold(Origin::root(), TEST_THRESHOLD,)); 150 | assert_ok!(Bridge::add_relayer(Origin::root(), RELAYER_A)); 151 | assert_ok!(Bridge::add_relayer(Origin::root(), RELAYER_B)); 152 | assert_ok!(Bridge::whitelist_chain(Origin::root(), src_id)); 153 | assert_ok!(Bridge::set_resource(Origin::root(), r_id, resource)); 154 | 155 | assert_ok!(Bridge::acknowledge_proposal( 156 | Origin::signed(RELAYER_A), 157 | prop_id, 158 | src_id, 159 | r_id, 160 | Box::new(proposal.clone()) 161 | )); 162 | assert_ok!(Bridge::acknowledge_proposal( 163 | Origin::signed(RELAYER_B), 164 | prop_id, 165 | src_id, 166 | r_id, 167 | Box::new(proposal.clone()) 168 | )); 169 | 170 | event_exists(RawEvent::Remark(hash)); 171 | }) 172 | } 173 | 174 | #[test] 175 | fn execute_remark_bad_origin() { 176 | new_test_ext().execute_with(|| { 177 | let hash: H256 = "ABC".using_encoded(blake2_256).into(); 178 | let resource_id = HashId::get(); 179 | assert_ok!(Example::remark( 180 | Origin::signed(Bridge::account_id()), 181 | hash, 182 | resource_id 183 | )); 184 | // Don't allow any signed origin except from bridge addr 185 | assert_noop!( 186 | Example::remark(Origin::signed(RELAYER_A), hash, resource_id), 187 | DispatchError::BadOrigin 188 | ); 189 | // Don't allow root calls 190 | assert_noop!( 191 | Example::remark(Origin::root(), hash, resource_id), 192 | DispatchError::BadOrigin 193 | ); 194 | }) 195 | } 196 | 197 | #[test] 198 | fn transfer() { 199 | new_test_ext().execute_with(|| { 200 | // Check inital state 201 | let bridge_id: u64 = Bridge::account_id(); 202 | let resource_id = HashId::get(); 203 | assert_eq!(Balances::free_balance(&bridge_id), ENDOWED_BALANCE); 204 | // Transfer and check result 205 | assert_ok!(Example::transfer( 206 | Origin::signed(Bridge::account_id()), 207 | RELAYER_A, 208 | 10, 209 | resource_id, 210 | )); 211 | assert_eq!(Balances::free_balance(&bridge_id), ENDOWED_BALANCE - 10); 212 | assert_eq!(Balances::free_balance(RELAYER_A), ENDOWED_BALANCE + 10); 213 | 214 | assert_events(vec![Event::balances(balances::Event::Transfer( 215 | Bridge::account_id(), 216 | RELAYER_A, 217 | 10, 218 | ))]); 219 | }) 220 | } 221 | 222 | #[test] 223 | fn mint_erc721() { 224 | new_test_ext().execute_with(|| { 225 | let token_id = U256::from(99); 226 | let recipient = RELAYER_A; 227 | let metadata = vec![1, 1, 1, 1]; 228 | let bridge_id: u64 = Bridge::account_id(); 229 | let resource_id = HashId::get(); 230 | // Token doesn't yet exist 231 | assert_eq!(Erc721::tokens(token_id), None); 232 | // Mint 233 | assert_ok!(Example::mint_erc721( 234 | Origin::signed(bridge_id), 235 | recipient, 236 | token_id, 237 | metadata.clone(), 238 | resource_id, 239 | )); 240 | // Ensure token exists 241 | assert_eq!( 242 | Erc721::tokens(token_id).unwrap(), 243 | Erc721Token { 244 | id: token_id, 245 | metadata: metadata.clone() 246 | } 247 | ); 248 | // Cannot mint same token 249 | assert_noop!( 250 | Example::mint_erc721( 251 | Origin::signed(bridge_id), 252 | recipient, 253 | token_id, 254 | metadata.clone(), 255 | resource_id, 256 | ), 257 | erc721::Error::::TokenAlreadyExists 258 | ); 259 | }) 260 | } 261 | 262 | #[test] 263 | fn create_sucessful_transfer_proposal() { 264 | new_test_ext().execute_with(|| { 265 | let prop_id = 1; 266 | let src_id = 1; 267 | let r_id = bridge::derive_resource_id(src_id, b"transfer"); 268 | let resource = b"Example.transfer".to_vec(); 269 | let proposal = make_transfer_proposal(RELAYER_A, 10); 270 | 271 | assert_ok!(Bridge::set_threshold(Origin::root(), TEST_THRESHOLD,)); 272 | assert_ok!(Bridge::add_relayer(Origin::root(), RELAYER_A)); 273 | assert_ok!(Bridge::add_relayer(Origin::root(), RELAYER_B)); 274 | assert_ok!(Bridge::add_relayer(Origin::root(), RELAYER_C)); 275 | assert_ok!(Bridge::whitelist_chain(Origin::root(), src_id)); 276 | assert_ok!(Bridge::set_resource(Origin::root(), r_id, resource)); 277 | 278 | // Create proposal (& vote) 279 | assert_ok!(Bridge::acknowledge_proposal( 280 | Origin::signed(RELAYER_A), 281 | prop_id, 282 | src_id, 283 | r_id, 284 | Box::new(proposal.clone()) 285 | )); 286 | let prop = Bridge::votes(src_id, (prop_id.clone(), proposal.clone())).unwrap(); 287 | let expected = bridge::ProposalVotes { 288 | votes_for: vec![RELAYER_A], 289 | votes_against: vec![], 290 | status: bridge::ProposalStatus::Initiated, 291 | expiry: ProposalLifetime::get() + 1, 292 | }; 293 | assert_eq!(prop, expected); 294 | 295 | // Second relayer votes against 296 | assert_ok!(Bridge::reject_proposal( 297 | Origin::signed(RELAYER_B), 298 | prop_id, 299 | src_id, 300 | r_id, 301 | Box::new(proposal.clone()) 302 | )); 303 | let prop = Bridge::votes(src_id, (prop_id.clone(), proposal.clone())).unwrap(); 304 | let expected = bridge::ProposalVotes { 305 | votes_for: vec![RELAYER_A], 306 | votes_against: vec![RELAYER_B], 307 | status: bridge::ProposalStatus::Initiated, 308 | expiry: ProposalLifetime::get() + 1, 309 | }; 310 | assert_eq!(prop, expected); 311 | 312 | // Third relayer votes in favour 313 | assert_ok!(Bridge::acknowledge_proposal( 314 | Origin::signed(RELAYER_C), 315 | prop_id, 316 | src_id, 317 | r_id, 318 | Box::new(proposal.clone()) 319 | )); 320 | let prop = Bridge::votes(src_id, (prop_id.clone(), proposal.clone())).unwrap(); 321 | let expected = bridge::ProposalVotes { 322 | votes_for: vec![RELAYER_A, RELAYER_C], 323 | votes_against: vec![RELAYER_B], 324 | status: bridge::ProposalStatus::Approved, 325 | expiry: ProposalLifetime::get() + 1, 326 | }; 327 | assert_eq!(prop, expected); 328 | 329 | assert_eq!(Balances::free_balance(RELAYER_A), ENDOWED_BALANCE + 10); 330 | assert_eq!( 331 | Balances::free_balance(Bridge::account_id()), 332 | ENDOWED_BALANCE - 10 333 | ); 334 | 335 | assert_events(vec![ 336 | Event::bridge(bridge::RawEvent::VoteFor(src_id, prop_id, RELAYER_A)), 337 | Event::bridge(bridge::RawEvent::VoteAgainst(src_id, prop_id, RELAYER_B)), 338 | Event::bridge(bridge::RawEvent::VoteFor(src_id, prop_id, RELAYER_C)), 339 | Event::bridge(bridge::RawEvent::ProposalApproved(src_id, prop_id)), 340 | Event::balances(balances::Event::Transfer( 341 | Bridge::account_id(), 342 | RELAYER_A, 343 | 10, 344 | )), 345 | Event::bridge(bridge::RawEvent::ProposalSucceeded(src_id, prop_id)), 346 | ]); 347 | }) 348 | } 349 | -------------------------------------------------------------------------------- /chainbridge/src/tests.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | use super::mock::{ 4 | assert_events, new_test_ext, Balances, Bridge, Call, Event, Origin, ProposalLifetime, System, 5 | Test, TestChainId, ENDOWED_BALANCE, RELAYER_A, RELAYER_B, RELAYER_C, TEST_THRESHOLD, 6 | }; 7 | use super::*; 8 | use crate::mock::new_test_ext_initialized; 9 | use frame_support::{assert_noop, assert_ok}; 10 | 11 | #[test] 12 | fn derive_ids() { 13 | let chain = 1; 14 | let id = [ 15 | 0x21, 0x60, 0x5f, 0x71, 0x84, 0x5f, 0x37, 0x2a, 0x9e, 0xd8, 0x42, 0x53, 0xd2, 0xd0, 0x24, 16 | 0xb7, 0xb1, 0x09, 0x99, 0xf4, 17 | ]; 18 | let r_id = derive_resource_id(chain, &id); 19 | let expected = [ 20 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0x60, 0x5f, 0x71, 0x84, 0x5f, 21 | 0x37, 0x2a, 0x9e, 0xd8, 0x42, 0x53, 0xd2, 0xd0, 0x24, 0xb7, 0xb1, 0x09, 0x99, 0xf4, chain, 22 | ]; 23 | assert_eq!(r_id, expected); 24 | } 25 | 26 | #[test] 27 | fn complete_proposal_approved() { 28 | let mut prop = ProposalVotes { 29 | votes_for: vec![1, 2], 30 | votes_against: vec![3], 31 | status: ProposalStatus::Initiated, 32 | expiry: ProposalLifetime::get(), 33 | }; 34 | 35 | prop.try_to_complete(2, 3); 36 | assert_eq!(prop.status, ProposalStatus::Approved); 37 | } 38 | 39 | #[test] 40 | fn complete_proposal_rejected() { 41 | let mut prop = ProposalVotes { 42 | votes_for: vec![1], 43 | votes_against: vec![2, 3], 44 | status: ProposalStatus::Initiated, 45 | expiry: ProposalLifetime::get(), 46 | }; 47 | 48 | prop.try_to_complete(2, 3); 49 | assert_eq!(prop.status, ProposalStatus::Rejected); 50 | } 51 | 52 | #[test] 53 | fn complete_proposal_bad_threshold() { 54 | let mut prop = ProposalVotes { 55 | votes_for: vec![1, 2], 56 | votes_against: vec![], 57 | status: ProposalStatus::Initiated, 58 | expiry: ProposalLifetime::get(), 59 | }; 60 | 61 | prop.try_to_complete(3, 2); 62 | assert_eq!(prop.status, ProposalStatus::Initiated); 63 | 64 | let mut prop = ProposalVotes { 65 | votes_for: vec![], 66 | votes_against: vec![1, 2], 67 | status: ProposalStatus::Initiated, 68 | expiry: ProposalLifetime::get(), 69 | }; 70 | 71 | prop.try_to_complete(3, 2); 72 | assert_eq!(prop.status, ProposalStatus::Initiated); 73 | } 74 | 75 | #[test] 76 | fn setup_resources() { 77 | new_test_ext().execute_with(|| { 78 | let id: ResourceId = [1; 32]; 79 | let method = "Pallet.do_something".as_bytes().to_vec(); 80 | let method2 = "Pallet.do_somethingElse".as_bytes().to_vec(); 81 | 82 | assert_ok!(Bridge::set_resource(Origin::root(), id, method.clone())); 83 | assert_eq!(Bridge::resources(id), Some(method)); 84 | 85 | assert_ok!(Bridge::set_resource(Origin::root(), id, method2.clone())); 86 | assert_eq!(Bridge::resources(id), Some(method2)); 87 | 88 | assert_ok!(Bridge::remove_resource(Origin::root(), id)); 89 | assert_eq!(Bridge::resources(id), None); 90 | }) 91 | } 92 | 93 | #[test] 94 | fn whitelist_chain() { 95 | new_test_ext().execute_with(|| { 96 | assert!(!Bridge::chain_whitelisted(0)); 97 | 98 | assert_ok!(Bridge::whitelist_chain(Origin::root(), 0)); 99 | assert_noop!( 100 | Bridge::whitelist_chain(Origin::root(), TestChainId::get()), 101 | Error::::InvalidChainId 102 | ); 103 | 104 | assert_events(vec![Event::bridge(RawEvent::ChainWhitelisted(0))]); 105 | }) 106 | } 107 | 108 | #[test] 109 | fn set_get_threshold() { 110 | new_test_ext().execute_with(|| { 111 | assert_eq!(::get(), 1); 112 | 113 | assert_ok!(Bridge::set_threshold(Origin::root(), TEST_THRESHOLD)); 114 | assert_eq!(::get(), TEST_THRESHOLD); 115 | 116 | assert_ok!(Bridge::set_threshold(Origin::root(), 5)); 117 | assert_eq!(::get(), 5); 118 | 119 | assert_events(vec![ 120 | Event::bridge(RawEvent::RelayerThresholdChanged(TEST_THRESHOLD)), 121 | Event::bridge(RawEvent::RelayerThresholdChanged(5)), 122 | ]); 123 | }) 124 | } 125 | 126 | #[test] 127 | fn asset_transfer_success() { 128 | new_test_ext().execute_with(|| { 129 | let dest_id = 2; 130 | let to = vec![2]; 131 | let resource_id = [1; 32]; 132 | let metadata = vec![]; 133 | let amount = 100; 134 | let token_id = vec![1, 2, 3, 4]; 135 | 136 | assert_ok!(Bridge::set_threshold(Origin::root(), TEST_THRESHOLD,)); 137 | 138 | assert_ok!(Bridge::whitelist_chain(Origin::root(), dest_id.clone())); 139 | assert_ok!(Bridge::transfer_fungible( 140 | dest_id.clone(), 141 | resource_id.clone(), 142 | to.clone(), 143 | amount.into() 144 | )); 145 | assert_events(vec![ 146 | Event::bridge(RawEvent::ChainWhitelisted(dest_id.clone())), 147 | Event::bridge(RawEvent::FungibleTransfer( 148 | dest_id.clone(), 149 | 1, 150 | resource_id.clone(), 151 | amount.into(), 152 | to.clone(), 153 | )), 154 | ]); 155 | 156 | assert_ok!(Bridge::transfer_nonfungible( 157 | dest_id.clone(), 158 | resource_id.clone(), 159 | token_id.clone(), 160 | to.clone(), 161 | metadata.clone() 162 | )); 163 | assert_events(vec![Event::bridge(RawEvent::NonFungibleTransfer( 164 | dest_id.clone(), 165 | 2, 166 | resource_id.clone(), 167 | token_id, 168 | to.clone(), 169 | metadata.clone(), 170 | ))]); 171 | 172 | assert_ok!(Bridge::transfer_generic( 173 | dest_id.clone(), 174 | resource_id.clone(), 175 | metadata.clone() 176 | )); 177 | assert_events(vec![Event::bridge(RawEvent::GenericTransfer( 178 | dest_id.clone(), 179 | 3, 180 | resource_id, 181 | metadata, 182 | ))]); 183 | }) 184 | } 185 | 186 | #[test] 187 | fn asset_transfer_invalid_chain() { 188 | new_test_ext().execute_with(|| { 189 | let chain_id = 2; 190 | let bad_dest_id = 3; 191 | let resource_id = [4; 32]; 192 | 193 | assert_ok!(Bridge::whitelist_chain(Origin::root(), chain_id.clone())); 194 | assert_events(vec![Event::bridge(RawEvent::ChainWhitelisted( 195 | chain_id.clone(), 196 | ))]); 197 | 198 | assert_noop!( 199 | Bridge::transfer_fungible(bad_dest_id, resource_id.clone(), vec![], U256::zero()), 200 | Error::::ChainNotWhitelisted 201 | ); 202 | 203 | assert_noop!( 204 | Bridge::transfer_nonfungible(bad_dest_id, resource_id.clone(), vec![], vec![], vec![]), 205 | Error::::ChainNotWhitelisted 206 | ); 207 | 208 | assert_noop!( 209 | Bridge::transfer_generic(bad_dest_id, resource_id.clone(), vec![]), 210 | Error::::ChainNotWhitelisted 211 | ); 212 | }) 213 | } 214 | 215 | #[test] 216 | fn add_remove_relayer() { 217 | new_test_ext().execute_with(|| { 218 | assert_ok!(Bridge::set_threshold(Origin::root(), TEST_THRESHOLD,)); 219 | assert_eq!(Bridge::relayer_count(), 0); 220 | 221 | assert_ok!(Bridge::add_relayer(Origin::root(), RELAYER_A)); 222 | assert_ok!(Bridge::add_relayer(Origin::root(), RELAYER_B)); 223 | assert_ok!(Bridge::add_relayer(Origin::root(), RELAYER_C)); 224 | assert_eq!(Bridge::relayer_count(), 3); 225 | 226 | // Already exists 227 | assert_noop!( 228 | Bridge::add_relayer(Origin::root(), RELAYER_A), 229 | Error::::RelayerAlreadyExists 230 | ); 231 | 232 | // Confirm removal 233 | assert_ok!(Bridge::remove_relayer(Origin::root(), RELAYER_B)); 234 | assert_eq!(Bridge::relayer_count(), 2); 235 | assert_noop!( 236 | Bridge::remove_relayer(Origin::root(), RELAYER_B), 237 | Error::::RelayerInvalid 238 | ); 239 | assert_eq!(Bridge::relayer_count(), 2); 240 | 241 | assert_events(vec![ 242 | Event::bridge(RawEvent::RelayerAdded(RELAYER_A)), 243 | Event::bridge(RawEvent::RelayerAdded(RELAYER_B)), 244 | Event::bridge(RawEvent::RelayerAdded(RELAYER_C)), 245 | Event::bridge(RawEvent::RelayerRemoved(RELAYER_B)), 246 | ]); 247 | }) 248 | } 249 | 250 | fn make_proposal(r: Vec) -> mock::Call { 251 | Call::System(system::Call::remark(r)) 252 | } 253 | 254 | #[test] 255 | fn create_sucessful_proposal() { 256 | let src_id = 1; 257 | let r_id = derive_resource_id(src_id, b"remark"); 258 | 259 | new_test_ext_initialized(src_id, r_id, b"System.remark".to_vec()).execute_with(|| { 260 | let prop_id = 1; 261 | let proposal = make_proposal(vec![10]); 262 | 263 | // Create proposal (& vote) 264 | assert_ok!(Bridge::acknowledge_proposal( 265 | Origin::signed(RELAYER_A), 266 | prop_id, 267 | src_id, 268 | r_id, 269 | Box::new(proposal.clone()) 270 | )); 271 | let prop = Bridge::votes(src_id, (prop_id.clone(), proposal.clone())).unwrap(); 272 | let expected = ProposalVotes { 273 | votes_for: vec![RELAYER_A], 274 | votes_against: vec![], 275 | status: ProposalStatus::Initiated, 276 | expiry: ProposalLifetime::get() + 1, 277 | }; 278 | assert_eq!(prop, expected); 279 | 280 | // Second relayer votes against 281 | assert_ok!(Bridge::reject_proposal( 282 | Origin::signed(RELAYER_B), 283 | prop_id, 284 | src_id, 285 | r_id, 286 | Box::new(proposal.clone()) 287 | )); 288 | let prop = Bridge::votes(src_id, (prop_id.clone(), proposal.clone())).unwrap(); 289 | let expected = ProposalVotes { 290 | votes_for: vec![RELAYER_A], 291 | votes_against: vec![RELAYER_B], 292 | status: ProposalStatus::Initiated, 293 | expiry: ProposalLifetime::get() + 1, 294 | }; 295 | assert_eq!(prop, expected); 296 | 297 | // Third relayer votes in favour 298 | assert_ok!(Bridge::acknowledge_proposal( 299 | Origin::signed(RELAYER_C), 300 | prop_id, 301 | src_id, 302 | r_id, 303 | Box::new(proposal.clone()) 304 | )); 305 | let prop = Bridge::votes(src_id, (prop_id.clone(), proposal.clone())).unwrap(); 306 | let expected = ProposalVotes { 307 | votes_for: vec![RELAYER_A, RELAYER_C], 308 | votes_against: vec![RELAYER_B], 309 | status: ProposalStatus::Approved, 310 | expiry: ProposalLifetime::get() + 1, 311 | }; 312 | assert_eq!(prop, expected); 313 | 314 | assert_events(vec![ 315 | Event::bridge(RawEvent::VoteFor(src_id, prop_id, RELAYER_A)), 316 | Event::bridge(RawEvent::VoteAgainst(src_id, prop_id, RELAYER_B)), 317 | Event::bridge(RawEvent::VoteFor(src_id, prop_id, RELAYER_C)), 318 | Event::bridge(RawEvent::ProposalApproved(src_id, prop_id)), 319 | Event::bridge(RawEvent::ProposalSucceeded(src_id, prop_id)), 320 | ]); 321 | }) 322 | } 323 | 324 | #[test] 325 | fn create_unsucessful_proposal() { 326 | let src_id = 1; 327 | let r_id = derive_resource_id(src_id, b"transfer"); 328 | 329 | new_test_ext_initialized(src_id, r_id, b"System.remark".to_vec()).execute_with(|| { 330 | let prop_id = 1; 331 | let proposal = make_proposal(vec![11]); 332 | 333 | // Create proposal (& vote) 334 | assert_ok!(Bridge::acknowledge_proposal( 335 | Origin::signed(RELAYER_A), 336 | prop_id, 337 | src_id, 338 | r_id, 339 | Box::new(proposal.clone()) 340 | )); 341 | let prop = Bridge::votes(src_id, (prop_id.clone(), proposal.clone())).unwrap(); 342 | let expected = ProposalVotes { 343 | votes_for: vec![RELAYER_A], 344 | votes_against: vec![], 345 | status: ProposalStatus::Initiated, 346 | expiry: ProposalLifetime::get() + 1, 347 | }; 348 | assert_eq!(prop, expected); 349 | 350 | // Second relayer votes against 351 | assert_ok!(Bridge::reject_proposal( 352 | Origin::signed(RELAYER_B), 353 | prop_id, 354 | src_id, 355 | r_id, 356 | Box::new(proposal.clone()) 357 | )); 358 | let prop = Bridge::votes(src_id, (prop_id.clone(), proposal.clone())).unwrap(); 359 | let expected = ProposalVotes { 360 | votes_for: vec![RELAYER_A], 361 | votes_against: vec![RELAYER_B], 362 | status: ProposalStatus::Initiated, 363 | expiry: ProposalLifetime::get() + 1, 364 | }; 365 | assert_eq!(prop, expected); 366 | 367 | // Third relayer votes against 368 | assert_ok!(Bridge::reject_proposal( 369 | Origin::signed(RELAYER_C), 370 | prop_id, 371 | src_id, 372 | r_id, 373 | Box::new(proposal.clone()) 374 | )); 375 | let prop = Bridge::votes(src_id, (prop_id.clone(), proposal.clone())).unwrap(); 376 | let expected = ProposalVotes { 377 | votes_for: vec![RELAYER_A], 378 | votes_against: vec![RELAYER_B, RELAYER_C], 379 | status: ProposalStatus::Rejected, 380 | expiry: ProposalLifetime::get() + 1, 381 | }; 382 | assert_eq!(prop, expected); 383 | 384 | assert_eq!(Balances::free_balance(RELAYER_B), 0); 385 | assert_eq!( 386 | Balances::free_balance(Bridge::account_id()), 387 | ENDOWED_BALANCE 388 | ); 389 | 390 | assert_events(vec![ 391 | Event::bridge(RawEvent::VoteFor(src_id, prop_id, RELAYER_A)), 392 | Event::bridge(RawEvent::VoteAgainst(src_id, prop_id, RELAYER_B)), 393 | Event::bridge(RawEvent::VoteAgainst(src_id, prop_id, RELAYER_C)), 394 | Event::bridge(RawEvent::ProposalRejected(src_id, prop_id)), 395 | ]); 396 | }) 397 | } 398 | 399 | #[test] 400 | fn execute_after_threshold_change() { 401 | let src_id = 1; 402 | let r_id = derive_resource_id(src_id, b"transfer"); 403 | 404 | new_test_ext_initialized(src_id, r_id, b"System.remark".to_vec()).execute_with(|| { 405 | let prop_id = 1; 406 | let proposal = make_proposal(vec![11]); 407 | 408 | // Create proposal (& vote) 409 | assert_ok!(Bridge::acknowledge_proposal( 410 | Origin::signed(RELAYER_A), 411 | prop_id, 412 | src_id, 413 | r_id, 414 | Box::new(proposal.clone()) 415 | )); 416 | let prop = Bridge::votes(src_id, (prop_id.clone(), proposal.clone())).unwrap(); 417 | let expected = ProposalVotes { 418 | votes_for: vec![RELAYER_A], 419 | votes_against: vec![], 420 | status: ProposalStatus::Initiated, 421 | expiry: ProposalLifetime::get() + 1, 422 | }; 423 | assert_eq!(prop, expected); 424 | 425 | // Change threshold 426 | assert_ok!(Bridge::set_threshold(Origin::root(), 1)); 427 | 428 | // Attempt to execute 429 | assert_ok!(Bridge::eval_vote_state( 430 | Origin::signed(RELAYER_A), 431 | prop_id, 432 | src_id, 433 | Box::new(proposal.clone()) 434 | )); 435 | 436 | let prop = Bridge::votes(src_id, (prop_id.clone(), proposal.clone())).unwrap(); 437 | let expected = ProposalVotes { 438 | votes_for: vec![RELAYER_A], 439 | votes_against: vec![], 440 | status: ProposalStatus::Approved, 441 | expiry: ProposalLifetime::get() + 1, 442 | }; 443 | assert_eq!(prop, expected); 444 | 445 | assert_eq!(Balances::free_balance(RELAYER_B), 0); 446 | assert_eq!( 447 | Balances::free_balance(Bridge::account_id()), 448 | ENDOWED_BALANCE 449 | ); 450 | 451 | assert_events(vec![ 452 | Event::bridge(RawEvent::VoteFor(src_id, prop_id, RELAYER_A)), 453 | Event::bridge(RawEvent::RelayerThresholdChanged(1)), 454 | Event::bridge(RawEvent::ProposalApproved(src_id, prop_id)), 455 | Event::bridge(RawEvent::ProposalSucceeded(src_id, prop_id)), 456 | ]); 457 | }) 458 | } 459 | 460 | #[test] 461 | fn proposal_expires() { 462 | let src_id = 1; 463 | let r_id = derive_resource_id(src_id, b"remark"); 464 | 465 | new_test_ext_initialized(src_id, r_id, b"System.remark".to_vec()).execute_with(|| { 466 | let prop_id = 1; 467 | let proposal = make_proposal(vec![10]); 468 | 469 | // Create proposal (& vote) 470 | assert_ok!(Bridge::acknowledge_proposal( 471 | Origin::signed(RELAYER_A), 472 | prop_id, 473 | src_id, 474 | r_id, 475 | Box::new(proposal.clone()) 476 | )); 477 | let prop = Bridge::votes(src_id, (prop_id.clone(), proposal.clone())).unwrap(); 478 | let expected = ProposalVotes { 479 | votes_for: vec![RELAYER_A], 480 | votes_against: vec![], 481 | status: ProposalStatus::Initiated, 482 | expiry: ProposalLifetime::get() + 1, 483 | }; 484 | assert_eq!(prop, expected); 485 | 486 | // Increment enough blocks such that now == expiry 487 | System::set_block_number(ProposalLifetime::get() + 1); 488 | 489 | // Attempt to submit a vote should fail 490 | assert_noop!( 491 | Bridge::reject_proposal( 492 | Origin::signed(RELAYER_B), 493 | prop_id, 494 | src_id, 495 | r_id, 496 | Box::new(proposal.clone()) 497 | ), 498 | Error::::ProposalExpired 499 | ); 500 | 501 | // Proposal state should remain unchanged 502 | let prop = Bridge::votes(src_id, (prop_id.clone(), proposal.clone())).unwrap(); 503 | let expected = ProposalVotes { 504 | votes_for: vec![RELAYER_A], 505 | votes_against: vec![], 506 | status: ProposalStatus::Initiated, 507 | expiry: ProposalLifetime::get() + 1, 508 | }; 509 | assert_eq!(prop, expected); 510 | 511 | // eval_vote_state should have no effect 512 | assert_noop!( 513 | Bridge::eval_vote_state( 514 | Origin::signed(RELAYER_C), 515 | prop_id, 516 | src_id, 517 | Box::new(proposal.clone()) 518 | ), 519 | Error::::ProposalExpired 520 | ); 521 | let prop = Bridge::votes(src_id, (prop_id.clone(), proposal.clone())).unwrap(); 522 | let expected = ProposalVotes { 523 | votes_for: vec![RELAYER_A], 524 | votes_against: vec![], 525 | status: ProposalStatus::Initiated, 526 | expiry: ProposalLifetime::get() + 1, 527 | }; 528 | assert_eq!(prop, expected); 529 | 530 | assert_events(vec![Event::bridge(RawEvent::VoteFor( 531 | src_id, prop_id, RELAYER_A, 532 | ))]); 533 | }) 534 | } 535 | -------------------------------------------------------------------------------- /chainbridge/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Ensure we're `no_std` when compiling for Wasm. 2 | #![cfg_attr(not(feature = "std"), no_std)] 3 | 4 | use frame_support::{ 5 | decl_error, decl_event, decl_module, decl_storage, 6 | dispatch::DispatchResult, 7 | ensure, 8 | traits::{EnsureOrigin, Get}, 9 | weights::{GetDispatchInfo, Pays}, 10 | Parameter, 11 | }; 12 | 13 | use frame_system::{self as system, ensure_root, ensure_signed}; 14 | use sp_core::U256; 15 | use sp_runtime::traits::{AccountIdConversion, Dispatchable}; 16 | use sp_runtime::{ModuleId, RuntimeDebug}; 17 | use sp_std::prelude::*; 18 | 19 | use codec::{Decode, Encode, EncodeLike}; 20 | 21 | mod mock; 22 | mod tests; 23 | 24 | const DEFAULT_RELAYER_THRESHOLD: u32 = 1; 25 | const MODULE_ID: ModuleId = ModuleId(*b"cb/bridg"); 26 | 27 | pub type ChainId = u8; 28 | pub type DepositNonce = u64; 29 | pub type ResourceId = [u8; 32]; 30 | 31 | /// Helper function to concatenate a chain ID and some bytes to produce a resource ID. 32 | /// The common format is (31 bytes unique ID + 1 byte chain ID). 33 | pub fn derive_resource_id(chain: u8, id: &[u8]) -> ResourceId { 34 | let mut r_id: ResourceId = [0; 32]; 35 | r_id[31] = chain; // last byte is chain id 36 | let range = if id.len() > 31 { 31 } else { id.len() }; // Use at most 31 bytes 37 | for i in 0..range { 38 | r_id[30 - i] = id[range - 1 - i]; // Ensure left padding for eth compatibility 39 | } 40 | return r_id; 41 | } 42 | 43 | #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] 44 | pub enum ProposalStatus { 45 | Initiated, 46 | Approved, 47 | Rejected, 48 | } 49 | 50 | #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] 51 | pub struct ProposalVotes { 52 | pub votes_for: Vec, 53 | pub votes_against: Vec, 54 | pub status: ProposalStatus, 55 | pub expiry: BlockNumber, 56 | } 57 | 58 | impl ProposalVotes { 59 | /// Attempts to mark the proposal as approve or rejected. 60 | /// Returns true if the status changes from active. 61 | fn try_to_complete(&mut self, threshold: u32, total: u32) -> ProposalStatus { 62 | if self.votes_for.len() >= threshold as usize { 63 | self.status = ProposalStatus::Approved; 64 | ProposalStatus::Approved 65 | } else if total >= threshold && self.votes_against.len() as u32 + threshold > total { 66 | self.status = ProposalStatus::Rejected; 67 | ProposalStatus::Rejected 68 | } else { 69 | ProposalStatus::Initiated 70 | } 71 | } 72 | 73 | /// Returns true if the proposal has been rejected or approved, otherwise false. 74 | fn is_complete(&self) -> bool { 75 | self.status != ProposalStatus::Initiated 76 | } 77 | 78 | /// Returns true if `who` has voted for or against the proposal 79 | fn has_voted(&self, who: &A) -> bool { 80 | self.votes_for.contains(&who) || self.votes_against.contains(&who) 81 | } 82 | 83 | /// Return true if the expiry time has been reached 84 | fn is_expired(&self, now: B) -> bool { 85 | self.expiry <= now 86 | } 87 | } 88 | 89 | impl Default for ProposalVotes { 90 | fn default() -> Self { 91 | Self { 92 | votes_for: vec![], 93 | votes_against: vec![], 94 | status: ProposalStatus::Initiated, 95 | expiry: BlockNumber::default(), 96 | } 97 | } 98 | } 99 | 100 | pub trait Config: system::Config { 101 | type Event: From> + Into<::Event>; 102 | /// Origin used to administer the pallet 103 | type AdminOrigin: EnsureOrigin; 104 | /// Proposed dispatchable call 105 | type Proposal: Parameter + Dispatchable + EncodeLike + GetDispatchInfo; 106 | /// The identifier for this chain. 107 | /// This must be unique and must not collide with existing IDs within a set of bridged chains. 108 | type ChainId: Get; 109 | 110 | type ProposalLifetime: Get; 111 | } 112 | 113 | decl_event! { 114 | pub enum Event where ::AccountId { 115 | /// Vote threshold has changed (new_threshold) 116 | RelayerThresholdChanged(u32), 117 | /// Chain now available for transfers (chain_id) 118 | ChainWhitelisted(ChainId), 119 | /// Relayer added to set 120 | RelayerAdded(AccountId), 121 | /// Relayer removed from set 122 | RelayerRemoved(AccountId), 123 | /// FunglibleTransfer is for relaying fungibles (dest_id, nonce, resource_id, amount, recipient, metadata) 124 | FungibleTransfer(ChainId, DepositNonce, ResourceId, U256, Vec), 125 | /// NonFungibleTransfer is for relaying NFTS (dest_id, nonce, resource_id, token_id, recipient, metadata) 126 | NonFungibleTransfer(ChainId, DepositNonce, ResourceId, Vec, Vec, Vec), 127 | /// GenericTransfer is for a generic data payload (dest_id, nonce, resource_id, metadata) 128 | GenericTransfer(ChainId, DepositNonce, ResourceId, Vec), 129 | /// Vote submitted in favour of proposal 130 | VoteFor(ChainId, DepositNonce, AccountId), 131 | /// Vot submitted against proposal 132 | VoteAgainst(ChainId, DepositNonce, AccountId), 133 | /// Voting successful for a proposal 134 | ProposalApproved(ChainId, DepositNonce), 135 | /// Voting rejected a proposal 136 | ProposalRejected(ChainId, DepositNonce), 137 | /// Execution of call succeeded 138 | ProposalSucceeded(ChainId, DepositNonce), 139 | /// Execution of call failed 140 | ProposalFailed(ChainId, DepositNonce), 141 | } 142 | } 143 | 144 | decl_error! { 145 | pub enum Error for Module { 146 | /// Relayer threshold not set 147 | ThresholdNotSet, 148 | /// Provided chain Id is not valid 149 | InvalidChainId, 150 | /// Relayer threshold cannot be 0 151 | InvalidThreshold, 152 | /// Interactions with this chain is not permitted 153 | ChainNotWhitelisted, 154 | /// Chain has already been enabled 155 | ChainAlreadyWhitelisted, 156 | /// Resource ID provided isn't mapped to anything 157 | ResourceDoesNotExist, 158 | /// Relayer already in set 159 | RelayerAlreadyExists, 160 | /// Provided accountId is not a relayer 161 | RelayerInvalid, 162 | /// Protected operation, must be performed by relayer 163 | MustBeRelayer, 164 | /// Relayer has already submitted some vote for this proposal 165 | RelayerAlreadyVoted, 166 | /// A proposal with these parameters has already been submitted 167 | ProposalAlreadyExists, 168 | /// No proposal with the ID was found 169 | ProposalDoesNotExist, 170 | /// Cannot complete proposal, needs more votes 171 | ProposalNotComplete, 172 | /// Proposal has either failed or succeeded 173 | ProposalAlreadyComplete, 174 | /// Lifetime of proposal has been exceeded 175 | ProposalExpired, 176 | } 177 | } 178 | 179 | decl_storage! { 180 | trait Store for Module as ChainBridge { 181 | /// All whitelisted chains and their respective transaction counts 182 | ChainNonces get(fn chains): map hasher(opaque_blake2_256) ChainId => Option; 183 | 184 | /// Number of votes required for a proposal to execute 185 | RelayerThreshold get(fn relayer_threshold): u32 = DEFAULT_RELAYER_THRESHOLD; 186 | 187 | /// Tracks current relayer set 188 | pub Relayers get(fn relayers): map hasher(opaque_blake2_256) T::AccountId => bool; 189 | 190 | /// Number of relayers in set 191 | pub RelayerCount get(fn relayer_count): u32; 192 | 193 | /// All known proposals. 194 | /// The key is the hash of the call and the deposit ID, to ensure it's unique. 195 | pub Votes get(fn votes): 196 | double_map hasher(opaque_blake2_256) ChainId, hasher(opaque_blake2_256) (DepositNonce, T::Proposal) 197 | => Option>; 198 | 199 | /// Utilized by the bridge software to map resource IDs to actual methods 200 | pub Resources get(fn resources): 201 | map hasher(opaque_blake2_256) ResourceId => Option> 202 | } 203 | } 204 | 205 | decl_module! { 206 | pub struct Module for enum Call where origin: T::Origin { 207 | type Error = Error; 208 | 209 | const ChainIdentity: ChainId = T::ChainId::get(); 210 | const ProposalLifetime: T::BlockNumber = T::ProposalLifetime::get(); 211 | const BridgeAccountId: T::AccountId = MODULE_ID.into_account(); 212 | 213 | fn deposit_event() = default; 214 | 215 | /// Sets the vote threshold for proposals. 216 | /// 217 | /// This threshold is used to determine how many votes are required 218 | /// before a proposal is executed. 219 | /// 220 | /// # 221 | /// - O(1) lookup and insert 222 | /// # 223 | #[weight = 195_000_000] 224 | pub fn set_threshold(origin, threshold: u32) -> DispatchResult { 225 | Self::ensure_admin(origin)?; 226 | Self::set_relayer_threshold(threshold) 227 | } 228 | 229 | /// Stores a method name on chain under an associated resource ID. 230 | /// 231 | /// # 232 | /// - O(1) write 233 | /// # 234 | #[weight = 195_000_000] 235 | pub fn set_resource(origin, id: ResourceId, method: Vec) -> DispatchResult { 236 | Self::ensure_admin(origin)?; 237 | Self::register_resource(id, method) 238 | } 239 | 240 | /// Removes a resource ID from the resource mapping. 241 | /// 242 | /// After this call, bridge transfers with the associated resource ID will 243 | /// be rejected. 244 | /// 245 | /// # 246 | /// - O(1) removal 247 | /// # 248 | #[weight = 195_000_000] 249 | pub fn remove_resource(origin, id: ResourceId) -> DispatchResult { 250 | Self::ensure_admin(origin)?; 251 | Self::unregister_resource(id) 252 | } 253 | 254 | /// Enables a chain ID as a source or destination for a bridge transfer. 255 | /// 256 | /// # 257 | /// - O(1) lookup and insert 258 | /// # 259 | #[weight = 195_000_000] 260 | pub fn whitelist_chain(origin, id: ChainId) -> DispatchResult { 261 | Self::ensure_admin(origin)?; 262 | Self::whitelist(id) 263 | } 264 | 265 | /// Adds a new relayer to the relayer set. 266 | /// 267 | /// # 268 | /// - O(1) lookup and insert 269 | /// # 270 | #[weight = 195_000_000] 271 | pub fn add_relayer(origin, v: T::AccountId) -> DispatchResult { 272 | Self::ensure_admin(origin)?; 273 | Self::register_relayer(v) 274 | } 275 | 276 | /// Removes an existing relayer from the set. 277 | /// 278 | /// # 279 | /// - O(1) lookup and removal 280 | /// # 281 | #[weight = 195_000_000] 282 | pub fn remove_relayer(origin, v: T::AccountId) -> DispatchResult { 283 | Self::ensure_admin(origin)?; 284 | Self::unregister_relayer(v) 285 | } 286 | 287 | /// Commits a vote in favour of the provided proposal. 288 | /// 289 | /// If a proposal with the given nonce and source chain ID does not already exist, it will 290 | /// be created with an initial vote in favour from the caller. 291 | /// 292 | /// # 293 | /// - weight of proposed call, regardless of whether execution is performed 294 | /// # 295 | #[weight = (call.get_dispatch_info().weight + 195_000_000, call.get_dispatch_info().class, Pays::Yes)] 296 | pub fn acknowledge_proposal(origin, nonce: DepositNonce, src_id: ChainId, r_id: ResourceId, call: Box<::Proposal>) -> DispatchResult { 297 | let who = ensure_signed(origin)?; 298 | ensure!(Self::is_relayer(&who), Error::::MustBeRelayer); 299 | ensure!(Self::chain_whitelisted(src_id), Error::::ChainNotWhitelisted); 300 | ensure!(Self::resource_exists(r_id), Error::::ResourceDoesNotExist); 301 | 302 | Self::vote_for(who, nonce, src_id, call) 303 | } 304 | 305 | /// Commits a vote against a provided proposal. 306 | /// 307 | /// # 308 | /// - Fixed, since execution of proposal should not be included 309 | /// # 310 | #[weight = 195_000_000] 311 | pub fn reject_proposal(origin, nonce: DepositNonce, src_id: ChainId, r_id: ResourceId, call: Box<::Proposal>) -> DispatchResult { 312 | let who = ensure_signed(origin)?; 313 | ensure!(Self::is_relayer(&who), Error::::MustBeRelayer); 314 | ensure!(Self::chain_whitelisted(src_id), Error::::ChainNotWhitelisted); 315 | ensure!(Self::resource_exists(r_id), Error::::ResourceDoesNotExist); 316 | 317 | Self::vote_against(who, nonce, src_id, call) 318 | } 319 | 320 | /// Evaluate the state of a proposal given the current vote threshold. 321 | /// 322 | /// A proposal with enough votes will be either executed or cancelled, and the status 323 | /// will be updated accordingly. 324 | /// 325 | /// # 326 | /// - weight of proposed call, regardless of whether execution is performed 327 | /// # 328 | #[weight = (prop.get_dispatch_info().weight + 195_000_000, prop.get_dispatch_info().class, Pays::Yes)] 329 | pub fn eval_vote_state(origin, nonce: DepositNonce, src_id: ChainId, prop: Box<::Proposal>) -> DispatchResult { 330 | ensure_signed(origin)?; 331 | 332 | Self::try_resolve_proposal(nonce, src_id, prop) 333 | } 334 | } 335 | } 336 | 337 | impl Module { 338 | // *** Utility methods *** 339 | 340 | pub fn ensure_admin(o: T::Origin) -> DispatchResult { 341 | T::AdminOrigin::try_origin(o) 342 | .map(|_| ()) 343 | .or_else(ensure_root)?; 344 | Ok(()) 345 | } 346 | 347 | /// Checks if who is a relayer 348 | pub fn is_relayer(who: &T::AccountId) -> bool { 349 | Self::relayers(who) 350 | } 351 | 352 | /// Provides an AccountId for the pallet. 353 | /// This is used both as an origin check and deposit/withdrawal account. 354 | pub fn account_id() -> T::AccountId { 355 | MODULE_ID.into_account() 356 | } 357 | 358 | /// Asserts if a resource is registered 359 | pub fn resource_exists(id: ResourceId) -> bool { 360 | return Self::resources(id) != None; 361 | } 362 | 363 | /// Checks if a chain exists as a whitelisted destination 364 | pub fn chain_whitelisted(id: ChainId) -> bool { 365 | return Self::chains(id) != None; 366 | } 367 | 368 | /// Increments the deposit nonce for the specified chain ID 369 | fn bump_nonce(id: ChainId) -> DepositNonce { 370 | let nonce = Self::chains(id).unwrap_or_default() + 1; 371 | ::insert(id, nonce); 372 | nonce 373 | } 374 | 375 | // *** Admin methods *** 376 | 377 | /// Set a new voting threshold 378 | pub fn set_relayer_threshold(threshold: u32) -> DispatchResult { 379 | ensure!(threshold > 0, Error::::InvalidThreshold); 380 | ::put(threshold); 381 | Self::deposit_event(RawEvent::RelayerThresholdChanged(threshold)); 382 | Ok(()) 383 | } 384 | 385 | /// Register a method for a resource Id, enabling associated transfers 386 | pub fn register_resource(id: ResourceId, method: Vec) -> DispatchResult { 387 | ::insert(id, method); 388 | Ok(()) 389 | } 390 | 391 | /// Removes a resource ID, disabling associated transfer 392 | pub fn unregister_resource(id: ResourceId) -> DispatchResult { 393 | ::remove(id); 394 | Ok(()) 395 | } 396 | 397 | /// Whitelist a chain ID for transfer 398 | pub fn whitelist(id: ChainId) -> DispatchResult { 399 | // Cannot whitelist this chain 400 | ensure!(id != T::ChainId::get(), Error::::InvalidChainId); 401 | // Cannot whitelist with an existing entry 402 | ensure!( 403 | !Self::chain_whitelisted(id), 404 | Error::::ChainAlreadyWhitelisted 405 | ); 406 | ::insert(&id, 0); 407 | Self::deposit_event(RawEvent::ChainWhitelisted(id)); 408 | Ok(()) 409 | } 410 | 411 | /// Adds a new relayer to the set 412 | pub fn register_relayer(relayer: T::AccountId) -> DispatchResult { 413 | ensure!( 414 | !Self::is_relayer(&relayer), 415 | Error::::RelayerAlreadyExists 416 | ); 417 | >::insert(&relayer, true); 418 | ::mutate(|i| *i += 1); 419 | 420 | Self::deposit_event(RawEvent::RelayerAdded(relayer)); 421 | Ok(()) 422 | } 423 | 424 | /// Removes a relayer from the set 425 | pub fn unregister_relayer(relayer: T::AccountId) -> DispatchResult { 426 | ensure!(Self::is_relayer(&relayer), Error::::RelayerInvalid); 427 | >::remove(&relayer); 428 | ::mutate(|i| *i -= 1); 429 | Self::deposit_event(RawEvent::RelayerRemoved(relayer)); 430 | Ok(()) 431 | } 432 | 433 | // *** Proposal voting and execution methods *** 434 | 435 | /// Commits a vote for a proposal. If the proposal doesn't exist it will be created. 436 | fn commit_vote( 437 | who: T::AccountId, 438 | nonce: DepositNonce, 439 | src_id: ChainId, 440 | prop: Box, 441 | in_favour: bool, 442 | ) -> DispatchResult { 443 | let now = >::block_number(); 444 | let mut votes = match >::get(src_id, (nonce, prop.clone())) { 445 | Some(v) => v, 446 | None => { 447 | let mut v = ProposalVotes::default(); 448 | v.expiry = now + T::ProposalLifetime::get(); 449 | v 450 | } 451 | }; 452 | 453 | // Ensure the proposal isn't complete and relayer hasn't already voted 454 | ensure!(!votes.is_complete(), Error::::ProposalAlreadyComplete); 455 | ensure!(!votes.is_expired(now), Error::::ProposalExpired); 456 | ensure!(!votes.has_voted(&who), Error::::RelayerAlreadyVoted); 457 | 458 | if in_favour { 459 | votes.votes_for.push(who.clone()); 460 | Self::deposit_event(RawEvent::VoteFor(src_id, nonce, who.clone())); 461 | } else { 462 | votes.votes_against.push(who.clone()); 463 | Self::deposit_event(RawEvent::VoteAgainst(src_id, nonce, who.clone())); 464 | } 465 | 466 | >::insert(src_id, (nonce, prop.clone()), votes.clone()); 467 | 468 | Ok(()) 469 | } 470 | 471 | /// Attempts to finalize or cancel the proposal if the vote count allows. 472 | fn try_resolve_proposal( 473 | nonce: DepositNonce, 474 | src_id: ChainId, 475 | prop: Box, 476 | ) -> DispatchResult { 477 | if let Some(mut votes) = >::get(src_id, (nonce, prop.clone())) { 478 | let now = >::block_number(); 479 | ensure!(!votes.is_complete(), Error::::ProposalAlreadyComplete); 480 | ensure!(!votes.is_expired(now), Error::::ProposalExpired); 481 | 482 | let status = votes.try_to_complete(::get(), ::get()); 483 | >::insert(src_id, (nonce, prop.clone()), votes.clone()); 484 | 485 | match status { 486 | ProposalStatus::Approved => Self::finalize_execution(src_id, nonce, prop), 487 | ProposalStatus::Rejected => Self::cancel_execution(src_id, nonce), 488 | _ => Ok(()), 489 | } 490 | } else { 491 | Err(Error::::ProposalDoesNotExist)? 492 | } 493 | } 494 | 495 | /// Commits a vote in favour of the proposal and executes it if the vote threshold is met. 496 | fn vote_for( 497 | who: T::AccountId, 498 | nonce: DepositNonce, 499 | src_id: ChainId, 500 | prop: Box, 501 | ) -> DispatchResult { 502 | Self::commit_vote(who, nonce, src_id, prop.clone(), true)?; 503 | Self::try_resolve_proposal(nonce, src_id, prop) 504 | } 505 | 506 | /// Commits a vote against the proposal and cancels it if more than (relayers.len() - threshold) 507 | /// votes against exist. 508 | fn vote_against( 509 | who: T::AccountId, 510 | nonce: DepositNonce, 511 | src_id: ChainId, 512 | prop: Box, 513 | ) -> DispatchResult { 514 | Self::commit_vote(who, nonce, src_id, prop.clone(), false)?; 515 | Self::try_resolve_proposal(nonce, src_id, prop) 516 | } 517 | 518 | /// Execute the proposal and signals the result as an event 519 | fn finalize_execution( 520 | src_id: ChainId, 521 | nonce: DepositNonce, 522 | call: Box, 523 | ) -> DispatchResult { 524 | Self::deposit_event(RawEvent::ProposalApproved(src_id, nonce)); 525 | call.dispatch(frame_system::RawOrigin::Signed(Self::account_id()).into()) 526 | .map(|_| ()) 527 | .map_err(|e| e.error)?; 528 | Self::deposit_event(RawEvent::ProposalSucceeded(src_id, nonce)); 529 | Ok(()) 530 | } 531 | 532 | /// Cancels a proposal. 533 | fn cancel_execution(src_id: ChainId, nonce: DepositNonce) -> DispatchResult { 534 | Self::deposit_event(RawEvent::ProposalRejected(src_id, nonce)); 535 | Ok(()) 536 | } 537 | 538 | /// Initiates a transfer of a fungible asset out of the chain. This should be called by another pallet. 539 | pub fn transfer_fungible( 540 | dest_id: ChainId, 541 | resource_id: ResourceId, 542 | to: Vec, 543 | amount: U256, 544 | ) -> DispatchResult { 545 | ensure!( 546 | Self::chain_whitelisted(dest_id), 547 | Error::::ChainNotWhitelisted 548 | ); 549 | let nonce = Self::bump_nonce(dest_id); 550 | Self::deposit_event(RawEvent::FungibleTransfer( 551 | dest_id, 552 | nonce, 553 | resource_id, 554 | amount, 555 | to, 556 | )); 557 | Ok(()) 558 | } 559 | 560 | /// Initiates a transfer of a nonfungible asset out of the chain. This should be called by another pallet. 561 | pub fn transfer_nonfungible( 562 | dest_id: ChainId, 563 | resource_id: ResourceId, 564 | token_id: Vec, 565 | to: Vec, 566 | metadata: Vec, 567 | ) -> DispatchResult { 568 | ensure!( 569 | Self::chain_whitelisted(dest_id), 570 | Error::::ChainNotWhitelisted 571 | ); 572 | let nonce = Self::bump_nonce(dest_id); 573 | Self::deposit_event(RawEvent::NonFungibleTransfer( 574 | dest_id, 575 | nonce, 576 | resource_id, 577 | token_id, 578 | to, 579 | metadata, 580 | )); 581 | Ok(()) 582 | } 583 | 584 | /// Initiates a transfer of generic data out of the chain. This should be called by another pallet. 585 | pub fn transfer_generic( 586 | dest_id: ChainId, 587 | resource_id: ResourceId, 588 | metadata: Vec, 589 | ) -> DispatchResult { 590 | ensure!( 591 | Self::chain_whitelisted(dest_id), 592 | Error::::ChainNotWhitelisted 593 | ); 594 | let nonce = Self::bump_nonce(dest_id); 595 | Self::deposit_event(RawEvent::GenericTransfer( 596 | dest_id, 597 | nonce, 598 | resource_id, 599 | metadata, 600 | )); 601 | Ok(()) 602 | } 603 | } 604 | 605 | /// Simple ensure origin for the bridge account 606 | pub struct EnsureBridge(sp_std::marker::PhantomData); 607 | impl EnsureOrigin for EnsureBridge { 608 | type Success = T::AccountId; 609 | fn try_origin(o: T::Origin) -> Result { 610 | let bridge_id = MODULE_ID.into_account(); 611 | o.into().and_then(|o| match o { 612 | system::RawOrigin::Signed(who) if who == bridge_id => Ok(bridge_id), 613 | r => Err(T::Origin::from(r)), 614 | }) 615 | } 616 | 617 | /// Returns an outer origin capable of passing `try_origin` check. 618 | /// 619 | /// ** Should be used for benchmarking only!!! ** 620 | #[cfg(feature = "runtime-benchmarks")] 621 | fn successful_origin() -> T::Origin { 622 | T::Origin::from( 623 | frame_system::RawOrigin::Signed(>::account_id()) 624 | ) 625 | } 626 | 627 | } 628 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "Inflector" 7 | version = "0.11.4" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" 10 | dependencies = [ 11 | "lazy_static", 12 | "regex", 13 | ] 14 | 15 | [[package]] 16 | name = "addr2line" 17 | version = "0.13.0" 18 | source = "registry+https://github.com/rust-lang/crates.io-index" 19 | checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072" 20 | dependencies = [ 21 | "gimli", 22 | ] 23 | 24 | [[package]] 25 | name = "adler" 26 | version = "0.2.3" 27 | source = "registry+https://github.com/rust-lang/crates.io-index" 28 | checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" 29 | 30 | [[package]] 31 | name = "ahash" 32 | version = "0.4.7" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" 35 | 36 | [[package]] 37 | name = "aho-corasick" 38 | version = "0.7.14" 39 | source = "registry+https://github.com/rust-lang/crates.io-index" 40 | checksum = "b476ce7103678b0c6d3d395dbbae31d48ff910bd28be979ba5d48c6351131d0d" 41 | dependencies = [ 42 | "memchr", 43 | ] 44 | 45 | [[package]] 46 | name = "ansi_term" 47 | version = "0.12.1" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 50 | dependencies = [ 51 | "winapi", 52 | ] 53 | 54 | [[package]] 55 | name = "anyhow" 56 | version = "1.0.38" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" 59 | 60 | [[package]] 61 | name = "approx" 62 | version = "0.3.2" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | checksum = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3" 65 | dependencies = [ 66 | "num-traits", 67 | ] 68 | 69 | [[package]] 70 | name = "arrayref" 71 | version = "0.3.6" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" 74 | 75 | [[package]] 76 | name = "arrayvec" 77 | version = "0.4.12" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" 80 | dependencies = [ 81 | "nodrop", 82 | ] 83 | 84 | [[package]] 85 | name = "arrayvec" 86 | version = "0.5.1" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" 89 | 90 | [[package]] 91 | name = "async-trait" 92 | version = "0.1.42" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "8d3a45e77e34375a7923b1e8febb049bb011f064714a8e17a1a616fef01da13d" 95 | dependencies = [ 96 | "proc-macro2", 97 | "quote", 98 | "syn", 99 | ] 100 | 101 | [[package]] 102 | name = "autocfg" 103 | version = "1.0.1" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 106 | 107 | [[package]] 108 | name = "backtrace" 109 | version = "0.3.53" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "707b586e0e2f247cbde68cdd2c3ce69ea7b7be43e1c5b426e37c9319c4b9838e" 112 | dependencies = [ 113 | "addr2line", 114 | "cfg-if 1.0.0", 115 | "libc", 116 | "miniz_oxide", 117 | "object", 118 | "rustc-demangle", 119 | ] 120 | 121 | [[package]] 122 | name = "base58" 123 | version = "0.1.0" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" 126 | 127 | [[package]] 128 | name = "bitflags" 129 | version = "1.2.1" 130 | source = "registry+https://github.com/rust-lang/crates.io-index" 131 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 132 | 133 | [[package]] 134 | name = "bitvec" 135 | version = "0.20.1" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "f5011ffc90248764d7005b0e10c7294f5aa1bd87d9dd7248f4ad475b347c294d" 138 | dependencies = [ 139 | "funty", 140 | "radium", 141 | "tap", 142 | "wyz", 143 | ] 144 | 145 | [[package]] 146 | name = "blake2-rfc" 147 | version = "0.2.18" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" 150 | dependencies = [ 151 | "arrayvec 0.4.12", 152 | "constant_time_eq", 153 | ] 154 | 155 | [[package]] 156 | name = "block-buffer" 157 | version = "0.7.3" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" 160 | dependencies = [ 161 | "block-padding", 162 | "byte-tools", 163 | "byteorder", 164 | "generic-array 0.12.3", 165 | ] 166 | 167 | [[package]] 168 | name = "block-buffer" 169 | version = "0.9.0" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 172 | dependencies = [ 173 | "generic-array 0.14.4", 174 | ] 175 | 176 | [[package]] 177 | name = "block-padding" 178 | version = "0.1.5" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" 181 | dependencies = [ 182 | "byte-tools", 183 | ] 184 | 185 | [[package]] 186 | name = "byte-slice-cast" 187 | version = "1.0.0" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "65c1bf4a04a88c54f589125563643d773f3254b5c38571395e2b591c693bbc81" 190 | 191 | [[package]] 192 | name = "byte-tools" 193 | version = "0.3.1" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" 196 | 197 | [[package]] 198 | name = "byteorder" 199 | version = "1.3.4" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" 202 | 203 | [[package]] 204 | name = "cfg-if" 205 | version = "0.1.10" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 208 | 209 | [[package]] 210 | name = "cfg-if" 211 | version = "1.0.0" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 214 | 215 | [[package]] 216 | name = "chainbridge" 217 | version = "0.0.2" 218 | dependencies = [ 219 | "frame-support", 220 | "frame-system", 221 | "pallet-balances", 222 | "parity-scale-codec", 223 | "serde", 224 | "sp-core", 225 | "sp-io", 226 | "sp-runtime", 227 | "sp-std", 228 | "substrate-wasm-builder-runner", 229 | ] 230 | 231 | [[package]] 232 | name = "chrono" 233 | version = "0.4.19" 234 | source = "registry+https://github.com/rust-lang/crates.io-index" 235 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 236 | dependencies = [ 237 | "libc", 238 | "num-integer", 239 | "num-traits", 240 | "winapi", 241 | ] 242 | 243 | [[package]] 244 | name = "cloudabi" 245 | version = "0.1.0" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" 248 | dependencies = [ 249 | "bitflags", 250 | ] 251 | 252 | [[package]] 253 | name = "constant_time_eq" 254 | version = "0.1.5" 255 | source = "registry+https://github.com/rust-lang/crates.io-index" 256 | checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" 257 | 258 | [[package]] 259 | name = "cpuid-bool" 260 | version = "0.1.2" 261 | source = "registry+https://github.com/rust-lang/crates.io-index" 262 | checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" 263 | 264 | [[package]] 265 | name = "crunchy" 266 | version = "0.2.2" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" 269 | 270 | [[package]] 271 | name = "crypto-mac" 272 | version = "0.7.0" 273 | source = "registry+https://github.com/rust-lang/crates.io-index" 274 | checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" 275 | dependencies = [ 276 | "generic-array 0.12.3", 277 | "subtle 1.0.0", 278 | ] 279 | 280 | [[package]] 281 | name = "crypto-mac" 282 | version = "0.8.0" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" 285 | dependencies = [ 286 | "generic-array 0.14.4", 287 | "subtle 2.3.0", 288 | ] 289 | 290 | [[package]] 291 | name = "curve25519-dalek" 292 | version = "2.1.0" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | checksum = "5d85653f070353a16313d0046f173f70d1aadd5b42600a14de626f0dfb3473a5" 295 | dependencies = [ 296 | "byteorder", 297 | "digest 0.8.1", 298 | "rand_core 0.5.1", 299 | "subtle 2.3.0", 300 | "zeroize", 301 | ] 302 | 303 | [[package]] 304 | name = "curve25519-dalek" 305 | version = "3.0.0" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | checksum = "c8492de420e9e60bc9a1d66e2dbb91825390b738a388606600663fc529b4b307" 308 | dependencies = [ 309 | "byteorder", 310 | "digest 0.9.0", 311 | "rand_core 0.5.1", 312 | "subtle 2.3.0", 313 | "zeroize", 314 | ] 315 | 316 | [[package]] 317 | name = "derive_more" 318 | version = "0.99.11" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "41cb0e6161ad61ed084a36ba71fbba9e3ac5aee3606fb607fe08da6acbcf3d8c" 321 | dependencies = [ 322 | "proc-macro2", 323 | "quote", 324 | "syn", 325 | ] 326 | 327 | [[package]] 328 | name = "digest" 329 | version = "0.8.1" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" 332 | dependencies = [ 333 | "generic-array 0.12.3", 334 | ] 335 | 336 | [[package]] 337 | name = "digest" 338 | version = "0.9.0" 339 | source = "registry+https://github.com/rust-lang/crates.io-index" 340 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 341 | dependencies = [ 342 | "generic-array 0.14.4", 343 | ] 344 | 345 | [[package]] 346 | name = "dyn-clonable" 347 | version = "0.9.0" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | checksum = "4e9232f0e607a262ceb9bd5141a3dfb3e4db6994b31989bbfd845878cba59fd4" 350 | dependencies = [ 351 | "dyn-clonable-impl", 352 | "dyn-clone", 353 | ] 354 | 355 | [[package]] 356 | name = "dyn-clonable-impl" 357 | version = "0.9.0" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" 360 | dependencies = [ 361 | "proc-macro2", 362 | "quote", 363 | "syn", 364 | ] 365 | 366 | [[package]] 367 | name = "dyn-clone" 368 | version = "1.0.2" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "4c53dc3a653e0f64081026e4bf048d48fec9fce90c66e8326ca7292df0ff2d82" 371 | 372 | [[package]] 373 | name = "ed25519" 374 | version = "1.0.3" 375 | source = "registry+https://github.com/rust-lang/crates.io-index" 376 | checksum = "37c66a534cbb46ab4ea03477eae19d5c22c01da8258030280b7bd9d8433fb6ef" 377 | dependencies = [ 378 | "signature", 379 | ] 380 | 381 | [[package]] 382 | name = "ed25519-dalek" 383 | version = "1.0.1" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" 386 | dependencies = [ 387 | "curve25519-dalek 3.0.0", 388 | "ed25519", 389 | "rand 0.7.3", 390 | "serde", 391 | "sha2 0.9.3", 392 | "zeroize", 393 | ] 394 | 395 | [[package]] 396 | name = "either" 397 | version = "1.6.1" 398 | source = "registry+https://github.com/rust-lang/crates.io-index" 399 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 400 | 401 | [[package]] 402 | name = "environmental" 403 | version = "1.1.2" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | checksum = "6576a1755ddffd988788025e75bce9e74b018f7cc226198fe931d077911c6d7e" 406 | 407 | [[package]] 408 | name = "example-erc721" 409 | version = "0.0.1" 410 | dependencies = [ 411 | "chainbridge", 412 | "frame-support", 413 | "frame-system", 414 | "pallet-balances", 415 | "parity-scale-codec", 416 | "serde", 417 | "sp-core", 418 | "sp-io", 419 | "sp-runtime", 420 | "sp-std", 421 | "substrate-wasm-builder-runner", 422 | ] 423 | 424 | [[package]] 425 | name = "example-pallet" 426 | version = "0.0.1" 427 | dependencies = [ 428 | "chainbridge", 429 | "example-erc721", 430 | "frame-support", 431 | "frame-system", 432 | "pallet-balances", 433 | "parity-scale-codec", 434 | "serde", 435 | "sp-arithmetic", 436 | "sp-core", 437 | "sp-io", 438 | "sp-runtime", 439 | "sp-std", 440 | "substrate-wasm-builder-runner", 441 | ] 442 | 443 | [[package]] 444 | name = "fake-simd" 445 | version = "0.1.2" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" 448 | 449 | [[package]] 450 | name = "fixed-hash" 451 | version = "0.7.0" 452 | source = "registry+https://github.com/rust-lang/crates.io-index" 453 | checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" 454 | dependencies = [ 455 | "byteorder", 456 | "rand 0.8.3", 457 | "rustc-hex", 458 | "static_assertions", 459 | ] 460 | 461 | [[package]] 462 | name = "frame-benchmarking" 463 | version = "3.1.0" 464 | source = "registry+https://github.com/rust-lang/crates.io-index" 465 | checksum = "70fe99487f84579a3f2c4ba52650fec875492eea41be0e4eea8019187f105052" 466 | dependencies = [ 467 | "frame-support", 468 | "frame-system", 469 | "linregress", 470 | "parity-scale-codec", 471 | "paste 1.0.4", 472 | "sp-api", 473 | "sp-io", 474 | "sp-runtime", 475 | "sp-runtime-interface", 476 | "sp-std", 477 | "sp-storage", 478 | ] 479 | 480 | [[package]] 481 | name = "frame-metadata" 482 | version = "13.0.0" 483 | source = "registry+https://github.com/rust-lang/crates.io-index" 484 | checksum = "073f7bef18421362441a1708f8528e442234954611f95bdc554b313fb321948e" 485 | dependencies = [ 486 | "parity-scale-codec", 487 | "serde", 488 | "sp-core", 489 | "sp-std", 490 | ] 491 | 492 | [[package]] 493 | name = "frame-support" 494 | version = "3.0.0" 495 | source = "registry+https://github.com/rust-lang/crates.io-index" 496 | checksum = "04e521e6214615bd82ba6b5fc7fd40a9cc14fdeb40f83da5eba12aa2f8179fb8" 497 | dependencies = [ 498 | "bitflags", 499 | "frame-metadata", 500 | "frame-support-procedural", 501 | "impl-trait-for-tuples", 502 | "log", 503 | "once_cell", 504 | "parity-scale-codec", 505 | "paste 1.0.4", 506 | "serde", 507 | "smallvec", 508 | "sp-arithmetic", 509 | "sp-core", 510 | "sp-inherents", 511 | "sp-io", 512 | "sp-runtime", 513 | "sp-staking", 514 | "sp-state-machine", 515 | "sp-std", 516 | "sp-tracing", 517 | ] 518 | 519 | [[package]] 520 | name = "frame-support-procedural" 521 | version = "3.0.0" 522 | source = "registry+https://github.com/rust-lang/crates.io-index" 523 | checksum = "2668e24cbaba7f0e91d0c92a94bd1ae425a942608ad0b775db32477f5df4da9e" 524 | dependencies = [ 525 | "Inflector", 526 | "frame-support-procedural-tools", 527 | "proc-macro2", 528 | "quote", 529 | "syn", 530 | ] 531 | 532 | [[package]] 533 | name = "frame-support-procedural-tools" 534 | version = "3.0.0" 535 | source = "registry+https://github.com/rust-lang/crates.io-index" 536 | checksum = "d4f88cfd111e004590f4542b75e6d3302137b9067d7e7219e4ac47a535c3b5c1" 537 | dependencies = [ 538 | "frame-support-procedural-tools-derive", 539 | "proc-macro-crate", 540 | "proc-macro2", 541 | "quote", 542 | "syn", 543 | ] 544 | 545 | [[package]] 546 | name = "frame-support-procedural-tools-derive" 547 | version = "3.0.0" 548 | source = "registry+https://github.com/rust-lang/crates.io-index" 549 | checksum = "79285388b120ac96c15a791c56b26b9264f7231324fbe0fd05026acd92bf2e6a" 550 | dependencies = [ 551 | "proc-macro2", 552 | "quote", 553 | "syn", 554 | ] 555 | 556 | [[package]] 557 | name = "frame-system" 558 | version = "3.0.0" 559 | source = "registry+https://github.com/rust-lang/crates.io-index" 560 | checksum = "f5fedbff05d665c00bf4e089b4377fcb15b8bd37ebc3e5fc06665474cf6e25d7" 561 | dependencies = [ 562 | "frame-support", 563 | "impl-trait-for-tuples", 564 | "parity-scale-codec", 565 | "serde", 566 | "sp-core", 567 | "sp-io", 568 | "sp-runtime", 569 | "sp-std", 570 | "sp-version", 571 | ] 572 | 573 | [[package]] 574 | name = "funty" 575 | version = "1.1.0" 576 | source = "registry+https://github.com/rust-lang/crates.io-index" 577 | checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" 578 | 579 | [[package]] 580 | name = "futures" 581 | version = "0.3.6" 582 | source = "registry+https://github.com/rust-lang/crates.io-index" 583 | checksum = "5d8e3078b7b2a8a671cb7a3d17b4760e4181ea243227776ba83fd043b4ca034e" 584 | dependencies = [ 585 | "futures-channel", 586 | "futures-core", 587 | "futures-executor", 588 | "futures-io", 589 | "futures-sink", 590 | "futures-task", 591 | "futures-util", 592 | ] 593 | 594 | [[package]] 595 | name = "futures-channel" 596 | version = "0.3.6" 597 | source = "registry+https://github.com/rust-lang/crates.io-index" 598 | checksum = "a7a4d35f7401e948629c9c3d6638fb9bf94e0b2121e96c3b428cc4e631f3eb74" 599 | dependencies = [ 600 | "futures-core", 601 | "futures-sink", 602 | ] 603 | 604 | [[package]] 605 | name = "futures-core" 606 | version = "0.3.6" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "d674eaa0056896d5ada519900dbf97ead2e46a7b6621e8160d79e2f2e1e2784b" 609 | 610 | [[package]] 611 | name = "futures-executor" 612 | version = "0.3.6" 613 | source = "registry+https://github.com/rust-lang/crates.io-index" 614 | checksum = "cc709ca1da6f66143b8c9bec8e6260181869893714e9b5a490b169b0414144ab" 615 | dependencies = [ 616 | "futures-core", 617 | "futures-task", 618 | "futures-util", 619 | "num_cpus", 620 | ] 621 | 622 | [[package]] 623 | name = "futures-io" 624 | version = "0.3.6" 625 | source = "registry+https://github.com/rust-lang/crates.io-index" 626 | checksum = "5fc94b64bb39543b4e432f1790b6bf18e3ee3b74653c5449f63310e9a74b123c" 627 | 628 | [[package]] 629 | name = "futures-macro" 630 | version = "0.3.6" 631 | source = "registry+https://github.com/rust-lang/crates.io-index" 632 | checksum = "f57ed14da4603b2554682e9f2ff3c65d7567b53188db96cb71538217fc64581b" 633 | dependencies = [ 634 | "proc-macro-hack", 635 | "proc-macro2", 636 | "quote", 637 | "syn", 638 | ] 639 | 640 | [[package]] 641 | name = "futures-sink" 642 | version = "0.3.6" 643 | source = "registry+https://github.com/rust-lang/crates.io-index" 644 | checksum = "0d8764258ed64ebc5d9ed185cf86a95db5cac810269c5d20ececb32e0088abbd" 645 | 646 | [[package]] 647 | name = "futures-task" 648 | version = "0.3.6" 649 | source = "registry+https://github.com/rust-lang/crates.io-index" 650 | checksum = "4dd26820a9f3637f1302da8bceba3ff33adbe53464b54ca24d4e2d4f1db30f94" 651 | dependencies = [ 652 | "once_cell", 653 | ] 654 | 655 | [[package]] 656 | name = "futures-util" 657 | version = "0.3.6" 658 | source = "registry+https://github.com/rust-lang/crates.io-index" 659 | checksum = "8a894a0acddba51a2d49a6f4263b1e64b8c579ece8af50fa86503d52cd1eea34" 660 | dependencies = [ 661 | "futures-channel", 662 | "futures-core", 663 | "futures-io", 664 | "futures-macro", 665 | "futures-sink", 666 | "futures-task", 667 | "memchr", 668 | "pin-project", 669 | "pin-utils", 670 | "proc-macro-hack", 671 | "proc-macro-nested", 672 | "slab", 673 | ] 674 | 675 | [[package]] 676 | name = "generic-array" 677 | version = "0.12.3" 678 | source = "registry+https://github.com/rust-lang/crates.io-index" 679 | checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" 680 | dependencies = [ 681 | "typenum", 682 | ] 683 | 684 | [[package]] 685 | name = "generic-array" 686 | version = "0.13.2" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "0ed1e761351b56f54eb9dcd0cfaca9fd0daecf93918e1cfc01c8a3d26ee7adcd" 689 | dependencies = [ 690 | "typenum", 691 | ] 692 | 693 | [[package]] 694 | name = "generic-array" 695 | version = "0.14.4" 696 | source = "registry+https://github.com/rust-lang/crates.io-index" 697 | checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" 698 | dependencies = [ 699 | "typenum", 700 | "version_check", 701 | ] 702 | 703 | [[package]] 704 | name = "getrandom" 705 | version = "0.1.15" 706 | source = "registry+https://github.com/rust-lang/crates.io-index" 707 | checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" 708 | dependencies = [ 709 | "cfg-if 0.1.10", 710 | "libc", 711 | "wasi 0.9.0+wasi-snapshot-preview1", 712 | ] 713 | 714 | [[package]] 715 | name = "getrandom" 716 | version = "0.2.2" 717 | source = "registry+https://github.com/rust-lang/crates.io-index" 718 | checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" 719 | dependencies = [ 720 | "cfg-if 1.0.0", 721 | "libc", 722 | "wasi 0.10.0+wasi-snapshot-preview1", 723 | ] 724 | 725 | [[package]] 726 | name = "gimli" 727 | version = "0.22.0" 728 | source = "registry+https://github.com/rust-lang/crates.io-index" 729 | checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724" 730 | 731 | [[package]] 732 | name = "hash-db" 733 | version = "0.15.2" 734 | source = "registry+https://github.com/rust-lang/crates.io-index" 735 | checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" 736 | 737 | [[package]] 738 | name = "hash256-std-hasher" 739 | version = "0.15.2" 740 | source = "registry+https://github.com/rust-lang/crates.io-index" 741 | checksum = "92c171d55b98633f4ed3860808f004099b36c1cc29c42cfc53aa8591b21efcf2" 742 | dependencies = [ 743 | "crunchy", 744 | ] 745 | 746 | [[package]] 747 | name = "hashbrown" 748 | version = "0.9.1" 749 | source = "registry+https://github.com/rust-lang/crates.io-index" 750 | checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" 751 | dependencies = [ 752 | "ahash", 753 | ] 754 | 755 | [[package]] 756 | name = "hermit-abi" 757 | version = "0.1.17" 758 | source = "registry+https://github.com/rust-lang/crates.io-index" 759 | checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" 760 | dependencies = [ 761 | "libc", 762 | ] 763 | 764 | [[package]] 765 | name = "hex" 766 | version = "0.4.2" 767 | source = "registry+https://github.com/rust-lang/crates.io-index" 768 | checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" 769 | 770 | [[package]] 771 | name = "hmac" 772 | version = "0.7.1" 773 | source = "registry+https://github.com/rust-lang/crates.io-index" 774 | checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" 775 | dependencies = [ 776 | "crypto-mac 0.7.0", 777 | "digest 0.8.1", 778 | ] 779 | 780 | [[package]] 781 | name = "hmac" 782 | version = "0.8.1" 783 | source = "registry+https://github.com/rust-lang/crates.io-index" 784 | checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" 785 | dependencies = [ 786 | "crypto-mac 0.8.0", 787 | "digest 0.9.0", 788 | ] 789 | 790 | [[package]] 791 | name = "hmac-drbg" 792 | version = "0.2.0" 793 | source = "registry+https://github.com/rust-lang/crates.io-index" 794 | checksum = "c6e570451493f10f6581b48cdd530413b63ea9e780f544bfd3bdcaa0d89d1a7b" 795 | dependencies = [ 796 | "digest 0.8.1", 797 | "generic-array 0.12.3", 798 | "hmac 0.7.1", 799 | ] 800 | 801 | [[package]] 802 | name = "impl-codec" 803 | version = "0.5.0" 804 | source = "registry+https://github.com/rust-lang/crates.io-index" 805 | checksum = "df170efa359aebdd5cb7fe78edcc67107748e4737bdca8a8fb40d15ea7a877ed" 806 | dependencies = [ 807 | "parity-scale-codec", 808 | ] 809 | 810 | [[package]] 811 | name = "impl-serde" 812 | version = "0.3.1" 813 | source = "registry+https://github.com/rust-lang/crates.io-index" 814 | checksum = "b47ca4d2b6931707a55fce5cf66aff80e2178c8b63bbb4ecb5695cbc870ddf6f" 815 | dependencies = [ 816 | "serde", 817 | ] 818 | 819 | [[package]] 820 | name = "impl-trait-for-tuples" 821 | version = "0.2.1" 822 | source = "registry+https://github.com/rust-lang/crates.io-index" 823 | checksum = "d5dacb10c5b3bb92d46ba347505a9041e676bb20ad220101326bffb0c93031ee" 824 | dependencies = [ 825 | "proc-macro2", 826 | "quote", 827 | "syn", 828 | ] 829 | 830 | [[package]] 831 | name = "instant" 832 | version = "0.1.7" 833 | source = "registry+https://github.com/rust-lang/crates.io-index" 834 | checksum = "63312a18f7ea8760cdd0a7c5aac1a619752a246b833545e3e36d1f81f7cd9e66" 835 | dependencies = [ 836 | "cfg-if 0.1.10", 837 | ] 838 | 839 | [[package]] 840 | name = "integer-sqrt" 841 | version = "0.1.5" 842 | source = "registry+https://github.com/rust-lang/crates.io-index" 843 | checksum = "276ec31bcb4a9ee45f58bec6f9ec700ae4cf4f4f8f2fa7e06cb406bd5ffdd770" 844 | dependencies = [ 845 | "num-traits", 846 | ] 847 | 848 | [[package]] 849 | name = "itoa" 850 | version = "0.4.6" 851 | source = "registry+https://github.com/rust-lang/crates.io-index" 852 | checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" 853 | 854 | [[package]] 855 | name = "keccak" 856 | version = "0.1.0" 857 | source = "registry+https://github.com/rust-lang/crates.io-index" 858 | checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" 859 | 860 | [[package]] 861 | name = "lazy_static" 862 | version = "1.4.0" 863 | source = "registry+https://github.com/rust-lang/crates.io-index" 864 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 865 | 866 | [[package]] 867 | name = "libc" 868 | version = "0.2.79" 869 | source = "registry+https://github.com/rust-lang/crates.io-index" 870 | checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" 871 | 872 | [[package]] 873 | name = "libm" 874 | version = "0.2.1" 875 | source = "registry+https://github.com/rust-lang/crates.io-index" 876 | checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" 877 | 878 | [[package]] 879 | name = "libsecp256k1" 880 | version = "0.3.5" 881 | source = "registry+https://github.com/rust-lang/crates.io-index" 882 | checksum = "1fc1e2c808481a63dc6da2074752fdd4336a3c8fcc68b83db6f1fd5224ae7962" 883 | dependencies = [ 884 | "arrayref", 885 | "crunchy", 886 | "digest 0.8.1", 887 | "hmac-drbg", 888 | "rand 0.7.3", 889 | "sha2 0.8.2", 890 | "subtle 2.3.0", 891 | "typenum", 892 | ] 893 | 894 | [[package]] 895 | name = "linregress" 896 | version = "0.4.0" 897 | source = "registry+https://github.com/rust-lang/crates.io-index" 898 | checksum = "0d0ad4b5cc8385a881c561fac3501353d63d2a2b7a357b5064d71815c9a92724" 899 | dependencies = [ 900 | "nalgebra", 901 | "statrs", 902 | ] 903 | 904 | [[package]] 905 | name = "lock_api" 906 | version = "0.4.1" 907 | source = "registry+https://github.com/rust-lang/crates.io-index" 908 | checksum = "28247cc5a5be2f05fbcd76dd0cf2c7d3b5400cb978a28042abcd4fa0b3f8261c" 909 | dependencies = [ 910 | "scopeguard", 911 | ] 912 | 913 | [[package]] 914 | name = "log" 915 | version = "0.4.11" 916 | source = "registry+https://github.com/rust-lang/crates.io-index" 917 | checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" 918 | dependencies = [ 919 | "cfg-if 0.1.10", 920 | ] 921 | 922 | [[package]] 923 | name = "matchers" 924 | version = "0.0.1" 925 | source = "registry+https://github.com/rust-lang/crates.io-index" 926 | checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" 927 | dependencies = [ 928 | "regex-automata", 929 | ] 930 | 931 | [[package]] 932 | name = "matrixmultiply" 933 | version = "0.2.3" 934 | source = "registry+https://github.com/rust-lang/crates.io-index" 935 | checksum = "d4f7ec66360130972f34830bfad9ef05c6610a43938a467bcc9ab9369ab3478f" 936 | dependencies = [ 937 | "rawpointer", 938 | ] 939 | 940 | [[package]] 941 | name = "memchr" 942 | version = "2.3.3" 943 | source = "registry+https://github.com/rust-lang/crates.io-index" 944 | checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" 945 | 946 | [[package]] 947 | name = "memory-db" 948 | version = "0.26.0" 949 | source = "registry+https://github.com/rust-lang/crates.io-index" 950 | checksum = "814bbecfc0451fc314eeea34f05bbcd5b98a7ad7af37faee088b86a1e633f1d4" 951 | dependencies = [ 952 | "hash-db", 953 | "hashbrown", 954 | "parity-util-mem", 955 | ] 956 | 957 | [[package]] 958 | name = "memory_units" 959 | version = "0.3.0" 960 | source = "registry+https://github.com/rust-lang/crates.io-index" 961 | checksum = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" 962 | 963 | [[package]] 964 | name = "merlin" 965 | version = "2.0.0" 966 | source = "registry+https://github.com/rust-lang/crates.io-index" 967 | checksum = "c6feca46f4fa3443a01769d768727f10c10a20fdb65e52dc16a81f0c8269bb78" 968 | dependencies = [ 969 | "byteorder", 970 | "keccak", 971 | "rand_core 0.5.1", 972 | "zeroize", 973 | ] 974 | 975 | [[package]] 976 | name = "miniz_oxide" 977 | version = "0.4.3" 978 | source = "registry+https://github.com/rust-lang/crates.io-index" 979 | checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" 980 | dependencies = [ 981 | "adler", 982 | "autocfg", 983 | ] 984 | 985 | [[package]] 986 | name = "nalgebra" 987 | version = "0.21.1" 988 | source = "registry+https://github.com/rust-lang/crates.io-index" 989 | checksum = "d6b6147c3d50b4f3cdabfe2ecc94a0191fd3d6ad58aefd9664cf396285883486" 990 | dependencies = [ 991 | "approx", 992 | "generic-array 0.13.2", 993 | "matrixmultiply", 994 | "num-complex", 995 | "num-rational", 996 | "num-traits", 997 | "rand 0.7.3", 998 | "rand_distr", 999 | "simba", 1000 | "typenum", 1001 | ] 1002 | 1003 | [[package]] 1004 | name = "nodrop" 1005 | version = "0.1.14" 1006 | source = "registry+https://github.com/rust-lang/crates.io-index" 1007 | checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" 1008 | 1009 | [[package]] 1010 | name = "num-bigint" 1011 | version = "0.2.6" 1012 | source = "registry+https://github.com/rust-lang/crates.io-index" 1013 | checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" 1014 | dependencies = [ 1015 | "autocfg", 1016 | "num-integer", 1017 | "num-traits", 1018 | ] 1019 | 1020 | [[package]] 1021 | name = "num-complex" 1022 | version = "0.2.4" 1023 | source = "registry+https://github.com/rust-lang/crates.io-index" 1024 | checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" 1025 | dependencies = [ 1026 | "autocfg", 1027 | "num-traits", 1028 | ] 1029 | 1030 | [[package]] 1031 | name = "num-integer" 1032 | version = "0.1.43" 1033 | source = "registry+https://github.com/rust-lang/crates.io-index" 1034 | checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" 1035 | dependencies = [ 1036 | "autocfg", 1037 | "num-traits", 1038 | ] 1039 | 1040 | [[package]] 1041 | name = "num-rational" 1042 | version = "0.2.4" 1043 | source = "registry+https://github.com/rust-lang/crates.io-index" 1044 | checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" 1045 | dependencies = [ 1046 | "autocfg", 1047 | "num-bigint", 1048 | "num-integer", 1049 | "num-traits", 1050 | ] 1051 | 1052 | [[package]] 1053 | name = "num-traits" 1054 | version = "0.2.12" 1055 | source = "registry+https://github.com/rust-lang/crates.io-index" 1056 | checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" 1057 | dependencies = [ 1058 | "autocfg", 1059 | "libm", 1060 | ] 1061 | 1062 | [[package]] 1063 | name = "num_cpus" 1064 | version = "1.13.0" 1065 | source = "registry+https://github.com/rust-lang/crates.io-index" 1066 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 1067 | dependencies = [ 1068 | "hermit-abi", 1069 | "libc", 1070 | ] 1071 | 1072 | [[package]] 1073 | name = "object" 1074 | version = "0.21.1" 1075 | source = "registry+https://github.com/rust-lang/crates.io-index" 1076 | checksum = "37fd5004feb2ce328a52b0b3d01dbf4ffff72583493900ed15f22d4111c51693" 1077 | 1078 | [[package]] 1079 | name = "once_cell" 1080 | version = "1.4.1" 1081 | source = "registry+https://github.com/rust-lang/crates.io-index" 1082 | checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad" 1083 | dependencies = [ 1084 | "parking_lot", 1085 | ] 1086 | 1087 | [[package]] 1088 | name = "opaque-debug" 1089 | version = "0.2.3" 1090 | source = "registry+https://github.com/rust-lang/crates.io-index" 1091 | checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" 1092 | 1093 | [[package]] 1094 | name = "opaque-debug" 1095 | version = "0.3.0" 1096 | source = "registry+https://github.com/rust-lang/crates.io-index" 1097 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 1098 | 1099 | [[package]] 1100 | name = "pallet-balances" 1101 | version = "3.0.0" 1102 | source = "registry+https://github.com/rust-lang/crates.io-index" 1103 | checksum = "41aaeaf084e594273f82bcbf96416ef1fcab602e15dd1df04b9930eceb2eb518" 1104 | dependencies = [ 1105 | "frame-benchmarking", 1106 | "frame-support", 1107 | "frame-system", 1108 | "parity-scale-codec", 1109 | "serde", 1110 | "sp-runtime", 1111 | "sp-std", 1112 | ] 1113 | 1114 | [[package]] 1115 | name = "parity-scale-codec" 1116 | version = "2.0.0" 1117 | source = "registry+https://github.com/rust-lang/crates.io-index" 1118 | checksum = "75c823fdae1bb5ff5708ee61a62697e6296175dc671710876871c853f48592b3" 1119 | dependencies = [ 1120 | "arrayvec 0.5.1", 1121 | "bitvec", 1122 | "byte-slice-cast", 1123 | "parity-scale-codec-derive", 1124 | "serde", 1125 | ] 1126 | 1127 | [[package]] 1128 | name = "parity-scale-codec-derive" 1129 | version = "2.0.0" 1130 | source = "registry+https://github.com/rust-lang/crates.io-index" 1131 | checksum = "9029e65297c7fd6d7013f0579e193ec2b34ae78eabca854c9417504ad8a2d214" 1132 | dependencies = [ 1133 | "proc-macro-crate", 1134 | "proc-macro2", 1135 | "quote", 1136 | "syn", 1137 | ] 1138 | 1139 | [[package]] 1140 | name = "parity-util-mem" 1141 | version = "0.9.0" 1142 | source = "registry+https://github.com/rust-lang/crates.io-index" 1143 | checksum = "664a8c6b8e62d8f9f2f937e391982eb433ab285b4cd9545b342441e04a906e42" 1144 | dependencies = [ 1145 | "cfg-if 1.0.0", 1146 | "hashbrown", 1147 | "impl-trait-for-tuples", 1148 | "parity-util-mem-derive", 1149 | "parking_lot", 1150 | "primitive-types", 1151 | "winapi", 1152 | ] 1153 | 1154 | [[package]] 1155 | name = "parity-util-mem-derive" 1156 | version = "0.1.0" 1157 | source = "registry+https://github.com/rust-lang/crates.io-index" 1158 | checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2" 1159 | dependencies = [ 1160 | "proc-macro2", 1161 | "syn", 1162 | "synstructure", 1163 | ] 1164 | 1165 | [[package]] 1166 | name = "parity-wasm" 1167 | version = "0.41.0" 1168 | source = "registry+https://github.com/rust-lang/crates.io-index" 1169 | checksum = "ddfc878dac00da22f8f61e7af3157988424567ab01d9920b962ef7dcbd7cd865" 1170 | 1171 | [[package]] 1172 | name = "parking_lot" 1173 | version = "0.11.1" 1174 | source = "registry+https://github.com/rust-lang/crates.io-index" 1175 | checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" 1176 | dependencies = [ 1177 | "instant", 1178 | "lock_api", 1179 | "parking_lot_core", 1180 | ] 1181 | 1182 | [[package]] 1183 | name = "parking_lot_core" 1184 | version = "0.8.0" 1185 | source = "registry+https://github.com/rust-lang/crates.io-index" 1186 | checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b" 1187 | dependencies = [ 1188 | "cfg-if 0.1.10", 1189 | "cloudabi", 1190 | "instant", 1191 | "libc", 1192 | "redox_syscall", 1193 | "smallvec", 1194 | "winapi", 1195 | ] 1196 | 1197 | [[package]] 1198 | name = "paste" 1199 | version = "0.1.18" 1200 | source = "registry+https://github.com/rust-lang/crates.io-index" 1201 | checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880" 1202 | dependencies = [ 1203 | "paste-impl", 1204 | "proc-macro-hack", 1205 | ] 1206 | 1207 | [[package]] 1208 | name = "paste" 1209 | version = "1.0.4" 1210 | source = "registry+https://github.com/rust-lang/crates.io-index" 1211 | checksum = "c5d65c4d95931acda4498f675e332fcbdc9a06705cd07086c510e9b6009cd1c1" 1212 | 1213 | [[package]] 1214 | name = "paste-impl" 1215 | version = "0.1.18" 1216 | source = "registry+https://github.com/rust-lang/crates.io-index" 1217 | checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6" 1218 | dependencies = [ 1219 | "proc-macro-hack", 1220 | ] 1221 | 1222 | [[package]] 1223 | name = "pbkdf2" 1224 | version = "0.3.0" 1225 | source = "registry+https://github.com/rust-lang/crates.io-index" 1226 | checksum = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" 1227 | dependencies = [ 1228 | "byteorder", 1229 | "crypto-mac 0.7.0", 1230 | ] 1231 | 1232 | [[package]] 1233 | name = "pbkdf2" 1234 | version = "0.4.0" 1235 | source = "registry+https://github.com/rust-lang/crates.io-index" 1236 | checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" 1237 | dependencies = [ 1238 | "crypto-mac 0.8.0", 1239 | ] 1240 | 1241 | [[package]] 1242 | name = "pin-project" 1243 | version = "0.4.27" 1244 | source = "registry+https://github.com/rust-lang/crates.io-index" 1245 | checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15" 1246 | dependencies = [ 1247 | "pin-project-internal", 1248 | ] 1249 | 1250 | [[package]] 1251 | name = "pin-project-internal" 1252 | version = "0.4.27" 1253 | source = "registry+https://github.com/rust-lang/crates.io-index" 1254 | checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895" 1255 | dependencies = [ 1256 | "proc-macro2", 1257 | "quote", 1258 | "syn", 1259 | ] 1260 | 1261 | [[package]] 1262 | name = "pin-project-lite" 1263 | version = "0.2.4" 1264 | source = "registry+https://github.com/rust-lang/crates.io-index" 1265 | checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" 1266 | 1267 | [[package]] 1268 | name = "pin-utils" 1269 | version = "0.1.0" 1270 | source = "registry+https://github.com/rust-lang/crates.io-index" 1271 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1272 | 1273 | [[package]] 1274 | name = "ppv-lite86" 1275 | version = "0.2.9" 1276 | source = "registry+https://github.com/rust-lang/crates.io-index" 1277 | checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" 1278 | 1279 | [[package]] 1280 | name = "primitive-types" 1281 | version = "0.9.0" 1282 | source = "registry+https://github.com/rust-lang/crates.io-index" 1283 | checksum = "2415937401cb030a2a0a4d922483f945fa068f52a7dbb22ce0fe5f2b6f6adace" 1284 | dependencies = [ 1285 | "fixed-hash", 1286 | "impl-codec", 1287 | "impl-serde", 1288 | "uint", 1289 | ] 1290 | 1291 | [[package]] 1292 | name = "proc-macro-crate" 1293 | version = "0.1.5" 1294 | source = "registry+https://github.com/rust-lang/crates.io-index" 1295 | checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" 1296 | dependencies = [ 1297 | "toml", 1298 | ] 1299 | 1300 | [[package]] 1301 | name = "proc-macro-hack" 1302 | version = "0.5.18" 1303 | source = "registry+https://github.com/rust-lang/crates.io-index" 1304 | checksum = "99c605b9a0adc77b7211c6b1f722dcb613d68d66859a44f3d485a6da332b0598" 1305 | 1306 | [[package]] 1307 | name = "proc-macro-nested" 1308 | version = "0.1.6" 1309 | source = "registry+https://github.com/rust-lang/crates.io-index" 1310 | checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" 1311 | 1312 | [[package]] 1313 | name = "proc-macro2" 1314 | version = "1.0.24" 1315 | source = "registry+https://github.com/rust-lang/crates.io-index" 1316 | checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" 1317 | dependencies = [ 1318 | "unicode-xid", 1319 | ] 1320 | 1321 | [[package]] 1322 | name = "quote" 1323 | version = "1.0.7" 1324 | source = "registry+https://github.com/rust-lang/crates.io-index" 1325 | checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" 1326 | dependencies = [ 1327 | "proc-macro2", 1328 | ] 1329 | 1330 | [[package]] 1331 | name = "radium" 1332 | version = "0.6.2" 1333 | source = "registry+https://github.com/rust-lang/crates.io-index" 1334 | checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" 1335 | 1336 | [[package]] 1337 | name = "rand" 1338 | version = "0.7.3" 1339 | source = "registry+https://github.com/rust-lang/crates.io-index" 1340 | checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" 1341 | dependencies = [ 1342 | "getrandom 0.1.15", 1343 | "libc", 1344 | "rand_chacha 0.2.2", 1345 | "rand_core 0.5.1", 1346 | "rand_hc", 1347 | "rand_pcg", 1348 | ] 1349 | 1350 | [[package]] 1351 | name = "rand" 1352 | version = "0.8.3" 1353 | source = "registry+https://github.com/rust-lang/crates.io-index" 1354 | checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" 1355 | dependencies = [ 1356 | "libc", 1357 | "rand_chacha 0.3.0", 1358 | "rand_core 0.6.2", 1359 | ] 1360 | 1361 | [[package]] 1362 | name = "rand_chacha" 1363 | version = "0.2.2" 1364 | source = "registry+https://github.com/rust-lang/crates.io-index" 1365 | checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" 1366 | dependencies = [ 1367 | "ppv-lite86", 1368 | "rand_core 0.5.1", 1369 | ] 1370 | 1371 | [[package]] 1372 | name = "rand_chacha" 1373 | version = "0.3.0" 1374 | source = "registry+https://github.com/rust-lang/crates.io-index" 1375 | checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" 1376 | dependencies = [ 1377 | "ppv-lite86", 1378 | "rand_core 0.6.2", 1379 | ] 1380 | 1381 | [[package]] 1382 | name = "rand_core" 1383 | version = "0.5.1" 1384 | source = "registry+https://github.com/rust-lang/crates.io-index" 1385 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 1386 | dependencies = [ 1387 | "getrandom 0.1.15", 1388 | ] 1389 | 1390 | [[package]] 1391 | name = "rand_core" 1392 | version = "0.6.2" 1393 | source = "registry+https://github.com/rust-lang/crates.io-index" 1394 | checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" 1395 | dependencies = [ 1396 | "getrandom 0.2.2", 1397 | ] 1398 | 1399 | [[package]] 1400 | name = "rand_distr" 1401 | version = "0.2.2" 1402 | source = "registry+https://github.com/rust-lang/crates.io-index" 1403 | checksum = "96977acbdd3a6576fb1d27391900035bf3863d4a16422973a409b488cf29ffb2" 1404 | dependencies = [ 1405 | "rand 0.7.3", 1406 | ] 1407 | 1408 | [[package]] 1409 | name = "rand_hc" 1410 | version = "0.2.0" 1411 | source = "registry+https://github.com/rust-lang/crates.io-index" 1412 | checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 1413 | dependencies = [ 1414 | "rand_core 0.5.1", 1415 | ] 1416 | 1417 | [[package]] 1418 | name = "rand_pcg" 1419 | version = "0.2.1" 1420 | source = "registry+https://github.com/rust-lang/crates.io-index" 1421 | checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" 1422 | dependencies = [ 1423 | "rand_core 0.5.1", 1424 | ] 1425 | 1426 | [[package]] 1427 | name = "rawpointer" 1428 | version = "0.2.1" 1429 | source = "registry+https://github.com/rust-lang/crates.io-index" 1430 | checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" 1431 | 1432 | [[package]] 1433 | name = "redox_syscall" 1434 | version = "0.1.57" 1435 | source = "registry+https://github.com/rust-lang/crates.io-index" 1436 | checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" 1437 | 1438 | [[package]] 1439 | name = "ref-cast" 1440 | version = "1.0.2" 1441 | source = "registry+https://github.com/rust-lang/crates.io-index" 1442 | checksum = "745c1787167ddae5569661d5ffb8b25ae5fedbf46717eaa92d652221cec72623" 1443 | dependencies = [ 1444 | "ref-cast-impl", 1445 | ] 1446 | 1447 | [[package]] 1448 | name = "ref-cast-impl" 1449 | version = "1.0.2" 1450 | source = "registry+https://github.com/rust-lang/crates.io-index" 1451 | checksum = "7d21b475ab879ef0e315ad99067fa25778c3b0377f57f1b00207448dac1a3144" 1452 | dependencies = [ 1453 | "proc-macro2", 1454 | "quote", 1455 | "syn", 1456 | ] 1457 | 1458 | [[package]] 1459 | name = "regex" 1460 | version = "1.4.3" 1461 | source = "registry+https://github.com/rust-lang/crates.io-index" 1462 | checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" 1463 | dependencies = [ 1464 | "aho-corasick", 1465 | "memchr", 1466 | "regex-syntax", 1467 | "thread_local", 1468 | ] 1469 | 1470 | [[package]] 1471 | name = "regex-automata" 1472 | version = "0.1.9" 1473 | source = "registry+https://github.com/rust-lang/crates.io-index" 1474 | checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" 1475 | dependencies = [ 1476 | "byteorder", 1477 | "regex-syntax", 1478 | ] 1479 | 1480 | [[package]] 1481 | name = "regex-syntax" 1482 | version = "0.6.22" 1483 | source = "registry+https://github.com/rust-lang/crates.io-index" 1484 | checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" 1485 | 1486 | [[package]] 1487 | name = "rustc-demangle" 1488 | version = "0.1.17" 1489 | source = "registry+https://github.com/rust-lang/crates.io-index" 1490 | checksum = "b2610b7f643d18c87dff3b489950269617e6601a51f1f05aa5daefee36f64f0b" 1491 | 1492 | [[package]] 1493 | name = "rustc-hash" 1494 | version = "1.1.0" 1495 | source = "registry+https://github.com/rust-lang/crates.io-index" 1496 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 1497 | 1498 | [[package]] 1499 | name = "rustc-hex" 1500 | version = "2.1.0" 1501 | source = "registry+https://github.com/rust-lang/crates.io-index" 1502 | checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" 1503 | 1504 | [[package]] 1505 | name = "ryu" 1506 | version = "1.0.5" 1507 | source = "registry+https://github.com/rust-lang/crates.io-index" 1508 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 1509 | 1510 | [[package]] 1511 | name = "schnorrkel" 1512 | version = "0.9.1" 1513 | source = "registry+https://github.com/rust-lang/crates.io-index" 1514 | checksum = "021b403afe70d81eea68f6ea12f6b3c9588e5d536a94c3bf80f15e7faa267862" 1515 | dependencies = [ 1516 | "arrayref", 1517 | "arrayvec 0.5.1", 1518 | "curve25519-dalek 2.1.0", 1519 | "getrandom 0.1.15", 1520 | "merlin", 1521 | "rand 0.7.3", 1522 | "rand_core 0.5.1", 1523 | "serde", 1524 | "sha2 0.8.2", 1525 | "subtle 2.3.0", 1526 | "zeroize", 1527 | ] 1528 | 1529 | [[package]] 1530 | name = "scopeguard" 1531 | version = "1.1.0" 1532 | source = "registry+https://github.com/rust-lang/crates.io-index" 1533 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1534 | 1535 | [[package]] 1536 | name = "secrecy" 1537 | version = "0.7.0" 1538 | source = "registry+https://github.com/rust-lang/crates.io-index" 1539 | checksum = "0673d6a6449f5e7d12a1caf424fd9363e2af3a4953023ed455e3c4beef4597c0" 1540 | dependencies = [ 1541 | "zeroize", 1542 | ] 1543 | 1544 | [[package]] 1545 | name = "serde" 1546 | version = "1.0.123" 1547 | source = "registry+https://github.com/rust-lang/crates.io-index" 1548 | checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" 1549 | dependencies = [ 1550 | "serde_derive", 1551 | ] 1552 | 1553 | [[package]] 1554 | name = "serde_derive" 1555 | version = "1.0.123" 1556 | source = "registry+https://github.com/rust-lang/crates.io-index" 1557 | checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" 1558 | dependencies = [ 1559 | "proc-macro2", 1560 | "quote", 1561 | "syn", 1562 | ] 1563 | 1564 | [[package]] 1565 | name = "serde_json" 1566 | version = "1.0.59" 1567 | source = "registry+https://github.com/rust-lang/crates.io-index" 1568 | checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95" 1569 | dependencies = [ 1570 | "itoa", 1571 | "ryu", 1572 | "serde", 1573 | ] 1574 | 1575 | [[package]] 1576 | name = "sha2" 1577 | version = "0.8.2" 1578 | source = "registry+https://github.com/rust-lang/crates.io-index" 1579 | checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" 1580 | dependencies = [ 1581 | "block-buffer 0.7.3", 1582 | "digest 0.8.1", 1583 | "fake-simd", 1584 | "opaque-debug 0.2.3", 1585 | ] 1586 | 1587 | [[package]] 1588 | name = "sha2" 1589 | version = "0.9.3" 1590 | source = "registry+https://github.com/rust-lang/crates.io-index" 1591 | checksum = "fa827a14b29ab7f44778d14a88d3cb76e949c45083f7dbfa507d0cb699dc12de" 1592 | dependencies = [ 1593 | "block-buffer 0.9.0", 1594 | "cfg-if 1.0.0", 1595 | "cpuid-bool", 1596 | "digest 0.9.0", 1597 | "opaque-debug 0.3.0", 1598 | ] 1599 | 1600 | [[package]] 1601 | name = "sharded-slab" 1602 | version = "0.1.1" 1603 | source = "registry+https://github.com/rust-lang/crates.io-index" 1604 | checksum = "79c719719ee05df97490f80a45acfc99e5a30ce98a1e4fb67aee422745ae14e3" 1605 | dependencies = [ 1606 | "lazy_static", 1607 | ] 1608 | 1609 | [[package]] 1610 | name = "signature" 1611 | version = "1.2.2" 1612 | source = "registry+https://github.com/rust-lang/crates.io-index" 1613 | checksum = "29f060a7d147e33490ec10da418795238fd7545bba241504d6b31a409f2e6210" 1614 | 1615 | [[package]] 1616 | name = "simba" 1617 | version = "0.1.5" 1618 | source = "registry+https://github.com/rust-lang/crates.io-index" 1619 | checksum = "fb931b1367faadea6b1ab1c306a860ec17aaa5fa39f367d0c744e69d971a1fb2" 1620 | dependencies = [ 1621 | "approx", 1622 | "num-complex", 1623 | "num-traits", 1624 | "paste 0.1.18", 1625 | ] 1626 | 1627 | [[package]] 1628 | name = "slab" 1629 | version = "0.4.2" 1630 | source = "registry+https://github.com/rust-lang/crates.io-index" 1631 | checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 1632 | 1633 | [[package]] 1634 | name = "smallvec" 1635 | version = "1.4.2" 1636 | source = "registry+https://github.com/rust-lang/crates.io-index" 1637 | checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" 1638 | 1639 | [[package]] 1640 | name = "sp-api" 1641 | version = "3.0.0" 1642 | source = "registry+https://github.com/rust-lang/crates.io-index" 1643 | checksum = "e63c3460d5daecf67df542c34c2bbd636214a5a200d4bddcfa2ffb9e72c346af" 1644 | dependencies = [ 1645 | "hash-db", 1646 | "parity-scale-codec", 1647 | "sp-api-proc-macro", 1648 | "sp-core", 1649 | "sp-runtime", 1650 | "sp-state-machine", 1651 | "sp-std", 1652 | "sp-version", 1653 | "thiserror", 1654 | ] 1655 | 1656 | [[package]] 1657 | name = "sp-api-proc-macro" 1658 | version = "3.0.0" 1659 | source = "registry+https://github.com/rust-lang/crates.io-index" 1660 | checksum = "289624f4fe0f61e63a5019ed26c3bc732b5145eb52796ac6053cd72656d947a1" 1661 | dependencies = [ 1662 | "blake2-rfc", 1663 | "proc-macro-crate", 1664 | "proc-macro2", 1665 | "quote", 1666 | "syn", 1667 | ] 1668 | 1669 | [[package]] 1670 | name = "sp-application-crypto" 1671 | version = "3.0.0" 1672 | source = "registry+https://github.com/rust-lang/crates.io-index" 1673 | checksum = "c52e2e6d43036b97c4fce1ed87c5262c1ffdc78c655ada4d3024a3f8094bdd2c" 1674 | dependencies = [ 1675 | "parity-scale-codec", 1676 | "serde", 1677 | "sp-core", 1678 | "sp-io", 1679 | "sp-std", 1680 | ] 1681 | 1682 | [[package]] 1683 | name = "sp-arithmetic" 1684 | version = "3.0.0" 1685 | source = "registry+https://github.com/rust-lang/crates.io-index" 1686 | checksum = "d0f1c69966c192d1dee8521f0b29ece2b14db07b9b44d801a94e295234761645" 1687 | dependencies = [ 1688 | "integer-sqrt", 1689 | "num-traits", 1690 | "parity-scale-codec", 1691 | "serde", 1692 | "sp-debug-derive", 1693 | "sp-std", 1694 | ] 1695 | 1696 | [[package]] 1697 | name = "sp-core" 1698 | version = "3.0.0" 1699 | source = "registry+https://github.com/rust-lang/crates.io-index" 1700 | checksum = "abbc8d4e9b8a7d5819ed26f1374017bb32833ef4890e4ff065e1da30669876bc" 1701 | dependencies = [ 1702 | "base58", 1703 | "blake2-rfc", 1704 | "byteorder", 1705 | "dyn-clonable", 1706 | "ed25519-dalek", 1707 | "futures", 1708 | "hash-db", 1709 | "hash256-std-hasher", 1710 | "hex", 1711 | "impl-serde", 1712 | "lazy_static", 1713 | "libsecp256k1", 1714 | "log", 1715 | "merlin", 1716 | "num-traits", 1717 | "parity-scale-codec", 1718 | "parity-util-mem", 1719 | "parking_lot", 1720 | "primitive-types", 1721 | "rand 0.7.3", 1722 | "regex", 1723 | "schnorrkel", 1724 | "secrecy", 1725 | "serde", 1726 | "sha2 0.9.3", 1727 | "sp-debug-derive", 1728 | "sp-externalities", 1729 | "sp-runtime-interface", 1730 | "sp-std", 1731 | "sp-storage", 1732 | "substrate-bip39", 1733 | "thiserror", 1734 | "tiny-bip39", 1735 | "tiny-keccak", 1736 | "twox-hash", 1737 | "wasmi", 1738 | "zeroize", 1739 | ] 1740 | 1741 | [[package]] 1742 | name = "sp-debug-derive" 1743 | version = "3.0.0" 1744 | source = "registry+https://github.com/rust-lang/crates.io-index" 1745 | checksum = "e80275f23b4e7ba8f54dec5f90f016530e7307d2ee9445f617ab986cbe97f31e" 1746 | dependencies = [ 1747 | "proc-macro2", 1748 | "quote", 1749 | "syn", 1750 | ] 1751 | 1752 | [[package]] 1753 | name = "sp-externalities" 1754 | version = "0.9.0" 1755 | source = "registry+https://github.com/rust-lang/crates.io-index" 1756 | checksum = "2fdc625f8c7b13b9a136d334888b21b5743d2081cb666cb03efca1dc9b8f74d1" 1757 | dependencies = [ 1758 | "environmental", 1759 | "parity-scale-codec", 1760 | "sp-std", 1761 | "sp-storage", 1762 | ] 1763 | 1764 | [[package]] 1765 | name = "sp-inherents" 1766 | version = "3.0.0" 1767 | source = "registry+https://github.com/rust-lang/crates.io-index" 1768 | checksum = "2542380b535c6941502a0a3069a657eb5abb70fd67b11afa164d4a4b038ba73a" 1769 | dependencies = [ 1770 | "parity-scale-codec", 1771 | "parking_lot", 1772 | "sp-core", 1773 | "sp-std", 1774 | "thiserror", 1775 | ] 1776 | 1777 | [[package]] 1778 | name = "sp-io" 1779 | version = "3.0.0" 1780 | source = "registry+https://github.com/rust-lang/crates.io-index" 1781 | checksum = "33fd69f0a6e91bedc2fb1c5cc3689c212474b6c918274cb4cb14dbbe3c428c14" 1782 | dependencies = [ 1783 | "futures", 1784 | "hash-db", 1785 | "libsecp256k1", 1786 | "log", 1787 | "parity-scale-codec", 1788 | "parking_lot", 1789 | "sp-core", 1790 | "sp-externalities", 1791 | "sp-keystore", 1792 | "sp-runtime-interface", 1793 | "sp-state-machine", 1794 | "sp-std", 1795 | "sp-tracing", 1796 | "sp-trie", 1797 | "sp-wasm-interface", 1798 | "tracing", 1799 | "tracing-core", 1800 | ] 1801 | 1802 | [[package]] 1803 | name = "sp-keystore" 1804 | version = "0.9.0" 1805 | source = "registry+https://github.com/rust-lang/crates.io-index" 1806 | checksum = "db6ccd2baf189112355338e8b224dc513cd239b974dbd717f12b3dc7a7248c3b" 1807 | dependencies = [ 1808 | "async-trait", 1809 | "derive_more", 1810 | "futures", 1811 | "merlin", 1812 | "parity-scale-codec", 1813 | "parking_lot", 1814 | "schnorrkel", 1815 | "sp-core", 1816 | "sp-externalities", 1817 | ] 1818 | 1819 | [[package]] 1820 | name = "sp-panic-handler" 1821 | version = "3.0.0" 1822 | source = "registry+https://github.com/rust-lang/crates.io-index" 1823 | checksum = "54702e109f1c8a870dd4065a497d2612d42cec5817126e96cc0658c5ea975784" 1824 | dependencies = [ 1825 | "backtrace", 1826 | ] 1827 | 1828 | [[package]] 1829 | name = "sp-runtime" 1830 | version = "3.0.0" 1831 | source = "registry+https://github.com/rust-lang/crates.io-index" 1832 | checksum = "dfa4b353b76f04616dbdb8d269d58dcac47acb31c006d3b70e7b64233e68695e" 1833 | dependencies = [ 1834 | "either", 1835 | "hash256-std-hasher", 1836 | "impl-trait-for-tuples", 1837 | "log", 1838 | "parity-scale-codec", 1839 | "parity-util-mem", 1840 | "paste 1.0.4", 1841 | "rand 0.7.3", 1842 | "serde", 1843 | "sp-application-crypto", 1844 | "sp-arithmetic", 1845 | "sp-core", 1846 | "sp-io", 1847 | "sp-std", 1848 | ] 1849 | 1850 | [[package]] 1851 | name = "sp-runtime-interface" 1852 | version = "3.0.0" 1853 | source = "registry+https://github.com/rust-lang/crates.io-index" 1854 | checksum = "b2e5c88b4bc8d607e4e2ff767a85db58cf7101f3dd6064f06929342ea67fe8fb" 1855 | dependencies = [ 1856 | "impl-trait-for-tuples", 1857 | "parity-scale-codec", 1858 | "primitive-types", 1859 | "sp-externalities", 1860 | "sp-runtime-interface-proc-macro", 1861 | "sp-std", 1862 | "sp-storage", 1863 | "sp-tracing", 1864 | "sp-wasm-interface", 1865 | "static_assertions", 1866 | ] 1867 | 1868 | [[package]] 1869 | name = "sp-runtime-interface-proc-macro" 1870 | version = "3.0.0" 1871 | source = "registry+https://github.com/rust-lang/crates.io-index" 1872 | checksum = "19a6c7c2251512c9e533d15db8a863b06ece1cbee778130dd9adbe44b6b39aa9" 1873 | dependencies = [ 1874 | "Inflector", 1875 | "proc-macro-crate", 1876 | "proc-macro2", 1877 | "quote", 1878 | "syn", 1879 | ] 1880 | 1881 | [[package]] 1882 | name = "sp-staking" 1883 | version = "3.0.0" 1884 | source = "registry+https://github.com/rust-lang/crates.io-index" 1885 | checksum = "fc729eb10f8809c61a1fe439ac118a4413de004aaf863003ee8752ac0b596e73" 1886 | dependencies = [ 1887 | "parity-scale-codec", 1888 | "sp-runtime", 1889 | "sp-std", 1890 | ] 1891 | 1892 | [[package]] 1893 | name = "sp-state-machine" 1894 | version = "0.9.0" 1895 | source = "registry+https://github.com/rust-lang/crates.io-index" 1896 | checksum = "46fa4143e58e9130f726d4e8a9b86f3530a8bd19a2eedcdcf4af205f4b5a6d4f" 1897 | dependencies = [ 1898 | "hash-db", 1899 | "log", 1900 | "num-traits", 1901 | "parity-scale-codec", 1902 | "parking_lot", 1903 | "rand 0.7.3", 1904 | "smallvec", 1905 | "sp-core", 1906 | "sp-externalities", 1907 | "sp-panic-handler", 1908 | "sp-std", 1909 | "sp-trie", 1910 | "thiserror", 1911 | "trie-db", 1912 | "trie-root", 1913 | ] 1914 | 1915 | [[package]] 1916 | name = "sp-std" 1917 | version = "3.0.0" 1918 | source = "registry+https://github.com/rust-lang/crates.io-index" 1919 | checksum = "35391ea974fa5ee869cb094d5b437688fbf3d8127d64d1b9fed5822a1ed39b12" 1920 | 1921 | [[package]] 1922 | name = "sp-storage" 1923 | version = "3.0.0" 1924 | source = "registry+https://github.com/rust-lang/crates.io-index" 1925 | checksum = "86af458d4a0251c490cdde9dcaaccb88d398f3b97ac6694cdd49ed9337e6b961" 1926 | dependencies = [ 1927 | "impl-serde", 1928 | "parity-scale-codec", 1929 | "ref-cast", 1930 | "serde", 1931 | "sp-debug-derive", 1932 | "sp-std", 1933 | ] 1934 | 1935 | [[package]] 1936 | name = "sp-tracing" 1937 | version = "3.0.0" 1938 | source = "registry+https://github.com/rust-lang/crates.io-index" 1939 | checksum = "567382d8d4e14fb572752863b5cd57a78f9e9a6583332b590b726f061f3ea957" 1940 | dependencies = [ 1941 | "log", 1942 | "parity-scale-codec", 1943 | "sp-std", 1944 | "tracing", 1945 | "tracing-core", 1946 | "tracing-subscriber", 1947 | ] 1948 | 1949 | [[package]] 1950 | name = "sp-trie" 1951 | version = "3.0.0" 1952 | source = "registry+https://github.com/rust-lang/crates.io-index" 1953 | checksum = "b85b7f745da41ef825c6f7b93f1fdc897b03df94a4884adfbb70fbcd0aed1298" 1954 | dependencies = [ 1955 | "hash-db", 1956 | "memory-db", 1957 | "parity-scale-codec", 1958 | "sp-core", 1959 | "sp-std", 1960 | "trie-db", 1961 | "trie-root", 1962 | ] 1963 | 1964 | [[package]] 1965 | name = "sp-version" 1966 | version = "3.0.0" 1967 | source = "registry+https://github.com/rust-lang/crates.io-index" 1968 | checksum = "dbeffa538a13d715d30e01d57a2636ba32845b737a29a3ea32403576588222e7" 1969 | dependencies = [ 1970 | "impl-serde", 1971 | "parity-scale-codec", 1972 | "serde", 1973 | "sp-runtime", 1974 | "sp-std", 1975 | ] 1976 | 1977 | [[package]] 1978 | name = "sp-wasm-interface" 1979 | version = "3.0.0" 1980 | source = "registry+https://github.com/rust-lang/crates.io-index" 1981 | checksum = "b214e125666a6416cf30a70cc6a5dacd34a4e5197f8a3d479f714af7e1dc7a47" 1982 | dependencies = [ 1983 | "impl-trait-for-tuples", 1984 | "parity-scale-codec", 1985 | "sp-std", 1986 | "wasmi", 1987 | ] 1988 | 1989 | [[package]] 1990 | name = "static_assertions" 1991 | version = "1.1.0" 1992 | source = "registry+https://github.com/rust-lang/crates.io-index" 1993 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 1994 | 1995 | [[package]] 1996 | name = "statrs" 1997 | version = "0.12.0" 1998 | source = "registry+https://github.com/rust-lang/crates.io-index" 1999 | checksum = "cce16f6de653e88beca7bd13780d08e09d4489dbca1f9210e041bc4852481382" 2000 | dependencies = [ 2001 | "rand 0.7.3", 2002 | ] 2003 | 2004 | [[package]] 2005 | name = "substrate-bip39" 2006 | version = "0.4.2" 2007 | source = "registry+https://github.com/rust-lang/crates.io-index" 2008 | checksum = "bed6646a0159b9935b5d045611560eeef842b78d7adc3ba36f5ca325a13a0236" 2009 | dependencies = [ 2010 | "hmac 0.7.1", 2011 | "pbkdf2 0.3.0", 2012 | "schnorrkel", 2013 | "sha2 0.8.2", 2014 | "zeroize", 2015 | ] 2016 | 2017 | [[package]] 2018 | name = "substrate-wasm-builder-runner" 2019 | version = "2.0.0" 2020 | source = "registry+https://github.com/rust-lang/crates.io-index" 2021 | checksum = "54cab12167e32b38a62c5ea5825aa0874cde315f907a46aad2b05aa8ef3d862f" 2022 | 2023 | [[package]] 2024 | name = "subtle" 2025 | version = "1.0.0" 2026 | source = "registry+https://github.com/rust-lang/crates.io-index" 2027 | checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" 2028 | 2029 | [[package]] 2030 | name = "subtle" 2031 | version = "2.3.0" 2032 | source = "registry+https://github.com/rust-lang/crates.io-index" 2033 | checksum = "343f3f510c2915908f155e94f17220b19ccfacf2a64a2a5d8004f2c3e311e7fd" 2034 | 2035 | [[package]] 2036 | name = "syn" 2037 | version = "1.0.60" 2038 | source = "registry+https://github.com/rust-lang/crates.io-index" 2039 | checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" 2040 | dependencies = [ 2041 | "proc-macro2", 2042 | "quote", 2043 | "unicode-xid", 2044 | ] 2045 | 2046 | [[package]] 2047 | name = "synstructure" 2048 | version = "0.12.4" 2049 | source = "registry+https://github.com/rust-lang/crates.io-index" 2050 | checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" 2051 | dependencies = [ 2052 | "proc-macro2", 2053 | "quote", 2054 | "syn", 2055 | "unicode-xid", 2056 | ] 2057 | 2058 | [[package]] 2059 | name = "tap" 2060 | version = "1.0.0" 2061 | source = "registry+https://github.com/rust-lang/crates.io-index" 2062 | checksum = "36474e732d1affd3a6ed582781b3683df3d0563714c59c39591e8ff707cf078e" 2063 | 2064 | [[package]] 2065 | name = "thiserror" 2066 | version = "1.0.24" 2067 | source = "registry+https://github.com/rust-lang/crates.io-index" 2068 | checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" 2069 | dependencies = [ 2070 | "thiserror-impl", 2071 | ] 2072 | 2073 | [[package]] 2074 | name = "thiserror-impl" 2075 | version = "1.0.24" 2076 | source = "registry+https://github.com/rust-lang/crates.io-index" 2077 | checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" 2078 | dependencies = [ 2079 | "proc-macro2", 2080 | "quote", 2081 | "syn", 2082 | ] 2083 | 2084 | [[package]] 2085 | name = "thread_local" 2086 | version = "1.0.1" 2087 | source = "registry+https://github.com/rust-lang/crates.io-index" 2088 | checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" 2089 | dependencies = [ 2090 | "lazy_static", 2091 | ] 2092 | 2093 | [[package]] 2094 | name = "tiny-bip39" 2095 | version = "0.8.0" 2096 | source = "registry+https://github.com/rust-lang/crates.io-index" 2097 | checksum = "d9e44c4759bae7f1032e286a7ef990bd9ed23fe831b7eeba0beb97484c2e59b8" 2098 | dependencies = [ 2099 | "anyhow", 2100 | "hmac 0.8.1", 2101 | "once_cell", 2102 | "pbkdf2 0.4.0", 2103 | "rand 0.7.3", 2104 | "rustc-hash", 2105 | "sha2 0.9.3", 2106 | "thiserror", 2107 | "unicode-normalization", 2108 | "zeroize", 2109 | ] 2110 | 2111 | [[package]] 2112 | name = "tiny-keccak" 2113 | version = "2.0.2" 2114 | source = "registry+https://github.com/rust-lang/crates.io-index" 2115 | checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" 2116 | dependencies = [ 2117 | "crunchy", 2118 | ] 2119 | 2120 | [[package]] 2121 | name = "tinyvec" 2122 | version = "0.3.4" 2123 | source = "registry+https://github.com/rust-lang/crates.io-index" 2124 | checksum = "238ce071d267c5710f9d31451efec16c5ee22de34df17cc05e56cbc92e967117" 2125 | 2126 | [[package]] 2127 | name = "toml" 2128 | version = "0.5.7" 2129 | source = "registry+https://github.com/rust-lang/crates.io-index" 2130 | checksum = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645" 2131 | dependencies = [ 2132 | "serde", 2133 | ] 2134 | 2135 | [[package]] 2136 | name = "tracing" 2137 | version = "0.1.25" 2138 | source = "registry+https://github.com/rust-lang/crates.io-index" 2139 | checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f" 2140 | dependencies = [ 2141 | "cfg-if 1.0.0", 2142 | "pin-project-lite", 2143 | "tracing-core", 2144 | ] 2145 | 2146 | [[package]] 2147 | name = "tracing-core" 2148 | version = "0.1.17" 2149 | source = "registry+https://github.com/rust-lang/crates.io-index" 2150 | checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" 2151 | dependencies = [ 2152 | "lazy_static", 2153 | ] 2154 | 2155 | [[package]] 2156 | name = "tracing-log" 2157 | version = "0.1.2" 2158 | source = "registry+https://github.com/rust-lang/crates.io-index" 2159 | checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" 2160 | dependencies = [ 2161 | "lazy_static", 2162 | "log", 2163 | "tracing-core", 2164 | ] 2165 | 2166 | [[package]] 2167 | name = "tracing-serde" 2168 | version = "0.1.2" 2169 | source = "registry+https://github.com/rust-lang/crates.io-index" 2170 | checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b" 2171 | dependencies = [ 2172 | "serde", 2173 | "tracing-core", 2174 | ] 2175 | 2176 | [[package]] 2177 | name = "tracing-subscriber" 2178 | version = "0.2.16" 2179 | source = "registry+https://github.com/rust-lang/crates.io-index" 2180 | checksum = "8ab8966ac3ca27126141f7999361cc97dd6fb4b71da04c02044fa9045d98bb96" 2181 | dependencies = [ 2182 | "ansi_term", 2183 | "chrono", 2184 | "lazy_static", 2185 | "matchers", 2186 | "regex", 2187 | "serde", 2188 | "serde_json", 2189 | "sharded-slab", 2190 | "smallvec", 2191 | "thread_local", 2192 | "tracing", 2193 | "tracing-core", 2194 | "tracing-log", 2195 | "tracing-serde", 2196 | ] 2197 | 2198 | [[package]] 2199 | name = "trie-db" 2200 | version = "0.22.3" 2201 | source = "registry+https://github.com/rust-lang/crates.io-index" 2202 | checksum = "ec051edf7f0fc9499a2cb0947652cab2148b9d7f61cee7605e312e9f970dacaf" 2203 | dependencies = [ 2204 | "hash-db", 2205 | "hashbrown", 2206 | "log", 2207 | "rustc-hex", 2208 | "smallvec", 2209 | ] 2210 | 2211 | [[package]] 2212 | name = "trie-root" 2213 | version = "0.16.0" 2214 | source = "registry+https://github.com/rust-lang/crates.io-index" 2215 | checksum = "652931506d2c1244d7217a70b99f56718a7b4161b37f04e7cd868072a99f68cd" 2216 | dependencies = [ 2217 | "hash-db", 2218 | ] 2219 | 2220 | [[package]] 2221 | name = "twox-hash" 2222 | version = "1.6.0" 2223 | source = "registry+https://github.com/rust-lang/crates.io-index" 2224 | checksum = "04f8ab788026715fa63b31960869617cba39117e520eb415b0139543e325ab59" 2225 | dependencies = [ 2226 | "cfg-if 0.1.10", 2227 | "rand 0.7.3", 2228 | "static_assertions", 2229 | ] 2230 | 2231 | [[package]] 2232 | name = "typenum" 2233 | version = "1.12.0" 2234 | source = "registry+https://github.com/rust-lang/crates.io-index" 2235 | checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" 2236 | 2237 | [[package]] 2238 | name = "uint" 2239 | version = "0.9.0" 2240 | source = "registry+https://github.com/rust-lang/crates.io-index" 2241 | checksum = "e11fe9a9348741cf134085ad57c249508345fe16411b3d7fb4ff2da2f1d6382e" 2242 | dependencies = [ 2243 | "byteorder", 2244 | "crunchy", 2245 | "hex", 2246 | "static_assertions", 2247 | ] 2248 | 2249 | [[package]] 2250 | name = "unicode-normalization" 2251 | version = "0.1.13" 2252 | source = "registry+https://github.com/rust-lang/crates.io-index" 2253 | checksum = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977" 2254 | dependencies = [ 2255 | "tinyvec", 2256 | ] 2257 | 2258 | [[package]] 2259 | name = "unicode-xid" 2260 | version = "0.2.1" 2261 | source = "registry+https://github.com/rust-lang/crates.io-index" 2262 | checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" 2263 | 2264 | [[package]] 2265 | name = "version_check" 2266 | version = "0.9.2" 2267 | source = "registry+https://github.com/rust-lang/crates.io-index" 2268 | checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" 2269 | 2270 | [[package]] 2271 | name = "wasi" 2272 | version = "0.9.0+wasi-snapshot-preview1" 2273 | source = "registry+https://github.com/rust-lang/crates.io-index" 2274 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 2275 | 2276 | [[package]] 2277 | name = "wasi" 2278 | version = "0.10.0+wasi-snapshot-preview1" 2279 | source = "registry+https://github.com/rust-lang/crates.io-index" 2280 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" 2281 | 2282 | [[package]] 2283 | name = "wasmi" 2284 | version = "0.6.2" 2285 | source = "registry+https://github.com/rust-lang/crates.io-index" 2286 | checksum = "bf617d864d25af3587aa745529f7aaa541066c876d57e050c0d0c85c61c92aff" 2287 | dependencies = [ 2288 | "libc", 2289 | "memory_units", 2290 | "num-rational", 2291 | "num-traits", 2292 | "parity-wasm", 2293 | "wasmi-validation", 2294 | ] 2295 | 2296 | [[package]] 2297 | name = "wasmi-validation" 2298 | version = "0.3.0" 2299 | source = "registry+https://github.com/rust-lang/crates.io-index" 2300 | checksum = "ea78c597064ba73596099281e2f4cfc019075122a65cdda3205af94f0b264d93" 2301 | dependencies = [ 2302 | "parity-wasm", 2303 | ] 2304 | 2305 | [[package]] 2306 | name = "winapi" 2307 | version = "0.3.9" 2308 | source = "registry+https://github.com/rust-lang/crates.io-index" 2309 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2310 | dependencies = [ 2311 | "winapi-i686-pc-windows-gnu", 2312 | "winapi-x86_64-pc-windows-gnu", 2313 | ] 2314 | 2315 | [[package]] 2316 | name = "winapi-i686-pc-windows-gnu" 2317 | version = "0.4.0" 2318 | source = "registry+https://github.com/rust-lang/crates.io-index" 2319 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2320 | 2321 | [[package]] 2322 | name = "winapi-x86_64-pc-windows-gnu" 2323 | version = "0.4.0" 2324 | source = "registry+https://github.com/rust-lang/crates.io-index" 2325 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2326 | 2327 | [[package]] 2328 | name = "wyz" 2329 | version = "0.2.0" 2330 | source = "registry+https://github.com/rust-lang/crates.io-index" 2331 | checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" 2332 | 2333 | [[package]] 2334 | name = "zeroize" 2335 | version = "1.2.0" 2336 | source = "registry+https://github.com/rust-lang/crates.io-index" 2337 | checksum = "81a974bcdd357f0dca4d41677db03436324d45a4c9ed2d0b873a5a360ce41c36" 2338 | dependencies = [ 2339 | "zeroize_derive", 2340 | ] 2341 | 2342 | [[package]] 2343 | name = "zeroize_derive" 2344 | version = "1.0.1" 2345 | source = "registry+https://github.com/rust-lang/crates.io-index" 2346 | checksum = "c3f369ddb18862aba61aa49bf31e74d29f0f162dec753063200e1dc084345d16" 2347 | dependencies = [ 2348 | "proc-macro2", 2349 | "quote", 2350 | "syn", 2351 | "synstructure", 2352 | ] 2353 | --------------------------------------------------------------------------------