,
21 | /// Transaction pool instance.
22 | pub pool: Arc,
23 | /// Whether to deny unsafe calls
24 | pub deny_unsafe: DenyUnsafe,
25 | }
26 |
27 | /// Instantiate all full RPC extensions.
28 | pub fn create_full(deps: FullDeps) -> jsonrpc_core::IoHandler
29 | where
30 | C: ProvideRuntimeApi,
31 | C: HeaderBackend + HeaderMetadata + 'static,
32 | C: Send + Sync + 'static,
33 | C::Api: substrate_frame_rpc_system::AccountNonceApi,
34 | C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi,
35 | C::Api: BlockBuilder,
36 | P: TransactionPool + 'static,
37 | {
38 | use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi};
39 | use substrate_frame_rpc_system::{FullSystem, SystemApi};
40 |
41 | let mut io = jsonrpc_core::IoHandler::default();
42 | let FullDeps {
43 | client,
44 | pool,
45 | deny_unsafe,
46 | } = deps;
47 |
48 | io.extend_with(SystemApi::to_delegate(FullSystem::new(
49 | client.clone(),
50 | pool,
51 | deny_unsafe,
52 | )));
53 |
54 | io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new(
55 | client.clone(),
56 | )));
57 |
58 | // Extend this RPC with a custom API by using the following syntax.
59 | // `YourRpcStruct` should have a reference to a client, which is needed
60 | // to call into the runtime.
61 | // `io.extend_with(YourRpcTrait::to_delegate(YourRpcStruct::new(ReferenceToClient, ...)));`
62 |
63 | io
64 | }
65 |
--------------------------------------------------------------------------------
/substrate-node-example/pallets/template/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | authors = ['Substrate DevHub ']
3 | description = 'FRAME pallet template for defining custom runtime logic.'
4 | edition = '2018'
5 | homepage = 'https://substrate.dev'
6 | license = 'Unlicense'
7 | name = 'pallet-template'
8 | readme = 'README.md'
9 | repository = 'https://github.com/substrate-developer-hub/substrate-node-template/'
10 | version = '3.0.0'
11 |
12 | [package.metadata.docs.rs]
13 | targets = ['x86_64-unknown-linux-gnu']
14 |
15 | [dependencies]
16 | serde = { version = "1.0.125", optional = true, features = ["derive"] }
17 | pallet-chainlink-feed = { path = '../../../pallet-chainlink-feed', default-features = false }
18 | codec = { default-features = false, features = ['derive'], package = 'parity-scale-codec', version = '2.0.0' }
19 | frame-system = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'master' }
20 | frame-support = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'master'}
21 | frame-benchmarking = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'master', version = "3.0.0", optional = true }
22 |
23 | [dev-dependencies]
24 | sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'master' }
25 | sp-io = { git = 'https://github.com/paritytech/substrate.git', branch = 'master' }
26 | sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'master' }
27 | pallet-balances = { git = 'https://github.com/paritytech/substrate.git', branch = 'master' }
28 |
29 | [features]
30 | default = ['std']
31 | std = [
32 | 'serde',
33 | 'codec/std',
34 | 'frame-support/std',
35 | 'frame-system/std',
36 | 'frame-benchmarking/std',
37 | 'pallet-chainlink-feed/std'
38 | ]
39 | runtime-benchmarks = ['frame-benchmarking']
40 | # Note: frame-support `try-runtime` feature is released after v3.
41 | # Uncomment the following line when `frame-support` version > `3.0.0`.
42 | # try-runtime = ['frame-support/try-runtime']
43 |
--------------------------------------------------------------------------------
/substrate-node-example/pallets/template/src/benchmarking.rs:
--------------------------------------------------------------------------------
1 | //! Benchmarking setup for pallet-template
2 |
3 | use super::*;
4 |
5 | #[allow(unused)]
6 | use crate::Pallet as Template;
7 | use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, whitelisted_caller};
8 | use frame_system::RawOrigin;
9 |
10 | benchmarks! {
11 | do_something {
12 | let s in 0 .. 100;
13 | let caller: T::AccountId = whitelisted_caller();
14 | }: _(RawOrigin::Signed(caller), s)
15 | verify {
16 | assert_eq!(Something::::get(), Some(s));
17 | }
18 | }
19 |
20 | impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test,);
21 |
--------------------------------------------------------------------------------
/substrate-node-example/pallets/template/src/mock.rs:
--------------------------------------------------------------------------------
1 | use crate as pallet_template;
2 | use frame_support::{parameter_types, PalletId};
3 | use frame_system as system;
4 | use sp_core::H256;
5 | use sp_runtime::{
6 | testing::Header,
7 | traits::{BlakeTwo256, IdentityLookup},
8 | };
9 |
10 | type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic;
11 | type Block = frame_system::mocking::MockBlock;
12 |
13 | // Configure a mock runtime to test the pallet.
14 | frame_support::construct_runtime!(
15 | pub enum Test where
16 | Block = Block,
17 | NodeBlock = Block,
18 | UncheckedExtrinsic = UncheckedExtrinsic,
19 | {
20 | System: frame_system::{Pallet, Call, Config, Storage, Event},
21 | Balances: pallet_balances::{Pallet, Call, Storage, Config, Event},
22 | ChainlinkFeed: pallet_chainlink_feed::{Pallet, Call, Storage, Event},
23 | TemplateModule: pallet_template::{Pallet, Call, Storage, Event},
24 | }
25 | );
26 |
27 | parameter_types! {
28 | pub const BlockHashCount: u64 = 250;
29 | pub const SS58Prefix: u8 = 42;
30 | }
31 |
32 | impl system::Config for Test {
33 | type BaseCallFilter = ();
34 | type BlockWeights = ();
35 | type BlockLength = ();
36 | type DbWeight = ();
37 | type Origin = Origin;
38 | type Call = Call;
39 | type Index = u64;
40 | type BlockNumber = u64;
41 | type Hash = H256;
42 | type Hashing = BlakeTwo256;
43 | type AccountId = u64;
44 | type Lookup = IdentityLookup;
45 | type Header = Header;
46 | type Event = Event;
47 | type BlockHashCount = BlockHashCount;
48 | type Version = ();
49 | type PalletInfo = PalletInfo;
50 | type AccountData = pallet_balances::AccountData;
51 | type OnNewAccount = ();
52 | type OnKilledAccount = ();
53 | type SystemWeightInfo = ();
54 | type SS58Prefix = SS58Prefix;
55 | type OnSetCode = ();
56 | }
57 |
58 | parameter_types! {
59 | pub const ExistentialDeposit: u64 = 1;
60 | }
61 |
62 | type Balance = u64;
63 |
64 | impl pallet_balances::Config for Test {
65 | type MaxLocks = ();
66 | type Balance = Balance;
67 | type Event = Event;
68 | type DustRemoval = ();
69 | type ExistentialDeposit = ExistentialDeposit;
70 | type AccountStore = System;
71 | type WeightInfo = ();
72 | type MaxReserves = ();
73 | type ReserveIdentifier = [u8; 8];
74 | }
75 |
76 | pub(crate) const MIN_RESERVE: u64 = 100;
77 |
78 | parameter_types! {
79 | pub const FeedPalletId: PalletId = PalletId(*b"linkfeed");
80 | pub const MinimumReserve: u64 = MIN_RESERVE;
81 | pub const StringLimit: u32 = 15;
82 | pub const OracleLimit: u32 = 10;
83 | pub const FeedLimit: u16 = 10;
84 | pub const PruningWindow: u32 = 3;
85 | }
86 |
87 | type FeedId = u16;
88 | type Value = u64;
89 |
90 | impl pallet_chainlink_feed::Config for Test {
91 | type Event = Event;
92 | type FeedId = FeedId;
93 | type Value = Value;
94 | type Currency = Balances;
95 | type PalletId = FeedPalletId;
96 | type MinimumReserve = MinimumReserve;
97 | type StringLimit = StringLimit;
98 | type OracleCountLimit = OracleLimit;
99 | type FeedLimit = FeedLimit;
100 | type WeightInfo = ();
101 | type OnAnswerHandler = ();
102 | }
103 |
104 | impl pallet_template::Config for Test {
105 | type Event = Event;
106 | type Oracle = ChainlinkFeed;
107 | }
108 |
109 | // Build genesis storage according to the mock runtime.
110 | pub fn new_test_ext() -> sp_io::TestExternalities {
111 | system::GenesisConfig::default()
112 | .build_storage::()
113 | .unwrap()
114 | .into()
115 | }
116 |
--------------------------------------------------------------------------------
/substrate-node-example/pallets/template/src/tests.rs:
--------------------------------------------------------------------------------
1 | use crate::{mock::*, Error};
2 | use frame_support::{assert_noop, assert_ok};
3 |
4 | #[test]
5 | fn it_works_for_default_value() {
6 | new_test_ext().execute_with(|| {
7 | // Dispatch a signed extrinsic.
8 | assert_ok!(TemplateModule::do_something(Origin::signed(1), 42));
9 | // Read pallet storage and assert an expected result.
10 | assert_eq!(TemplateModule::something(), Some(42));
11 | });
12 | }
13 |
14 | #[test]
15 | fn correct_error_for_none_value() {
16 | new_test_ext().execute_with(|| {
17 | // Ensure the expected error is thrown when no value is present.
18 | assert_noop!(
19 | TemplateModule::cause_error(Origin::signed(1)),
20 | Error::::NoneValue
21 | );
22 | });
23 | }
24 |
--------------------------------------------------------------------------------
/substrate-node-example/runtime/build.rs:
--------------------------------------------------------------------------------
1 | use substrate_wasm_builder::WasmBuilder;
2 |
3 | fn main() {
4 | WasmBuilder::new()
5 | .with_current_project()
6 | .export_heap_base()
7 | .import_memory()
8 | .build()
9 | }
10 |
--------------------------------------------------------------------------------
/substrate-node-example/runtime/src/example.rs:
--------------------------------------------------------------------------------
1 | use codec::{Decode, Encode};
2 | use frame_support::sp_runtime::traits::UniqueSaturatedFrom;
3 | use frame_support::traits::Currency;
4 | use frame_support::{decl_module, decl_storage, dispatch::DispatchResult};
5 | use frame_system::ensure_root;
6 | use pallet_chainlink::{CallbackWithParameter, Config as ChainlinkTrait, Event};
7 | use sp_std::prelude::*;
8 |
9 | type BalanceOf = <::Currency as Currency<
10 | ::AccountId,
11 | >>::Balance;
12 |
13 | pub trait Config: pallet_chainlink::Config + ChainlinkTrait {
14 | type Event: From> + Into<::Event>;
15 | type Callback: From> + Into<::Callback>;
16 | }
17 |
18 | decl_storage! {
19 | trait Store for Module as ExampleStorage {
20 | pub Result: i128;
21 | }
22 | }
23 |
24 | decl_module! {
25 | pub struct Module for enum Call where origin: T::Origin {
26 | fn deposit_event() = default;
27 |
28 | #[weight = 0]
29 | pub fn send_request(origin, operator: T::AccountId, specid: Vec) -> DispatchResult {
30 | let parameters = ("get", "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD", "path", "RAW.ETH.USD.PRICE", "times", "100000000");
31 | let call: ::Callback = Call::callback(vec![]).into();
32 |
33 | let fee = BalanceOf::::unique_saturated_from(100u32);
34 | >::initiate_request(origin, operator, specid, 0, parameters.encode(), fee, call.into())?;
35 |
36 | Ok(())
37 | }
38 |
39 | #[weight = 0]
40 | pub fn callback(origin, result: Vec) -> DispatchResult {
41 | ensure_root(origin)?;
42 |
43 | // The result is expected to be a SCALE encoded `i128`
44 | let r : i128 = i128::decode(&mut &result[..]).map_err(|_| Error::::DecodingFailed)?;
45 | ::put(r);
46 |
47 | Ok(())
48 | }
49 | }
50 | }
51 |
52 | frame_support::decl_error! {
53 | pub enum Error for Module {
54 | DecodingFailed
55 | }
56 | }
57 |
58 | impl CallbackWithParameter for Call {
59 | fn with_result(&self, result: Vec) -> Option {
60 | match *self {
61 | Call::callback(_) => Some(Call::callback(result)),
62 | _ => None,
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/substrate-node-example/runtime/src/weights/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod pallet_chainlink_feed;
2 |
--------------------------------------------------------------------------------
/substrate-node-example/scripts/docker_run.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | echo "*** Start Substrate node template ***"
6 |
7 | cd $(dirname ${BASH_SOURCE[0]})/..
8 |
9 | docker-compose down --remove-orphans
10 | docker-compose run --rm --service-ports dev $@
--------------------------------------------------------------------------------
/substrate-node-example/scripts/init.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | echo "*** Initializing WASM build environment ***"
6 |
7 | if [ -z $CI_PROJECT_NAME ] ; then
8 | rustup update nightly
9 | rustup update stable
10 | fi
11 |
12 | rustup target add wasm32-unknown-unknown --toolchain nightly
13 | rustup target add wasm32-unknown-unknown --toolchain nightly-2020-10-05
14 |
--------------------------------------------------------------------------------
/substrate-node-example/specs/README.md:
--------------------------------------------------------------------------------
1 | This folder contains different chains-specs you can use to specify the example chain's specifications
2 |
3 | To run the example chain with a custom chainspec:
4 |
5 | ```shell
6 | cargo build --release
7 | ./target/release/node-template --chain=./specs/chainlink-feed.json --tmp --alice
8 | ```
9 |
10 | You can check that the feed is included in the chain state:
11 | - use the polkadot UI -> Developer -> Chain State -> chainlinkFeed -> Feeds(0)
12 |
13 | If it shows `` you need to register the custom [types](../types.json) by copying the json types into Settings -> Developer in the UI
14 |
15 | If the chain blocks access from the UI (`Blocked connection to WebSockets server from untrusted origin`) add the `--rpc-cors all` option
16 |
17 |
18 | Read more about substrate's [Chain Specification](https://substrate.dev/docs/en/knowledgebase/integrate/chain-spec) and [creating private networks](https://substrate.dev/docs/en/tutorials/start-a-private-network)
19 |
20 |
21 | * [chainlink.json](chainlink.json) is a spec with multiple registered feed creators (Alice, Bob, Charlie, Dave, Eve, Ferdie as well as their stash accounts). pallet admin is Alice
22 | * [chainlink-feed.json](chainlink-feed.json) is a spec with the same feed creators and a feed owned by Alice, several oracles (Bob, Charlie, Dave, Eve) and Ferdie as their admin.
23 | To add more feeds, add another feed in the `feeds` array.
24 | * [chainlink-no-admin-funds.json](chainlink-no-admin-funds.json) is a spec the same feed creators but the admin is Ferdie which has no endowment.
25 |
26 | The `--chain` command of the node is modified to accept also feed config json files like [feedconfig.json](feedconfig.json) directly. In this case the same config as `--dev` is used but with feed config of the given json file.
27 | In addtion the `--chain` option also accepts a feed config string directly.
28 |
29 | ```shell
30 | ./target/release/node-template --chain=./specs/feedconfig.json --tmp --alice
31 | ```
32 |
33 | The genesis config of the `chainlink-feed` pallet can be created like:
34 |
35 | ```rust
36 | chainlink_feed: ChainlinkFeedConfig {
37 | pallet_admin: Some(root_key),
38 | // accounts that are allowed to create feeds, must include the owners of the `feeds`
39 | feed_creators: vec![get_account_id_from_seed::("Alice")],
40 | feeds: vec![node_template_runtime::FeedBuilder::new()
41 | // owner of this feed
42 | .owner(get_account_id_from_seed::("Alice"))
43 | .decimals(8)
44 | // payment of oracle rounds
45 | .payment(1_000)
46 | // round initiation delay
47 | .restart_delay(0)
48 | // timeout of blocks
49 | .timeout(10)
50 | .description(b"LINK".to_vec())
51 | .value_bounds(1, 1_000)
52 | .min_submissions(2)
53 | // make Bob, Charlie, Dave and Eve oracles and Ferdie their admin
54 | .oracles(vec![
55 | (
56 | get_account_id_from_seed::("Bob"),
57 | get_account_id_from_seed::("Ferdie"),
58 | ),
59 | (
60 | get_account_id_from_seed::("Charlie"),
61 | get_account_id_from_seed::("Ferdie"),
62 | )
63 | ])]
64 | },
65 | ```
--------------------------------------------------------------------------------
/substrate-node-example/specs/feedconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "palletAdmin": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
3 | "feedCreators": [
4 | "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
5 | "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
6 | "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y",
7 | "5DAAnrj7VHTznn2AWBemMuyBwZWs6FNFjdyVXUeYum3PTXFy",
8 | "5HGjWAeFDfFCWPsjFQdVV2Msvz2XtMktvgocEZcCj68kUMaw",
9 | "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL",
10 | "5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY",
11 | "5HpG9w8EBLe5XCrbczpwq5TSXvedjrBGCwqxK1iQ7qUsSWFc",
12 | "5Ck5SLSHYac6WFt5UZRSsdJjwmpSZq85fd5TRNAdZQVzEAPT",
13 | "5HKPmK9GYtE1PSLsS1qiYU9xQ9Si1NcEhdeCq9sw5bqu4ns8",
14 | "5FCfAonRZgTFrTd9HREEyeJjDpT397KMzizE6T3DvebLFE7n",
15 | "5CRmqmsiNFExV6VbdmPJViVxrWmkaXXvBrSX8oqBT8R9vmWk"
16 | ],
17 | "feeds": [
18 | {
19 | "owner": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
20 | "payment": 1000,
21 | "timeout": 10,
22 | "value_bounds": [
23 | 1,
24 | 1000
25 | ],
26 | "min_submissions": 2,
27 | "description": [
28 | 76,
29 | 73,
30 | 78,
31 | 75
32 | ],
33 | "decimals": 8,
34 | "restart_delay": 0,
35 | "oracles": [
36 | [
37 | "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
38 | "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL"
39 | ],
40 | [
41 | "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y",
42 | "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL"
43 | ],
44 | [
45 | "5DAAnrj7VHTznn2AWBemMuyBwZWs6FNFjdyVXUeYum3PTXFy",
46 | "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL"
47 | ],
48 | [
49 | "5HGjWAeFDfFCWPsjFQdVV2Msvz2XtMktvgocEZcCj68kUMaw",
50 | "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL"
51 | ]
52 | ],
53 | "pruning_window": null,
54 | "max_debt": null
55 | }
56 | ]
57 | }
--------------------------------------------------------------------------------
/substrate-node-example/types.json:
--------------------------------------------------------------------------------
1 | {
2 | "SpecIndex": "Vec",
3 | "RequestIdentifier": "u64",
4 | "DataVersion": "u64",
5 | "Address": "MultiAddress",
6 | "LookupSource": "MultiAddress",
7 | "FeedId": "u32",
8 | "RoundId": "u32",
9 | "Value": "u128",
10 | "FeedConfig": {
11 | "owner": "AccountId",
12 | "pending_owner": "Option",
13 | "submission_value_bounds": "(Value, Value)",
14 | "submission_count_bounds": "(u32, u32)",
15 | "payment": "Balance",
16 | "timeout": "BlockNumber",
17 | "decimals": "u8",
18 | "description": "Vec",
19 | "restart_delay": "u32",
20 | "reporting_round": "RoundId",
21 | "latest_round": "RoundId",
22 | "first_valid_round": "Option",
23 | "oracle_count": "u32",
24 | "pruning_window": "u32",
25 | "next_round_to_prune": "RoundId",
26 | "debt": "Balance",
27 | "max_debt": "Option"
28 | },
29 | "FeedConfigOf": "FeedConfig",
30 | "Round": {
31 | "started_at": "BlockNumber",
32 | "answer": "Option",
33 | "updated_at": "Option",
34 | "answered_in_round": "Option"
35 | },
36 | "RoundOf": "Round",
37 | "RoundDetails": {
38 | "submissions": "Vec",
39 | "submission_count_bounds": "(u32, u32)",
40 | "payment": "Balance",
41 | "timeout": "BlockNumber"
42 | },
43 | "RoundDetailsOf": "RoundDetails",
44 | "OracleMeta": {
45 | "withdrawable": "Balance",
46 | "admin": "AccountId",
47 | "pending_admin": "Option"
48 | },
49 | "OracleMetaOf": "OracleMeta",
50 | "OracleStatus": {
51 | "starting_round": "RoundId",
52 | "ending_round": "Option",
53 | "last_reported_round": "Option",
54 | "last_started_round": "Option",
55 | "latest_submission": "Option"
56 | },
57 | "OracleStatusOf": "OracleStatus",
58 | "Requester": {
59 | "delay": "RoundId",
60 | "last_started_round": "Option"
61 | },
62 | "RoundData": {
63 | "started_at": "BlockNumber",
64 | "answer": "Value",
65 | "updated_at": "BlockNumber",
66 | "answered_in_round": "RoundId"
67 | },
68 | "RoundDataOf": "RoundData",
69 | "SubmissionBounds": "(u32, u32)"
70 | }
--------------------------------------------------------------------------------