├── .actrc ├── .cargo └── config.toml ├── .circleci └── config.yml ├── .dockerignore ├── .github ├── ISSUE_TEMPLATE │ ├── backlog_item.md │ ├── bug_issue.md │ ├── config.yml │ └── general_issue.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── check-licence.yml │ └── docs.yml ├── .gitignore ├── .gitmodules ├── Cargo.lock ├── Cargo.toml ├── HEADER-LICENSE ├── LICENSE ├── README.md ├── config.json ├── docker ├── launch.Dockerfile └── release.Dockerfile ├── docs ├── .gitignore ├── 404.html ├── assets │ ├── css │ │ └── style.scss │ ├── favicon.ico │ ├── img │ │ ├── nav-formula.png │ │ ├── pint.png │ │ └── set-custom-types.png │ └── pint2.svg ├── getting-started │ ├── installation.md │ ├── overview │ │ └── architecture.md │ └── resources │ │ ├── developer-resources.md │ │ └── general-resources.md ├── index.md └── usage │ ├── command-line.md │ └── configuration.md ├── js ├── .prettierrc ├── e2e │ ├── README.md │ ├── index.ts │ ├── package.json │ ├── src │ │ ├── config.ts │ │ ├── extrinsic.ts │ │ ├── index.ts │ │ ├── launch.ts │ │ ├── runner.ts │ │ └── util.ts │ ├── tsconfig.json │ └── tslint.json ├── finalize │ ├── index.ts │ ├── package.json │ └── tsconfig.json ├── package.json ├── pint-types-bundle │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── chainlink.json │ ├── index.ts │ ├── package.json │ └── tsconfig.json ├── scripts │ └── update_pint_types.ts └── yarn.lock ├── mkdocs.yml ├── node ├── Cargo.toml ├── build.rs └── src │ ├── chain_spec │ ├── dev.rs │ ├── mod.rs │ ├── pint.rs │ └── shot.rs │ ├── cli.rs │ ├── client.rs │ ├── command.rs │ ├── instant_finalize.rs │ ├── lib.rs │ ├── main.rs │ └── service.rs ├── package-lock.json ├── pallets ├── asset-index │ ├── Cargo.toml │ ├── README.md │ ├── rpc │ │ ├── Cargo.toml │ │ ├── runtime-api │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── src │ │ │ └── lib.rs │ └── src │ │ ├── benchmarking.rs │ │ ├── lib.rs │ │ ├── mock.rs │ │ ├── tests.rs │ │ ├── traits.rs │ │ └── types.rs ├── committee │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── benchmarking.rs │ │ ├── lib.rs │ │ ├── mock.rs │ │ ├── tests.rs │ │ ├── traits.rs │ │ ├── types.rs │ │ └── utils.rs ├── local-treasury │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── benchmarking.rs │ │ ├── lib.rs │ │ ├── mock.rs │ │ └── tests.rs ├── price-feed │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── benchmarking.rs │ │ ├── lib.rs │ │ ├── mock.rs │ │ ├── tests.rs │ │ ├── traits.rs │ │ └── types.rs ├── remote-asset-manager │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── lib.rs │ │ ├── traits.rs │ │ └── types.rs ├── remote-treasury │ ├── Cargo.toml │ ├── README.md │ └── src │ │ └── lib.rs └── saft-registry │ ├── Cargo.toml │ ├── README.md │ └── src │ ├── benchmarking.rs │ ├── lib.rs │ ├── mock.rs │ ├── tests.rs │ └── traits.rs ├── primitives ├── derive │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── lib.rs │ │ └── xcm │ │ ├── mod.rs │ │ └── result.rs ├── primitives │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── fee.rs │ │ ├── lib.rs │ │ ├── traits.rs │ │ └── types.rs └── xcm-calls │ ├── Cargo.toml │ ├── README.md │ └── src │ ├── assets.rs │ ├── encode_with.rs │ ├── lib.rs │ ├── proxy.rs │ ├── staking.rs │ └── utility.rs ├── resources ├── README.md ├── pint-dev-with-chainlink-feed.json ├── pint-dev.json └── types.json ├── rpc ├── Cargo.toml └── src │ └── lib.rs ├── runtime ├── common │ ├── Cargo.toml │ └── src │ │ ├── constants.rs │ │ ├── lib.rs │ │ ├── payment.rs │ │ ├── traits.rs │ │ ├── types.rs │ │ └── weights │ │ ├── mod.rs │ │ ├── pallet_asset_index.rs │ │ ├── pallet_chainlink_feed.rs │ │ ├── pallet_committee.rs │ │ ├── pallet_local_treasury.rs │ │ ├── pallet_price_feed.rs │ │ ├── pallet_remote_asset_manager.rs │ │ └── pallet_saft_registry.rs ├── dev │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ └── lib.rs ├── integration-tests │ ├── Cargo.toml │ └── src │ │ ├── ext.rs │ │ ├── lib.rs │ │ ├── prelude.rs │ │ ├── statemint.rs │ │ ├── tests.rs │ │ └── util.rs ├── pint │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ └── lib.rs └── shot │ ├── Cargo.toml │ ├── build.rs │ └── src │ └── lib.rs ├── rustfmt.toml ├── scripts ├── header.txt └── init.sh ├── templates ├── pallet-weight-template.hbs └── runtime-weight-template.hbs └── test-utils └── xcm-test-support └── Cargo.toml /.actrc: -------------------------------------------------------------------------------- 1 | # When using act to run github actions locally it must use a full image to be able to compile correctly 2 | -P ubuntu-20.04=nektos/act-environments-ubuntu:20.04 3 | -------------------------------------------------------------------------------- /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [net] 2 | git-fetch-with-cli = true 3 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | **/target/ 4 | # These are backup files generated by rustfmt 5 | **/*.rs.bk 6 | 7 | # node deps for e2e 8 | node_modules 9 | 10 | # The directory caches for osx 11 | .DS_Store 12 | 13 | # typescript language server logs and logs 14 | *.log 15 | 16 | # rococo specs 17 | rococo* 18 | 19 | # The cache for docker container dependency 20 | .cargo 21 | 22 | # The cache for chain data in container 23 | .local 24 | 25 | # Binaries for launching PINT with polkadot 26 | bin 27 | 28 | # Libraries of js output 29 | js/**/*/lib 30 | 31 | # Unknown 32 | local-test 33 | 34 | # docker 35 | docker -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/backlog_item.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Backlog Item 3 | about: Issue that has enough reasoning, research and information to be implemented 4 | title: '' 5 | labels: 'needs triage' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | ## Implementation details 13 | 14 | 15 | ## Testing details 16 | 17 | 18 | ## Acceptance Criteria 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: 'bug' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Describe the bug 11 | 12 | 13 | - 14 | 15 | 16 | ## Expected Behavior 17 | 18 | 25 | 26 | - 27 | 28 | 29 | ## Current Behavior 30 | 31 | 39 | 40 | - 41 | 42 | 43 | ## Possible Solution 44 | 45 | 53 | 54 | - 55 | 56 | 57 | ## To Reproduce 58 | Steps to reproduce the behavior: 59 | 60 | 1. 61 | 2. 62 | 3. 63 | 64 | 65 | ## Log output 66 | 67 |
68 | Log Output 69 | 70 | ```Paste log output here 71 | paste log output... 72 | ``` 73 |
74 |
75 | 76 | ## Specification 77 | 78 | 91 | 92 | - rustc version: 93 | - pint version: 94 | - commit tag: 95 | - commit hash: 96 | - operating system: 97 | - additional links: 98 | 99 | 100 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | 2 | blank_issues_enabled: true -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/general_issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: General issue 3 | about: General purpose issue template 4 | title: '' 5 | labels: 'needs triage' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Issue summary 11 | 12 | - 13 | 14 | 15 | ## Other information and links 16 | 17 | - 18 | 19 | 20 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Changes 2 | 3 | 9 | 10 | - 11 | - 12 | - 13 | 14 | ## Tests 15 | 16 | 21 | 22 | ``` 23 | 24 | ``` 25 | 26 | ## Issues 27 | 28 | 34 | 35 | - -------------------------------------------------------------------------------- /.github/workflows/check-licence.yml: -------------------------------------------------------------------------------- 1 | name: Check Licence 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | push: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | check-licence: 13 | runs-on: ubuntu-18.04 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Set up Golang 18 | uses: actions/setup-go@v2 19 | with: 20 | go-version: '^1.16' 21 | - name: Install addlicense 22 | run: | 23 | export PATH=${PATH}:`go env GOPATH`/bin 24 | go get -v -u github.com/google/addlicense 25 | - name: Check license 26 | run: | 27 | export PATH=${PATH}:`go env GOPATH`/bin 28 | addlicense -check -c "ChainSafe Systems" -f ./scripts/header.txt -y 2021 $(find $PWD -type f -name '*.rs') 29 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: Publish docs via GitHub Pages 2 | on: 3 | push: 4 | branches: 5 | - main 6 | 7 | jobs: 8 | build: 9 | name: Deploy docs 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout main 13 | uses: actions/checkout@v2 14 | 15 | - uses: actions-rs/toolchain@v1 16 | with: 17 | toolchain: nightly 18 | target: wasm32-unknown-unknown 19 | 20 | - run: | 21 | cargo doc --all-features 22 | mv target/doc docs/api 23 | 24 | - name: Deploy docs 25 | uses: mhausenblas/mkdocs-deploy-gh-pages@master 26 | env: 27 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 28 | CONFIG_FILE: ./mkdocs.yml 29 | EXTRA_PACKAGES: build-base 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | **/target/ 4 | # These are backup files generated by rustfmt 5 | **/*.rs.bk 6 | 7 | # node deps for e2e 8 | node_modules 9 | 10 | # The directory caches for osx 11 | .DS_Store 12 | 13 | # typescript language server logs and logs 14 | *.log 15 | 16 | # rococo specs 17 | rococo* 18 | 19 | # The cache for docker container dependency 20 | .cargo 21 | 22 | # The cache for chain data in container 23 | .local 24 | 25 | # Binaries for launching PINT with polkadot 26 | bin 27 | 28 | # Libraries of js output 29 | js/**/*/lib 30 | 31 | # Unknown 32 | local-test 33 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "js/polkadot-launch"] 2 | path = js/polkadot-launch 3 | url = https://github.com/ChainSafe/polkadot-launch.git 4 | -------------------------------------------------------------------------------- /HEADER-LICENSE: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Polkadot Index Network Token (PINT :beer:) 2 | 3 | [![License: LGPL v3](https://img.shields.io/badge/License-LGPL%20v3-blue.svg)](http://www.gnu.org/licenses/lgpl-3.0) 4 | [![rustdocs](https://img.shields.io/badge/docs-rust-yellow)](https://chainsafe.github.io/PINT/api/pint_runtime_dev/) 5 | 6 | A Polkadot ecosystem index for investors. A self sustaining auction treasury for parachains. 7 | 8 | Organized by the Stateless Money validator, governed by a community that includes Polychain Capital, Hypersphere 9 | Ventures, HashKey Capital, Acala, and built by ChainSafe as a StakerDAO product. 10 | 11 | For more information on the project please visit [Polkadot Index Network Token](https://docs.polkadotindex.com/) 12 | documentation. 13 | 14 | ❗**Current development should be considered a work in progress.** 15 | 16 | ## Upstream 17 | 18 | This project is a fork of the 19 | [Substrate Developer Hub Node Template](https://github.com/substrate-developer-hub/substrate-node-template). 20 | 21 | ## Build & Run 22 | 23 | Follow these steps to prepare a local Substrate development environment :hammer_and_wrench: 24 | 25 | ### Setup 26 | 27 | This project currently builds against Rust nightly-2021-08-01. Assuming you have rustup already insatlled set up your 28 | local environment: 29 | 30 | ```shell 31 | rustup install nightly-2021-08-01 32 | rustup target add wasm32-unknown-unknown --toolchain nightly-2021-08-01 33 | rustup override set nightly-2021-08-01 34 | ``` 35 | 36 | ### Build 37 | 38 | Once the development environment is set up, build the node template. This command will build the 39 | [Wasm](https://substrate.dev/docs/en/knowledgebase/advanced/executor#wasm-execution) and 40 | [native](https://substrate.dev/docs/en/knowledgebase/advanced/executor#native-execution) code: 41 | 42 | ```bash 43 | cargo build --release 44 | ``` 45 | 46 | Note: If the build fails with `(signal: 9, SIGKILL: kill)` it has probably run out of memory. Try freeing some memory or 47 | build on another machine. 48 | 49 | ## Run 50 | 51 | ### Development Chain 52 | 53 | You can start a standalone development chain with instant sealing: 54 | 55 | ```bash 56 | cargo run -- --tmp --dev --instant-sealing 57 | ``` 58 | 59 | Use a chain spec file with pre funded Developer accounts 60 | 61 | ```bash 62 | cargo run -- --tmp --chain ./resources/pint-dev.json --instant-sealing 63 | ``` 64 | 65 | __NOTE: the amount of PINT in all the endowed accounts (dev accounts) of the balances pallet ( 66 | see [pint-dev.json](resources/pint-dev.json)) directly affects the NAV, since this is the total amount of PINT in 67 | curculation at genesis__ 68 | 69 | Or if already built 70 | 71 | ```bash 72 | ./target/release/pint --tmp --dev --instant-sealing 73 | ``` 74 | 75 | This will use the [`node/src/chain_spec/dev.rs`](node/src/chain_spec/dev.rs) chain spec. 76 | 77 | ### Local Testnet 78 | 79 | Polkadot (release-v0.9.x branch) 80 | 81 | ```bash 82 | cargo build --release 83 | 84 | ./target/release/polkadot build-spec --chain rococo-local --raw --disable-default-bootnode > rococo_local.json 85 | 86 | ./target/release/polkadot --chain ./rococo_local.json -d cumulus_relay0 --validator --alice --port 9844 87 | 88 | ./target/release/polkadot --chain ./rococo_local.json -d cumulus_relay1 --validator --bob --port 9955 89 | ``` 90 | 91 | PINT Parachain: 92 | 93 | ```bash 94 | # this command assumes the chain spec is in a directory named polkadot that is a sibling of the pint directory 95 | ./target/release/pint --collator --alice --chain pint-dev --ws-port 9945 --parachain-id 200 --rpc-cors all -- --execution wasm --chain ../polkadot/rococo_local.json --ws-port 9977 --rpc-cors all 96 | ``` 97 | 98 | ### Registering on Local Relay Chain 99 | 100 | In order to produce blocks you will need to register the parachain as detailed in 101 | the [Substrate Cumulus Workshop](https://substrate.dev/cumulus-workshop/#/en/3-parachains/2-register) by going to 102 | 103 | Developer -> sudo -> paraSudoWrapper -> sudoScheduleParaInitialize(id, genesis) 104 | 105 | Ensure you set the `ParaId` to `200` and the `parachain: Bool` to `Yes`. 106 | 107 | ```bash 108 | cargo build --release 109 | # Build the Chain spec 110 | ./target/release/pint build-spec --disable-default-bootnode > ./pint-local-plain.json 111 | # Build the raw file 112 | ./target/release/pint build-spec --chain=./pint-local-plain.json --raw --disable-default-bootnode > ./pint-local.json 113 | 114 | 115 | # export genesis state and wasm 116 | ./target/release/pint export-genesis-state --parachain-id 200 > ./resources/para-200-genesis 117 | ./target/release/pint export-genesis-wasm > ./para-200.wasm 118 | ``` 119 | 120 | * [polkadot-launch](https://github.com/paritytech/polkadot-launch) can be run by dropping the proper polkadot binary in 121 | the `./bin` folder and 122 | * Run globally 123 | * `polkadot-launch config.json` 124 | * Run locally, navigate into polkadot-launch, 125 | * ``` yarn ``` 126 | * ``` yarn start ``` 127 | 128 | ### Documentation 129 | 130 | ## Commands 131 | 132 | * `mkdocs serve` - Start the live-reloading docs server. 133 | * `mkdocs build` - Build the documentation site. 134 | * `mkdocs -h` - Print help message and exit. 135 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "relaychain": { 3 | "bin": "./bin/polkadot", 4 | "chain": "rococo-local", 5 | "nodes": [ 6 | { 7 | "name": "alice", 8 | "wsPort": 9944, 9 | "port": 30444 10 | }, 11 | { 12 | "name": "bob", 13 | "wsPort": 9955, 14 | "port": 30555 15 | }, 16 | { 17 | "name": "charlie", 18 | "wsPort": 9966, 19 | "port": 30666 20 | } 21 | ] 22 | }, 23 | "parachains": [ 24 | { 25 | "bin": "./bin/pint", 26 | "chain": "dev-local", 27 | "balance": "1000000000000000000000", 28 | "nodes": [ 29 | { 30 | "wsPort": 9988, 31 | "port": 31200, 32 | "name": "alice", 33 | "flags": [ 34 | "--unsafe-ws-external", 35 | "--force-authoring", 36 | "--", 37 | "--execution=wasm" 38 | ] 39 | } 40 | ] 41 | } 42 | ], 43 | "simpleParachains": [], 44 | "types": {}, 45 | "finalization": true 46 | } 47 | -------------------------------------------------------------------------------- /docker/launch.Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:experimental 2 | # 3 | # Copyright 2021 ChainSafe Systems 4 | # SPDX-License-Identifier: LGPL-3.0-only 5 | # 6 | # This Dockerfile builds the environment of e2e tests 7 | FROM debian:buster-slim 8 | COPY config.json config.json 9 | COPY js/polkadot-launch polkadot-launch 10 | COPY --from=chainsafe/pint /usr/local/bin/pint bin/ 11 | COPY --from=parity/polkadot:v0.9.12 /usr/bin/polkadot bin/ 12 | ENV CARGO_TERM_COLOR=always 13 | RUN apt-get update -y \ 14 | && apt-get install openssl curl git -y \ 15 | && curl -sL https://deb.nodesource.com/setup_15.x | bash - \ 16 | && apt-get -qqy --no-install-recommends install nodejs -y \ 17 | && rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb \ 18 | && rm -f /var/cache/apt/*.bin \ 19 | && cd polkadot-launch \ 20 | && npm install \ 21 | && npm run build 22 | EXPOSE 9988 23 | ENTRYPOINT [ "node", "polkadot-launch/dist/cli.js", "config.json" ] 24 | -------------------------------------------------------------------------------- /docker/release.Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:experimental 2 | # 3 | # Copyright 2021 ChainSafe Systems 4 | # SPDX-License-Identifier: LGPL-3.0-only 5 | # 6 | # Building layer 7 | FROM paritytech/ci-linux:production as builder 8 | COPY . . 9 | ENV CARGO_TERM_COLOR=always 10 | RUN --mount=type=cache,target=/usr/local/cargo/git \ 11 | --mount=type=cache,target=/usr/local/cargo/registry \ 12 | --mount=type=cache,sharing=private,target=target \ 13 | cargo build --release \ 14 | && mv target/release/pint /pint 15 | 16 | # Release 17 | FROM debian:buster-slim 18 | LABEL description="The docker image of PINT" 19 | COPY --from=builder /pint /usr/local/bin/ 20 | RUN useradd -m -u 1000 -U -s /bin/sh -d /pint pint && \ 21 | mkdir -p /pint/.local/share && \ 22 | mkdir /data && \ 23 | chown -R pint:pint /data && \ 24 | ln -s /data /pint/.local/share/pint && \ 25 | rm -rf /usr/bin /usr/sbin 26 | USER pint 27 | # 30333 for p2p traffic 28 | # 9933 for RPC call 29 | # 9944 for Websocket 30 | # 9615 for Prometheus (metrics) 31 | EXPOSE 30333 9933 9944 9615 32 | VOLUME [ "/data" ] 33 | ENTRYPOINT [ "/usr/local/bin/pint" ] 34 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _site 2 | -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | permalink: /404.html 4 | --- 5 | 6 | 19 | 20 |
21 |

404

22 | 23 |

Page not found :(

24 |

The requested page could not be found.

25 |
26 | -------------------------------------------------------------------------------- /docs/assets/css/style.scss: -------------------------------------------------------------------------------- 1 | body { 2 | color: #BBB !important; 3 | font-family: "ubuntu", sans-serif; 4 | line-height: 1.75 !important; 5 | } 6 | 7 | header, footer { 8 | border: 0 !important; 9 | padding: 2% 0 !important; 10 | } 11 | 12 | h1, h2, h3, h4, h5 { 13 | color: #CCC; 14 | font-weight: 500; 15 | padding-top: 2%; 16 | } 17 | 18 | h1.title { 19 | font-size: 110%; 20 | } 21 | 22 | b, strong { 23 | color: #CCC; 24 | } 25 | 26 | a { 27 | color: #e6087b !important; 28 | } 29 | 30 | a:hover { 31 | color: #EEE !important; 32 | text-decoration: none; 33 | transition: 0.1s; 34 | } 35 | 36 | ul, li { 37 | padding: 0.5% 0; 38 | } 39 | 40 | code { 41 | padding: 4px; 42 | } 43 | 44 | pre { 45 | font-size: 17px; 46 | padding: 10px 16px; 47 | } 48 | -------------------------------------------------------------------------------- /docs/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChainSafe/PINT/acb2900a8bf45044aa15c0dd22d2d947f168bf2f/docs/assets/favicon.ico -------------------------------------------------------------------------------- /docs/assets/img/nav-formula.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChainSafe/PINT/acb2900a8bf45044aa15c0dd22d2d947f168bf2f/docs/assets/img/nav-formula.png -------------------------------------------------------------------------------- /docs/assets/img/pint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChainSafe/PINT/acb2900a8bf45044aa15c0dd22d2d947f168bf2f/docs/assets/img/pint.png -------------------------------------------------------------------------------- /docs/assets/img/set-custom-types.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChainSafe/PINT/acb2900a8bf45044aa15c0dd22d2d947f168bf2f/docs/assets/img/set-custom-types.png -------------------------------------------------------------------------------- /docs/getting-started/installation.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Installation 4 | permalink: /getting-started/installation 5 | --- 6 | 7 | # Get Started 8 | 9 | ## Prerequisites 10 | 11 | This project currently builds against Rust nightly-2021-08-01. Assuming you have rustup already insatlled set up your local environment: 12 | 13 | ```shell 14 | rustup install nightly-2021-08-01 15 | rustup target add wasm32-unknown-unknown --toolchain nightly-2021-08-01 16 | rustup override set nightly-2021-08-01 17 | ``` 18 | 19 | ## Build 20 | 21 | Once the development environment is set up, build the node template. This command will build the 22 | [Wasm](https://substrate.dev/docs/en/knowledgebase/advanced/executor#wasm-execution) and 23 | [native](https://substrate.dev/docs/en/knowledgebase/advanced/executor#native-execution) code: 24 | 25 | ```bash 26 | cargo build --release 27 | ``` 28 | 29 | Note: If the build fails with `(signal: 9, SIGKILL: kill)` it has probably run out of memory. Try freeing some memory or build on another machine. 30 | 31 | ## Run 32 | 33 | ### Development Chain 34 | 35 | You can start a standalone development chain with: 36 | 37 | ```bash 38 | cargo run -- --dev --instant-sealing 39 | ``` 40 | 41 | Or if already built: 42 | 43 | ```bash 44 | ./target/release/pint --dev --instant-sealing 45 | ``` 46 | 47 | For [docker](https://github.com/ChainSafe/PINT/blob/main/docker/release.Dockerfile): 48 | 49 | ``` 50 | docker run chainsafe/pint --dev --instant-sealing 51 | ``` 52 | 53 | This will use the [`node/src/chain_spec/dev.rs`](../../node/src/chain_spec/dev.rs) chain spec. 54 | 55 | ### Local Testnet 56 | 57 | Polkadot (release-v0.9.x branch) 58 | 59 | ``` 60 | cargo build --release 61 | 62 | ./target/release/polkadot build-spec --chain rococo-local --raw --disable-default-bootnode > rococo_local.json 63 | 64 | ./target/release/polkadot --chain ./rococo_local.json -d cumulus_relay0 --validator --alice --port 9844 65 | 66 | ./target/release/polkadot --chain ./rococo_local.json -d cumulus_relay1 --validator --bob --port 9955 67 | ``` 68 | 69 | ##### PINT Parachain: 70 | 71 | ``` 72 | # this command assumes the chain spec is in a directory named polkadot that is a sibling of the pint directory 73 | ./target/release/pint --collator --alice --chain pint-dev --ws-port 9945 --parachain-id 200 --rpc-cors all -- --execution wasm --chain ../polkadot/rococo_local.json --ws-port 9977 --rpc-cors all 74 | ``` 75 | 76 | ### Registering on Local Relay Chain 77 | 78 | In order to produce blocks you will need to register the parachain as detailed in the [Substrate Cumulus Workshop](https://substrate.dev/cumulus-workshop/#/en/3-parachains/2-register) by going to 79 | 80 | Developer -> sudo -> paraSudoWrapper -> sudoScheduleParaInitialize(id, genesis) 81 | 82 | Ensure you set the `ParaId` to `200` and the `parachain: Bool` to `Yes`. 83 | 84 | ``` 85 | cargo build --release 86 | # Build the Chain spec 87 | ./target/release/pint build-spec --chain=pint-dev --disable-default-bootnode > ./pint-local-plain.json 88 | # Build the raw file 89 | ./target/release/pint build-spec --chain=./pint-local-plain.json --raw --disable-default-bootnode > ./pint-local.json 90 | 91 | 92 | # export genesis state and wasm 93 | ./target/release/pint export-genesis-state --chain=pint-dev --parachain-id 200 > para-200-genesis 94 | ./target/release/pint export-genesis-wasm --chain=pint-dev > ./para-200.wasm 95 | ``` 96 | 97 | 98 | ### Start a Parachain Node (Collator) 99 | 100 | From the parachain template working directory: 101 | 102 | ```bash 103 | # This assumes a ParaId of 200. Change as needed. 104 | ./target/release/pint \ 105 | -d /tmp/parachain/alice \ 106 | --collator \ 107 | --alice \ 108 | --force-authoring \ 109 | --ws-port 9945 \ 110 | --parachain-id 200 \ 111 | -- \ 112 | --execution wasm \ 113 | --chain pint_local.json 114 | ``` 115 | 116 | 117 | 118 | * [polkadot-launch](https://github.com/paritytech/polkadot-launch) can be run by dropping the proper polkadot binary in the `./bin` folder and 119 | * Run globally 120 | * `polkadot-launch config.json` 121 | * Run locally, navigate into polkadot-launch, 122 | * ``` yarn ``` 123 | * ``` yarn start ``` 124 | 125 | 126 | ## Test 127 | 128 | ### Testing PINT with cargo 129 | 130 | ``` 131 | cargo test --all-features 132 | ``` 133 | 134 | Will run the tests of PINT with cargo. 135 | 136 | ### Testing PINT with polkadot.js 137 | 138 | ``` 139 | # the e2e tests require `polkadot-launch` as a git submodule 140 | git submodule update --recursive 141 | 142 | # install dependencies and run e2e tests 143 | cd js && yarn && yarn e2e 144 | ``` 145 | 146 | Will bootstrap `PINT` with `polkadot-launch` and run all calls of PINT with `polkadot.js` 147 | to test both `PINT` can connect to `rococo` and PINT calls are workable with `polkadot.js`. 148 | 149 | 150 | ## Learn More 151 | 152 | - More detailed instructions to use Cumulus parachains are found in the 153 | [Cumulus Workshop](https://substrate.dev/cumulus-workshop/#/en/3-parachains/2-register). 154 | - Refer to the upstream [Substrate Node Template](https://github.com/substrate-developer-hub/substrate-node-template) 155 | to learn more about the structure of this project, the capabilities it encapsulates and the way in 156 | which those capabilities are implemented. 157 | - Learn more about how a parachain block is added to a finalized chain [here](https://polkadot.network/the-path-of-a-parachain-block/). 158 | -------------------------------------------------------------------------------- /docs/getting-started/resources/developer-resources.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Developer Resources 4 | permalink: /developer-resources/ 5 | --- 6 | 7 | ### Cryptography 8 | 9 | - blake2s used for hashing 10 | - ed25519 (signing) 11 | - ed25519 (curve) 12 | 13 | ### WASM 14 | 15 | - WASM Specification 16 | - Wasm on the Blockchain: The Lesser Evil [blog post] 17 | 18 | ### Polkadot 19 | 20 | - Polkadot Wiki 21 | - Polkadot Consensus Wiki 22 | - Polkadot Runtime Environment Specification (Section 8.2) 23 | - Rust Docs: finality_grandpa 24 | - paritytech/finality_grandpa 25 | - The State of Crypto Interoperability Explained in Pictures 26 | 27 | #### Parachains 28 | 29 | - The Parachain (Blog Post) 30 | - Parachains on Polkadot Wiki 31 | - Parathreads (Blog Post) 32 | - Parathreads on Polkadot Wiki 33 | - The Path of a Parachain Block 34 | - The Path of a Parachain Block (Video) 35 | 36 | ### Substrate 37 | 38 | - Official Substrate Documentation 39 | 40 | 41 | -------------------------------------------------------------------------------- /docs/getting-started/resources/general-resources.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: General Resources 4 | permalink: /getting-started/resources/general-resources 5 | --- 6 | 7 | ## Welcome 8 | 9 | Here you will find resources to help facilitate your learning about _Polkadot_. Don't worry if you are unfamiliar with these terms, the resources listed here assume no prior knowledge about them. 10 | 11 | ## Polkadot 12 | 13 | To start, it would be extremely beneficial to have an understanding of the Polkadot Network. For a high-level introduction to Polkadot, check out the lightpaper. To understand the motivation behind Polkadot's creation and what makes it unique, check out this great blog post A brief summary of everything Substrate and Polkadot. While reading, it would be helpful to note that Substrate. 14 | 15 | ### Additional Resources 16 | 17 | #### Docs 18 | 19 | - Polkadot Wiki 20 | 21 | - Polkadot Paper 22 | 23 | #### Articles 24 | 25 | - How Polkadot tackles the biggest problems facing blockchain innovators - June 7th 2018 26 | 27 | #### Block explorers 28 | 29 | - Polkadot Explorer 30 | 31 | - Polkascan - Polkadot block explorer 32 | 33 | - Polkadot Telemetry Service 34 | 35 | ### Additional Resources 36 | 37 | ## Substrate 38 | 39 | #### Docs 40 | 41 | - Substrate Documentation 42 | 43 | #### Videos 44 | 45 | - Gavin Wood on Substrate at Event Horizon 2018 46 | 47 | - Rob Habermeier presents Parity Substrate 48 | 49 | #### Articles 50 | 51 | - What is Substrate? - July 9th 2018 52 | 53 | - A brief summary of everything Substrate and Polkadot - March 18th 2019 54 | 55 | ## Web3 Foundation 56 | 57 | #### Docs 58 | 59 | - Web3 Foundation's General Grants Program 60 | 61 | #### Articles 62 | 63 | - Why Wy Need Web 3.0 - September 12th 2018 64 | -------------------------------------------------------------------------------- /docs/usage/command-line.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Command-Line 4 | permalink: /usage/command-line/ 5 | --- 6 | 7 | ## Commands 8 | 9 | ### Build 10 | 11 | This will build the 12 | [Wasm Runtime](https://substrate.dev/docs/en/knowledgebase/advanced/executor#wasm-execution) and 13 | [native](https://substrate.dev/docs/en/knowledgebase/advanced/executor#native-execution) of PINT: 14 | 15 | ``` 16 | cargo build --release 17 | ``` 18 | 19 | ### Test 20 | 21 | Run all tests 22 | ``` 23 | cargo test 24 | ``` 25 | 26 | Run all tests, including benchmarks 27 | ``` 28 | cargo test --all-features 29 | ``` 30 | 31 | 32 | ### Start the PINT chain 33 | 34 | ``` 35 | ./target/release/pint --dev --instant-sealing 36 | ``` 37 | 38 | This will seal blocks instantly. The node will never produce blocks 39 | 40 | Use the docker image: 41 | 42 | ``` 43 | docker run -it -p 9944:9944 chainsafe/pint --tmp --dev --instant-sealing --rpc-external --ws-external --rpc-cors all --rpc-methods Unsafe 44 | ``` 45 | 46 | If the [polkadot.js UI](https://polkadot.js.org/apps/#/explorer) fails to connect try adding `--rpc-cors all`. 47 | -------------------------------------------------------------------------------- /docs/usage/configuration.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default title: Configuration permalink: /usage/configuration/ 3 | --- 4 | 5 | # Configuration 6 | 7 | ## Polkadot JS UI 8 | 9 | In order to use [polkadot.js UI](https://polkadot.js.org/apps/#/explorer) to interact with the chain you need to specify 10 | the custom PINT is using by copying the [types.json](../../resources/types.json) object into the input 11 | at `Settings > Devoloper` in the polkadot js UI menu. 12 | 13 |
Add custom types
14 | 15 | ## Chain Spec 16 | 17 | By default, PINT uses the [dev chain spec](../../node/src/chain_spec/dev.rs). 18 | 19 | The `GenesisConfig` configures the initial chain state at genesis. 20 | 21 | Excerpt: 22 | 23 | ```rust 24 | GenesisConfig { 25 | system: SystemConfig { 26 | code: WASM_BINARY.expect("WASM binary was not build, please build it!").to_vec(), 27 | changes_trie_config: Default::default (), 28 | }, 29 | // This ensures the `endowed_accounts` have funds in their accounts 30 | balances: BalancesConfig { balances: endowed_accounts.iter().cloned().map( | k| (k, 1 < < 12)).collect() }, 31 | // This configures the comittee 32 | committee: CommitteeConfig { council_members: council_members.clone(), ..Default::default () }, 33 | // all council members can create feeds and no feeds in genesis 34 | chainlink_feed: ChainlinkFeedConfig { feeds: Default::default(), pallet_admin: Some(root_key.clone()), feed_creators: council_members }, 35 | sudo: SudoConfig { key: root_key }, 36 | parachain_info: ParachainInfoConfig { parachain_id: id }, 37 | } 38 | ``` 39 | 40 | To run the chain with a custom chainspec we need to provide the path to your chainspec json file: 41 | 42 | *NOTE:* the id of your custom chain spec should contain `dev` in order to run it as standalone chain. 43 | 44 | ``` 45 | ./target/release/pint --tmp --chain= 46 | ``` 47 | 48 | Read more about substrate's [Chain Specification](https://substrate.dev/docs/en/knowledgebase/integrate/chain-spec) 49 | and [creating private networks](https://substrate.dev/docs/en/tutorials/start-a-private-network) 50 | 51 | #### Build the chainspec 52 | 53 | ``` 54 | ./target/release/pint build-spec \ 55 | --disable-default-bootnode > pint-local-plain.json 56 | ``` 57 | 58 | #### Build the raw chainspec file 59 | ``` 60 | ./target/release/pint build-spec \ 61 | --chain=./pint-local-plain.json \ 62 | --raw --disable-default-bootnode > pint-local-raw.json 63 | ``` 64 | -------------------------------------------------------------------------------- /js/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 4, 3 | "overrides": [ 4 | { 5 | "files": "*.json", 6 | "options": { 7 | "tabWidth": 2 8 | } 9 | }, 10 | { 11 | "files": ".prettierrc", 12 | "options": { 13 | "tabWidth": 2 14 | } 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /js/e2e/README.md: -------------------------------------------------------------------------------- 1 | # E2E 2 | 3 | E2E tests for PINT 4 | 5 | This package will traverse all APIs provided written in the config 6 | 7 | 8 | ## LICENSE 9 | 10 | GNU-v3 11 | -------------------------------------------------------------------------------- /js/e2e/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@pint/e2e", 3 | "version": "1.0.0", 4 | "description": "E2E tests for PINT", 5 | "main": "index.js", 6 | "repository": "https://github.com/ChainSafe/PINT", 7 | "author": "ChainSafe", 8 | "license": "GNU-v3", 9 | "private": true, 10 | "devDependencies": { 11 | "@types/bn.js": "^5.1.0", 12 | "@types/node": "^15.3.1", 13 | "ts-node": "^10.0.0", 14 | "tslint": "^6.1.3", 15 | "typescript": "^4.2.4" 16 | }, 17 | "dependencies": { 18 | "@open-web3/orml-types": "^0.9.3", 19 | "@pint/types": "^1.0.0", 20 | "@polkadot/api": "^6.8.1", 21 | "@polkadot/keyring": "^7.8.2", 22 | "@polkadot/types": "^6.8.1", 23 | "@polkadot/util-crypto": "^7.8.2", 24 | "bn.js": "^5.2.0", 25 | "find-up": "^5.0.0" 26 | }, 27 | "scripts": { 28 | "start": "ts-node index.ts", 29 | "build": "tsc --strict", 30 | "lint": "tsc --noEmit --strict && tslint --project ./tsconfig.json" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /js/e2e/src/config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Config of E2E tests 3 | */ 4 | import { ApiPromise } from "@polkadot/api"; 5 | import { KeyringPair } from "@polkadot/keyring/types"; 6 | import { Extrinsic } from "./extrinsic"; 7 | 8 | /** 9 | * The config of e2e tests 10 | */ 11 | export interface Config { 12 | api: ApiPromise; 13 | pair: KeyringPair; 14 | exs: Extrinsic[]; 15 | config: ExtrinsicConfig; 16 | } 17 | 18 | /** 19 | * The config of extrinsics 20 | */ 21 | export interface ExtrinsicConfig { 22 | alice: KeyringPair; 23 | bob: KeyringPair; 24 | charlie: KeyringPair; 25 | dave: KeyringPair; 26 | ziggy: KeyringPair; 27 | } 28 | 29 | /** 30 | * Extrinsic interface 31 | */ 32 | export interface IExtrinsic { 33 | // extrinsic id 34 | id?: string; 35 | // use signed origin 36 | signed?: KeyringPair; 37 | pallet: string; 38 | call: string; 39 | args: any[]; 40 | shared?: () => Promise; 41 | verify?: (shared?: any) => Promise; 42 | proposal?: boolean; 43 | /// Required calls or functions before this extrinsic 44 | required?: string[]; 45 | /// Calls or functions with this extrinsic 46 | with?: IExtrinsic[]; 47 | } 48 | -------------------------------------------------------------------------------- /js/e2e/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * E2E tests for PINT 3 | */ 4 | import Runner from "./runner"; 5 | export { Config, ExtrinsicConfig, IExtrinsic } from "./config"; 6 | export * as Launch from "./launch"; 7 | export { Extrinsic } from "./extrinsic"; 8 | export { assert, expandId, waitBlock } from "./util"; 9 | export { Runner }; 10 | -------------------------------------------------------------------------------- /js/e2e/src/launch.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * pint-launch 3 | */ 4 | import fs from "fs"; 5 | import findUp from "find-up"; 6 | import path from "path"; 7 | import { fork, ChildProcess, StdioOptions, spawn } from "child_process"; 8 | 9 | /** 10 | * Launch PINT locally 11 | * 12 | * @param stdio {StdioOptions} 13 | * @returns {Promise} 14 | */ 15 | export async function local(stdio?: StdioOptions): Promise { 16 | return fork("js/polkadot-launch/src/cli.ts", ["config.json"], { 17 | cwd: path.resolve(String(await findUp("Cargo.toml")), ".."), 18 | killSignal: "SIGINT", 19 | stdio, 20 | } as any); 21 | } 22 | 23 | /** 24 | * Launch PINT via docker (CI) 25 | * 26 | * @param stdio {StdioOptions} 27 | * @returns {Promise} 28 | */ 29 | export async function docker(stdio?: StdioOptions): Promise { 30 | return spawn( 31 | "sudo", 32 | [ 33 | "docker", 34 | "run", 35 | "--name", 36 | "launch", 37 | "-p", 38 | "9988:9988", 39 | "-p", 40 | "9966:9966", 41 | "-p", 42 | "9999:9999", 43 | "--ip", 44 | "0.0.0.0", 45 | "launch", 46 | ], 47 | { 48 | stdio, 49 | } 50 | ); 51 | } 52 | 53 | /** 54 | * Launch PINT via local or docker 55 | * 56 | * @param stdio {StdioOptions} 57 | * @returns {Promise} 58 | */ 59 | export async function launch(stdio?: StdioOptions): Promise { 60 | const root = await findUp("Cargo.toml"); 61 | if (fs.existsSync(path.resolve(String(root), "../bin/pint"))) { 62 | return local(stdio); 63 | } else { 64 | return docker(stdio); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /js/e2e/src/util.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Utils 3 | */ 4 | import { IExtrinsic } from "./config"; 5 | 6 | export function assert(r: boolean, msg: string): string | void { 7 | if (!r) { 8 | return msg; 9 | } 10 | } 11 | 12 | /** 13 | * Expand Id of extrinsic 14 | */ 15 | export function expandId(e: IExtrinsic): IExtrinsic { 16 | if (!e.id) e.id = `${e.pallet}.${e.call}`; 17 | 18 | if (e.with) { 19 | for (const r of e.with) { 20 | if (typeof r !== "function") { 21 | expandId(r); 22 | } 23 | } 24 | } 25 | 26 | return e; 27 | } 28 | 29 | /** 30 | * Wait for n blocks 31 | * 32 | * The current gap of producing a block is 4s, 33 | * we use 5s here. 34 | * 35 | * @param {number} block 36 | * @returns {Promise} 37 | */ 38 | export async function waitBlock(block: number): Promise { 39 | return new Promise((resolve) => setTimeout(resolve, block * 12000)); 40 | } 41 | -------------------------------------------------------------------------------- /js/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "indent": [true, "spaces", 2], 3 | "compilerOptions": { 4 | "allowSyntheticDefaultImports": true, 5 | "baseUrl": ".", 6 | "declaration": true, 7 | "esModuleInterop": true, 8 | "outDir": "lib", 9 | "module": "commonjs", 10 | "moduleResolution": "node", 11 | "noImplicitAny": true, 12 | "resolveJsonModule": true, 13 | "sourceMap": true, 14 | "skipLibCheck": true, 15 | "target": "es6" 16 | }, 17 | "include": ["index.ts", "src/**/*"], 18 | "exclude": ["node_modules"] 19 | } 20 | -------------------------------------------------------------------------------- /js/e2e/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rules": { 4 | "curly": [true, "ignore-same-line"], 5 | "max-classes-per-file": false, 6 | "max-line-length": { 7 | "options": [120] 8 | }, 9 | "new-parens": true, 10 | "no-arg": true, 11 | "no-bitwise": true, 12 | "no-conditional-assignment": true, 13 | "no-consecutive-blank-lines": false, 14 | "no-console": false 15 | }, 16 | "linterOptions": { 17 | "exclude": [] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /js/finalize/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Test the finalization of parachain intergration 3 | */ 4 | import fs from "fs"; 5 | import path from "path"; 6 | import { Launch } from "@pint/e2e/src"; 7 | import findUp from "find-up"; 8 | import { ChildProcess, spawn } from "child_process"; 9 | 10 | // Message of launching complete 11 | const LAUNCH_COMPLETE: string = "POLKADOT LAUNCH COMPLETE"; 12 | 13 | // PINT finalization regex 14 | export const PINT_FINALIZE: RegExp = /\[Parachain\].*finalized #(\d)/; 15 | 16 | // Kill subprocesses 17 | function killAll(ps: ChildProcess, exitCode: number) { 18 | try { 19 | ps.send && !ps.killed && ps.send("exit"); 20 | ps.kill("SIGINT"); 21 | } catch (e) { 22 | if (e.code !== "EPERM") { 23 | process.stdout.write(e); 24 | process.exit(2); 25 | } 26 | } 27 | 28 | process.exit(exitCode); 29 | } 30 | 31 | /** 32 | * Tail file and done when got expected message 33 | */ 34 | async function tail( 35 | file: string, 36 | match: (s: string) => boolean 37 | ): Promise { 38 | const root = await findUp("Cargo.toml"); 39 | 40 | return new Promise(async (resolve) => { 41 | const ps = fs.existsSync(path.resolve(String(root), "../bin/pint")) 42 | ? spawn("tail", ["-f", file], { 43 | cwd: path.resolve(String(root), ".."), 44 | stdio: "pipe", 45 | }) 46 | : spawn("docker", ["exec", "launch", "tail", "-f", `${file}`], { 47 | stdio: "pipe", 48 | }); 49 | 50 | ps.stdout.on("data", (chunk: Buffer) => { 51 | chunk && match(chunk.toString()) && resolve(null); 52 | }); 53 | 54 | ps.stderr.on("data", (chunk: Buffer) => { 55 | process.stderr.write(chunk); 56 | process.exit(1); 57 | }); 58 | }); 59 | } 60 | 61 | /** 62 | * Entrypoint 63 | */ 64 | async function main() { 65 | const ps = await Launch.launch("pipe"); 66 | ps.stdout.on("data", async (chunk: Buffer) => { 67 | process.stdout.write(chunk.toString()); 68 | if (chunk.includes(LAUNCH_COMPLETE)) { 69 | await tail("9988.log", (chunk: string): boolean => { 70 | process.stdout.write(chunk); 71 | const match = chunk.match(PINT_FINALIZE); 72 | return ( 73 | match && match.length == 2 && Number.parseInt(match[1]) > 0 74 | ); 75 | }); 76 | 77 | console.log("FINALIZE SUCCEED!"); 78 | process.exit(0); 79 | } 80 | }); 81 | 82 | // Kill all processes when exiting. 83 | process.on("exit", () => { 84 | console.log("-> exit polkadot-launch..."); 85 | killAll(ps, process.exitCode); 86 | }); 87 | 88 | // Log errors 89 | ps.stderr.on("data", (chunk: Buffer) => 90 | process.stderr.write(chunk.toString()) 91 | ); 92 | } 93 | 94 | (() => { 95 | main(); 96 | })(); 97 | -------------------------------------------------------------------------------- /js/finalize/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@pint/finalization", 3 | "version": "1.0.0", 4 | "description": "Test the finalization in parachain intergration", 5 | "main": "index.js", 6 | "license": "MIT", 7 | "private": true, 8 | "devDependencies": { 9 | "@types/node": "^15.3.1", 10 | "ts-node": "^10.0.0", 11 | "tslint": "^6.1.3", 12 | "typescript": "^4.2.4" 13 | }, 14 | "dependencies": { 15 | "@pint/e2e": "^1.0.0", 16 | "find-up": "^5.0.0" 17 | }, 18 | "scripts": { 19 | "start": "ts-node index.ts", 20 | "build": "tsc --strict", 21 | "lint": "tsc --noEmit --strict && tslint --project ./tsconfig.json" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /js/finalize/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "indent": [true, "spaces", 2], 3 | "compilerOptions": { 4 | "allowSyntheticDefaultImports": true, 5 | "baseUrl": ".", 6 | "declaration": true, 7 | "esModuleInterop": true, 8 | "outDir": "lib", 9 | "module": "commonjs", 10 | "moduleResolution": "node", 11 | "noImplicitAny": true, 12 | "resolveJsonModule": true, 13 | "sourceMap": true, 14 | "skipLibCheck": true, 15 | "target": "es6" 16 | }, 17 | "include": ["index.ts", "src/**/*"], 18 | "exclude": ["node_modules"] 19 | } 20 | -------------------------------------------------------------------------------- /js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "workspaces": [ 4 | "e2e", 5 | "pint-types-bundle", 6 | "finalize" 7 | ], 8 | "scripts": { 9 | "e2e": "ts-node e2e/index.ts", 10 | "update-pint-types": "ts-node scripts/update_pint_types.ts" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /js/pint-types-bundle/.gitignore: -------------------------------------------------------------------------------- 1 | # ignore files generated by typescript 2 | dist/ 3 | node_modules/ 4 | -------------------------------------------------------------------------------- /js/pint-types-bundle/README.md: -------------------------------------------------------------------------------- 1 | # PINT Types 2 | 3 | Substrate types used in PINT parachain. 4 | 5 | 6 | ## Usage 7 | 8 | Import the types in your JS or TS app. 9 | 10 | ```ts 11 | import definitions from "@pint/types"; 12 | ``` -------------------------------------------------------------------------------- /js/pint-types-bundle/chainlink.json: -------------------------------------------------------------------------------- 1 | { 2 | "Address": "MultiAddress", 3 | "LookupSource": "MultiAddress", 4 | "FeedId": "u32", 5 | "RoundId": "u32", 6 | "Value": "u128", 7 | "FeedConfig": { 8 | "owner": "AccountId", 9 | "pending_owner": "Option", 10 | "submission_value_bounds": "(Value, Value)", 11 | "submission_count_bounds": "(u32, u32)", 12 | "payment": "Balance", 13 | "timeout": "BlockNumber", 14 | "decimals": "u8", 15 | "description": "Vec", 16 | "restart_delay": "RoundId", 17 | "reporting_round": "RoundId", 18 | "latest_round": "RoundId", 19 | "first_valid_round": "Option", 20 | "oracle_count": "u32", 21 | "pruning_window": "RoundId", 22 | "next_round_to_prune": "RoundId", 23 | "debt": "Balance", 24 | "max_debt": "Option" 25 | }, 26 | "FeedConfigOf": "FeedConfig", 27 | "Round": { 28 | "started_at": "BlockNumber", 29 | "answer": "Option", 30 | "updated_at": "Option", 31 | "answered_in_round": "Option" 32 | }, 33 | "RoundOf": "Round", 34 | "RoundDetails": { 35 | "submissions": "Vec", 36 | "submission_count_bounds": "(u32, u32)", 37 | "payment": "Balance", 38 | "timeout": "BlockNumber" 39 | }, 40 | "RoundDetailsOf": "RoundDetails", 41 | "OracleMeta": { 42 | "withdrawable": "Balance", 43 | "admin": "AccountId", 44 | "pending_admin": "Option" 45 | }, 46 | "OracleMetaOf": "OracleMeta", 47 | "OracleStatus": { 48 | "starting_round": "RoundId", 49 | "ending_round": "Option", 50 | "last_reported_round": "Option", 51 | "last_started_round": "Option", 52 | "latest_submission": "Option" 53 | }, 54 | "OracleStatusOf": "OracleStatus", 55 | "Requester": { 56 | "delay": "RoundId", 57 | "last_started_round": "Option" 58 | }, 59 | "RoundData": { 60 | "started_at": "BlockNumber", 61 | "answer": "Value", 62 | "updated_at": "BlockNumber", 63 | "answered_in_round": "RoundId" 64 | }, 65 | "RoundDataOf": "RoundData", 66 | "SubmissionBounds": "(u32, u32)" 67 | } 68 | -------------------------------------------------------------------------------- /js/pint-types-bundle/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@pint/types", 3 | "version": "1.0.0", 4 | "description": "Bundled types to instantiate the Polkadot JS api with PINT", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "prepublish": "tsc", 8 | "scripts": { 9 | "build": "tsc" 10 | }, 11 | "keywords": ["pint", "types", "polkadot", "api"], 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/ChainSafe/PINT.git" 15 | }, 16 | "author": "ChainSafe Systems", 17 | "license": "GPL-3.0-only", 18 | "dependencies": { 19 | "@polkadot/keyring": "^7.8.2", 20 | "@polkadot/types": "^6.8.1" 21 | }, 22 | "devDependencies": { 23 | "typescript": "^4.2.4" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /js/pint-types-bundle/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "indent": [true, "spaces", 2], 3 | "compilerOptions": { 4 | "target": "es5", 5 | "module": "commonjs", 6 | "lib": ["es2017", "es7", "es6", "dom"], 7 | "declaration": true, 8 | "outDir": "dist", 9 | "strict": true, 10 | "esModuleInterop": true, 11 | "resolveJsonModule": true 12 | }, 13 | "exclude": ["node_modules", "dist"] 14 | } 15 | -------------------------------------------------------------------------------- /js/scripts/update_pint_types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Exports `pint-types-bundle` to `/resources/types.json` 3 | */ 4 | 5 | import fs from "fs"; 6 | import path from "path"; 7 | import { definitions } from "../pint-types-bundle/index"; 8 | 9 | (async () => { 10 | const types = (definitions.types as any)[0].types; 11 | if (types.length === 0) { 12 | throw "No PINT types provided"; 13 | } 14 | 15 | const target = path.resolve(__dirname, "../../resources/types.json"); 16 | fs.writeFileSync(target, JSON.stringify(types, null, 2)); 17 | console.log("Updated \x1b[36m/resources/types.json\x1b[0m !"); 18 | })(); 19 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 ChainSafe Systems 2 | # SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | site_name: PINT Docs 5 | site_description: The Official Documentation for PINT | A Polkadot ecosystem index for investors 6 | 7 | repo_name: chainsafe/pint 8 | repo_url: https://github.com/ChainSafe/pint 9 | edit_uri: edit/development/docs/ 10 | 11 | # Configuration 12 | markdown_extensions: 13 | - meta 14 | - admonition 15 | - codehilite 16 | - toc: 17 | permalink: true 18 | 19 | theme: 20 | name: material 21 | palette: 22 | primary: brown 23 | accent: yellow 24 | theme: 25 | # Light mode 26 | - media: "(prefers-color-scheme: light)" 27 | scheme: default 28 | primary: brown 29 | accent: yellow 30 | toggle: 31 | icon: material/toggle-switch-off-outline 32 | name: Switch to dark mode 33 | # Dark mode 34 | - media: "(prefers-color-scheme: dark)" 35 | scheme: slate 36 | primary: brown 37 | accent: yellow 38 | toggle: 39 | icon: material/toggle-switch 40 | name: Switch to light mode 41 | favicon: ./assets/favicon.ico 42 | features: 43 | # - navigation.instant 44 | - navigation.tracking 45 | - navigation.sections 46 | - navigation.tabs 47 | - navigation.tabs.sticky 48 | nav: 49 | - Getting Started: 50 | - Overview: ./index.md 51 | - Architecture: ./getting-started/overview/architecture.md 52 | - Installation: ./getting-started/installation.md 53 | - General Resources: ./getting-started/resources/general-resources.md 54 | - Developer Resources: ./getting-started/resources/developer-resources.md 55 | - Usage: 56 | - Command Line: ./usage/command-line.md 57 | - Configuration: ./usage/configuration.md 58 | - API Docs: ./api/pint_runtime_dev/index.html 59 | # - Testing and Debugging: 60 | # - Test Suite: ./testing-and-debugging/test-suite.md 61 | # - Debugging: ./testing-and-debugging/debugging.md 62 | # - Contributing: 63 | # - Overview: ./contributing.md 64 | extra: 65 | social: 66 | - icon: fontawesome/brands/github-alt 67 | link: https://github.com/ChainSafe/pint 68 | - icon: fontawesome/brands/twitter 69 | link: https://twitter.com/ChainSafeth 70 | -------------------------------------------------------------------------------- /node/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; 5 | 6 | fn main() { 7 | generate_cargo_keys(); 8 | rerun_if_git_head_changed(); 9 | } 10 | -------------------------------------------------------------------------------- /node/src/chain_spec/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | use primitives::{AccountId, AccountPublic}; 4 | use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup}; 5 | use serde::{Deserialize, Serialize}; 6 | use sp_consensus_aura::sr25519::AuthorityId as AuraId; 7 | use sp_core::{Pair, Public}; 8 | use sp_runtime::traits::IdentifyAccount; 9 | 10 | pub mod dev; 11 | #[cfg(feature = "pint")] 12 | pub mod pint; 13 | #[cfg(feature = "shot")] 14 | pub mod shot; 15 | 16 | /// The extensions for the [`DevChainSpec`]. 17 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)] 18 | #[serde(deny_unknown_fields)] 19 | pub struct Extensions { 20 | /// The relay chain of the Parachain. 21 | pub relay_chain: String, 22 | /// The id of the Parachain. 23 | pub para_id: u32, 24 | } 25 | 26 | impl Extensions { 27 | /// Try to get the extension from the given `ChainSpec`. 28 | pub fn try_get(chain_spec: &dyn sc_service::ChainSpec) -> Option<&Self> { 29 | sc_chain_spec::get_extension(chain_spec.extensions()) 30 | } 31 | } 32 | 33 | /// Helper function to generate a crypto pair from seed 34 | pub fn get_from_seed(seed: &str) -> ::Public { 35 | TPublic::Pair::from_string(&format!("//{}", seed), None).expect("static values are valid; qed").public() 36 | } 37 | 38 | /// Helper function to generate an account ID from seed 39 | pub fn get_account_id_from_seed(seed: &str) -> AccountId 40 | where 41 | AccountPublic: From<::Public>, 42 | { 43 | AccountPublic::from(get_from_seed::(seed)).into_account() 44 | } 45 | 46 | /// Generate collator keys from seed. 47 | /// 48 | /// This function's return type must always match the session keys of the chain 49 | /// in tuple format. 50 | pub fn get_collator_keys_from_seed(seed: &str) -> AuraId { 51 | get_from_seed::(seed) 52 | } 53 | -------------------------------------------------------------------------------- /node/src/cli.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | use crate::chain_spec; 5 | use cumulus_client_cli; 6 | use sc_cli; 7 | use std::path::PathBuf; 8 | use structopt::StructOpt; 9 | 10 | /// Sub-commands supported by the collator. 11 | #[derive(Debug, StructOpt)] 12 | pub enum Subcommand { 13 | /// Export the genesis state of the parachain. 14 | #[structopt(name = "export-genesis-state")] 15 | ExportGenesisState(ExportGenesisStateCommand), 16 | 17 | /// Export the genesis wasm of the parachain. 18 | #[structopt(name = "export-genesis-wasm")] 19 | ExportGenesisWasm(ExportGenesisWasmCommand), 20 | 21 | /// Build a chain specification. 22 | BuildSpec(sc_cli::BuildSpecCmd), 23 | 24 | /// Validate blocks. 25 | CheckBlock(sc_cli::CheckBlockCmd), 26 | 27 | /// Export blocks. 28 | ExportBlocks(sc_cli::ExportBlocksCmd), 29 | 30 | /// Export the state of a given block into a chain spec. 31 | ExportState(sc_cli::ExportStateCmd), 32 | 33 | /// Import blocks. 34 | ImportBlocks(sc_cli::ImportBlocksCmd), 35 | 36 | /// Remove the whole chain. 37 | PurgeChain(cumulus_client_cli::PurgeChainCmd), 38 | 39 | /// Revert the chain to a previous state. 40 | Revert(sc_cli::RevertCmd), 41 | 42 | /// The custom benchmark subcommmand benchmarking runtime pallets. 43 | #[structopt(name = "benchmark", about = "Benchmark runtime pallets.")] 44 | Benchmark(frame_benchmarking_cli::BenchmarkCmd), 45 | } 46 | 47 | /// Command for exporting the genesis state of the parachain 48 | #[derive(Debug, StructOpt)] 49 | pub struct ExportGenesisStateCommand { 50 | /// Output file name or stdout if unspecified. 51 | #[structopt(parse(from_os_str))] 52 | pub output: Option, 53 | 54 | /// Id of the parachain this state is for. 55 | /// 56 | /// Default: 100 57 | #[structopt(long)] 58 | pub parachain_id: Option, 59 | 60 | /// Write output in binary. Default is to write in hex. 61 | #[structopt(short, long)] 62 | pub raw: bool, 63 | 64 | /// The name of the chain for that the genesis state should be exported. 65 | #[structopt(short, long)] 66 | pub chain: Option, 67 | } 68 | 69 | /// Command for exporting the genesis wasm file. 70 | #[derive(Debug, StructOpt)] 71 | pub struct ExportGenesisWasmCommand { 72 | /// Output file name or stdout if unspecified. 73 | #[structopt(parse(from_os_str))] 74 | pub output: Option, 75 | 76 | /// Write output in binary. Default is to write in hex. 77 | #[structopt(short, long)] 78 | pub raw: bool, 79 | 80 | /// The name of the chain for that the genesis wasm file should be exported. 81 | #[structopt(long)] 82 | pub chain: Option, 83 | } 84 | 85 | #[derive(Debug, StructOpt)] 86 | #[structopt(settings = &[ 87 | structopt::clap::AppSettings::GlobalVersion, 88 | structopt::clap::AppSettings::ArgsNegateSubcommands, 89 | structopt::clap::AppSettings::SubcommandsNegateReqs, 90 | ])] 91 | pub struct Cli { 92 | #[structopt(subcommand)] 93 | pub subcommand: Option, 94 | 95 | #[structopt(flatten)] 96 | pub run: cumulus_client_cli::RunCmd, 97 | 98 | /// Relaychain arguments 99 | #[structopt(raw = true)] 100 | pub relaychain_args: Vec, 101 | 102 | /// Instant block sealing 103 | /// 104 | /// Can only be used with `--dev` 105 | #[structopt(long = "instant-sealing")] 106 | pub instant_sealing: bool, 107 | } 108 | 109 | #[derive(Debug)] 110 | pub struct RelayChainCli { 111 | /// The actual relay chain cli object. 112 | pub base: polkadot_cli::RunCmd, 113 | 114 | /// Optional chain id that should be passed to the relay chain. 115 | pub chain_id: Option, 116 | 117 | /// The base path that should be used by the relay chain. 118 | pub base_path: Option, 119 | } 120 | 121 | impl RelayChainCli { 122 | /// Parse the relay chain CLI parameters using the para chain 123 | /// `Configuration`. 124 | pub fn new<'a>( 125 | para_config: &sc_service::Configuration, 126 | relay_chain_args: impl Iterator, 127 | ) -> Self { 128 | let extension = chain_spec::Extensions::try_get(&*para_config.chain_spec); 129 | let chain_id = extension.map(|e| e.relay_chain.clone()); 130 | let base_path = para_config.base_path.as_ref().map(|x| x.path().join("polkadot")); 131 | Self { base_path, chain_id, base: polkadot_cli::RunCmd::from_iter(relay_chain_args) } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /node/src/instant_finalize.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | use sc_consensus::BlockImport; 5 | use sp_runtime::traits::Block as BlockT; 6 | 7 | pub struct InstantFinalizeBlockImport(I); 8 | 9 | impl InstantFinalizeBlockImport { 10 | /// Create a new instance. 11 | pub fn new(inner: I) -> Self { 12 | Self(inner) 13 | } 14 | } 15 | 16 | #[async_trait::async_trait] 17 | impl BlockImport for InstantFinalizeBlockImport 18 | where 19 | Block: BlockT, 20 | I: BlockImport + Send, 21 | { 22 | type Error = I::Error; 23 | type Transaction = I::Transaction; 24 | 25 | async fn check_block( 26 | &mut self, 27 | block: sc_consensus::BlockCheckParams, 28 | ) -> Result { 29 | self.0.check_block(block).await 30 | } 31 | 32 | async fn import_block( 33 | &mut self, 34 | mut block_import_params: sc_consensus::BlockImportParams, 35 | cache: std::collections::HashMap>, 36 | ) -> Result { 37 | block_import_params.finalized = true; 38 | self.0.import_block(block_import_params, cache).await 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /node/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | pub mod chain_spec; 5 | pub mod client; 6 | pub mod instant_finalize; 7 | pub mod service; 8 | -------------------------------------------------------------------------------- /node/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | //! Substrate Parachain Node Template CLI 5 | 6 | #![warn(missing_docs)] 7 | 8 | mod chain_spec; 9 | #[macro_use] 10 | mod service; 11 | mod cli; 12 | mod client; 13 | mod command; 14 | mod instant_finalize; 15 | 16 | fn main() -> sc_cli::Result<()> { 17 | command::run() 18 | } 19 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PINT", 3 | "lockfileVersion": 2, 4 | "requires": true, 5 | "packages": {} 6 | } 7 | -------------------------------------------------------------------------------- /pallets/asset-index/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ['ChainSafe Systems'] 3 | description = 'FRAME pallet to implement PINT asset index.' 4 | edition = '2018' 5 | license = 'LGPL-3.0-only' 6 | name = 'pallet-asset-index' 7 | readme = 'README.md' 8 | repository = 'https://github.com/ChainSafe/PINT/' 9 | version = '0.0.1' 10 | 11 | [dependencies] 12 | serde = { version = "1.0.130", features = ["derive"], optional = true } 13 | codec = { package = "parity-scale-codec", version = "2.3.1", default-features = false } 14 | scale-info = { version = "1.0", default-features = false, features = ["derive"] } 15 | 16 | # Substrate Dependencies 17 | sp-core = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 18 | frame-support = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 19 | frame-system = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 20 | frame-benchmarking = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false, optional = true } 21 | 22 | # Polkadot Dependencies 23 | polkadot-parachain = { git = 'https://github.com/paritytech/polkadot', branch = 'release-v0.9.13', default-features = false } 24 | xcm = { git = 'https://github.com/paritytech/polkadot', branch = 'release-v0.9.13', default-features = false } 25 | xcm-executor = { git = 'https://github.com/paritytech/polkadot', branch = 'release-v0.9.13', default-features = false } 26 | 27 | # PINT dependencies 28 | pallet-chainlink-feed = { git = 'https://github.com/smartcontractkit/chainlink-polkadot', branch = 'polkadot-v0.9.13', default-features = false } 29 | pallet-price-feed = { path = "../price-feed", default-features = false } 30 | primitives = { path = "../../primitives/primitives", default-features = false } 31 | 32 | # ORML Dependencies 33 | orml-traits = { git = 'https://github.com/open-web3-stack/open-runtime-module-library', branch = 'master', default-features = false } 34 | 35 | [dev-dependencies] 36 | serde = "1.0.130" 37 | 38 | sp-io = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 39 | sp-runtime = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 40 | sp-std = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 41 | 42 | pallet-balances = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 43 | 44 | pallet-saft-registry = { path = "../saft-registry" } 45 | 46 | orml-tokens = { git = 'https://github.com/open-web3-stack/open-runtime-module-library', branch = 'master' } 47 | rand = "0.8.4" 48 | 49 | [features] 50 | default = ['std'] 51 | std = [ 52 | 'serde', 53 | 'codec/std', 54 | 'sp-core/std', 55 | 'frame-support/std', 56 | 'frame-system/std', 57 | 'pallet-price-feed/std', 58 | 'primitives/std', 59 | 60 | 'polkadot-parachain/std', 61 | 'xcm/std', 62 | 'xcm-executor/std', 63 | 64 | 'orml-traits/std', 65 | ] 66 | runtime-benchmarks = [ 67 | 'frame-benchmarking', 68 | 'frame-support/runtime-benchmarks', 69 | 'pallet-price-feed/runtime-benchmarks', 70 | # 'pallet-chainlink-feed/runtime-benchmarks', 71 | 'primitives/runtime-benchmarks', 72 | ] 73 | 74 | [package.metadata.docs.rs] 75 | targets = ['x86_64-unknown-linux-gnu'] 76 | -------------------------------------------------------------------------------- /pallets/asset-index/README.md: -------------------------------------------------------------------------------- 1 | License: LGPL-3.0-only -------------------------------------------------------------------------------- /pallets/asset-index/rpc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ['ChainSafe Systems'] 3 | description = 'RPC for the asset-index pallet.' 4 | edition = '2018' 5 | license = 'LGPL-3.0-only' 6 | name = 'pallet-asset-index-rpc' 7 | readme = 'README.md' 8 | repository = 'https://github.com/ChainSafe/PINT/' 9 | version = '0.0.1' 10 | 11 | [dependencies] 12 | serde = { version = "1.0.130", features = ["derive"] } 13 | codec = { package = "parity-scale-codec", version = "2.3.1" } 14 | jsonrpc-core = "18.0.0" 15 | jsonrpc-core-client = "18.0.0" 16 | jsonrpc-derive = "18.0.0" 17 | sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 18 | sp-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 19 | sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 20 | 21 | # PINT RPC 22 | pallet-asset-index-rpc-runtime-api = { path = "runtime-api" } 23 | 24 | # PINT dependencies 25 | primitives = { path = "../../../primitives/primitives", default-features = false } 26 | 27 | [dev-dependencies] 28 | serde_json = "1.0.69" 29 | 30 | [package.metadata.docs.rs] 31 | targets = ['x86_64-unknown-linux-gnu'] 32 | -------------------------------------------------------------------------------- /pallets/asset-index/rpc/runtime-api/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ['ChainSafe Systems'] 3 | description = 'RPC runtime API for the asset-index pallet.' 4 | edition = '2018' 5 | license = 'LGPL-3.0-only' 6 | name = 'pallet-asset-index-rpc-runtime-api' 7 | readme = 'README.md' 8 | repository = 'https://github.com/ChainSafe/PINT/' 9 | version = '0.0.1' 10 | 11 | [dependencies] 12 | serde = { version = "1.0.130", optional = true, features = ["derive"] } 13 | codec = { package = "parity-scale-codec", version = "2.3.1", default-features = false } 14 | scale-info = { version = "1.0", default-features = false, features = ["derive"] } 15 | sp-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13", default-features = false } 16 | sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13", default-features = false } 17 | sp-std = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13", default-features = false } 18 | 19 | # PINT dependencies 20 | primitives = { path = "../../../../primitives/primitives", default-features = false } 21 | 22 | [features] 23 | default = ["std"] 24 | std = [ 25 | "serde", 26 | "codec/std", 27 | "sp-api/std", 28 | "sp-runtime/std", 29 | "sp-std/std", 30 | "primitives/std", 31 | ] 32 | 33 | [package.metadata.docs.rs] 34 | targets = ['x86_64-unknown-linux-gnu'] 35 | -------------------------------------------------------------------------------- /pallets/asset-index/rpc/runtime-api/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | //! Runtime API definition for the asset-index pallet. 5 | 6 | #![cfg_attr(not(feature = "std"), no_std)] 7 | // The `too_many_arguments` warning originates from `decl_runtime_apis` macro. 8 | #![allow(clippy::too_many_arguments)] 9 | #![allow(clippy::unnecessary_mut_passed)] 10 | 11 | use codec::Codec; 12 | use sp_std::prelude::*; 13 | 14 | use primitives::Ratio; 15 | 16 | sp_api::decl_runtime_apis! { 17 | pub trait AssetIndexApi where 18 | AccountId: Codec, 19 | AssetId: Codec, 20 | Balance: Codec, 21 | { 22 | fn get_nav() -> Ratio; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pallets/asset-index/rpc/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | //! RPC interface for the asset-index pallet. 5 | 6 | use codec::Codec; 7 | use jsonrpc_core::{Error as RpcError, ErrorCode, Result}; 8 | use jsonrpc_derive::rpc; 9 | use primitives::Ratio; 10 | use sp_api::ProvideRuntimeApi; 11 | use sp_blockchain::HeaderBackend; 12 | use sp_runtime::{generic::BlockId, traits::Block as BlockT}; 13 | use std::sync::Arc; 14 | 15 | pub use self::gen_client::Client as AssetIndexClient; 16 | pub use pallet_asset_index_rpc_runtime_api::AssetIndexApi as AssetIndexRuntimeApi; 17 | 18 | /// Asset index state API 19 | #[rpc] 20 | pub trait AssetIndexApi { 21 | #[rpc(name = "assetIndex_getNav")] 22 | fn get_nav(&self, at: Option) -> Result; 23 | } 24 | 25 | /// A struct that implements the [`AssetIndexApi`]. 26 | pub struct AssetIndexBackend { 27 | client: Arc, 28 | _marker: std::marker::PhantomData, 29 | } 30 | 31 | impl AssetIndexBackend { 32 | /// Create new `AssetIndex` with the given reference to the client. 33 | pub fn new(client: Arc) -> Self { 34 | AssetIndexBackend { client, _marker: Default::default() } 35 | } 36 | } 37 | 38 | pub enum Error { 39 | RuntimeError, 40 | } 41 | 42 | impl From for i64 { 43 | fn from(e: Error) -> i64 { 44 | match e { 45 | Error::RuntimeError => 1, 46 | } 47 | } 48 | } 49 | 50 | impl AssetIndexApi<::Hash, AccountId, AssetId, Balance> 51 | for AssetIndexBackend 52 | where 53 | Block: BlockT, 54 | C: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, 55 | C::Api: AssetIndexRuntimeApi, 56 | AccountId: Codec, 57 | AssetId: Codec, 58 | Balance: Codec, 59 | { 60 | fn get_nav(&self, at: Option<::Hash>) -> Result { 61 | let api = self.client.runtime_api(); 62 | let at = BlockId::hash(at.unwrap_or( 63 | // If the block hash is not supplied assume the best block. 64 | self.client.info().best_hash, 65 | )); 66 | api.get_nav(&at).map_err(|e| RpcError { 67 | code: ErrorCode::ServerError(Error::RuntimeError.into()), 68 | message: "Unable to get current NAV.".into(), 69 | data: Some(format!("{:?}", e).into()), 70 | }) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /pallets/asset-index/src/traits.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | /// A type to abstract the range of lockup period 5 | pub trait LockupPeriodRange { 6 | /// The minimum value of the lockup period range 7 | fn min() -> BlockNumber; 8 | 9 | /// The maximum value of the lockup period range 10 | fn max() -> BlockNumber; 11 | } 12 | -------------------------------------------------------------------------------- /pallets/asset-index/src/types.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | use codec::{Decode, Encode}; 5 | use frame_support::{ 6 | sp_runtime::{ 7 | traits::{AtLeast32BitUnsigned, Zero}, 8 | RuntimeDebug, 9 | }, 10 | sp_std::vec::Vec, 11 | }; 12 | 13 | /// Abstraction over the lock of minted index token that are locked up for 14 | /// `LockupPeriod` 15 | #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] 16 | pub struct IndexTokenLock { 17 | /// Locked amount of index token. 18 | pub locked: Balance, 19 | /// The block when the locked index token can be unlocked. 20 | pub end_block: BlockNumber, 21 | } 22 | 23 | /// Metadata for an asset 24 | #[derive(PartialEq, Eq, Clone, Default, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] 25 | pub struct AssetMetadata { 26 | pub name: BoundedString, 27 | pub symbol: BoundedString, 28 | pub decimals: u8, 29 | } 30 | 31 | /// Represents a single asset being withdrawn 32 | #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] 33 | pub struct AssetWithdrawal { 34 | /// The identifier of the asset 35 | pub asset: AssetId, 36 | /// The amount of asset units about to be transferred to the LP. 37 | pub units: Balance, 38 | /// The amount still reserved for this withdrawal. 39 | pub reserved: Balance, 40 | /// Whether this withdrawal was already been closed. 41 | pub withdrawn: bool, 42 | } 43 | 44 | #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] 45 | /// Describes an in progress withdrawal of a collection of assets from the index 46 | pub struct PendingRedemption { 47 | /// The block after which the redemption process is over. 48 | pub end_block: BlockNumber, 49 | /// All the withdrawals resulted from the redemption. 50 | pub assets: Vec>, 51 | } 52 | 53 | /// Represents the redemption of a given pint amount based on the 54 | /// `AssetDistribution`. 55 | #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] 56 | pub struct AssetRedemption { 57 | /// All the assets together with their redeemed amount 58 | pub asset_amounts: Vec<(AssetId, Balance)>, 59 | /// The total amount of redeemed pint 60 | pub redeemed_index_tokens: Balance, 61 | } 62 | 63 | impl Default for AssetRedemption { 64 | fn default() -> Self { 65 | Self { asset_amounts: Vec::new(), redeemed_index_tokens: Balance::zero() } 66 | } 67 | } 68 | 69 | /// Limits the amount of deposits 70 | #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] 71 | #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] 72 | pub struct DepositRange { 73 | /// Minimum amount of index tokens a deposit must be worth 74 | pub minimum: Balance, 75 | /// Maximum amount of index tokens a deposit must be worth 76 | pub maximum: Balance, 77 | } 78 | 79 | // Default implementation for bounds [0, MAX] 80 | impl Default for DepositRange { 81 | fn default() -> Self { 82 | Self { minimum: Balance::one(), maximum: Balance::max_value() } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /pallets/committee/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ['ChainSafe Systems'] 3 | description = 'FRAME pallet to implement PINT committee.' 4 | edition = '2018' 5 | license = 'LGPL-3.0-only' 6 | name = 'pallet-committee' 7 | readme = 'README.md' 8 | repository = 'https://github.com/ChainSafe/PINT/' 9 | version = '0.0.1' 10 | 11 | [dependencies] 12 | log = { version = "0.4.14", default-features = false } 13 | codec = { package = "parity-scale-codec", version = "2.3.1", default-features = false } 14 | scale-info = { version = "1.0", default-features = false, features = ["derive"] } 15 | 16 | # Substrate Dependencies 17 | frame-support = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 18 | frame-system = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 19 | frame-benchmarking = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false, optional = true } 20 | 21 | [dev-dependencies] 22 | sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 23 | sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 24 | sp-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 25 | frame-benchmarking = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 26 | 27 | [features] 28 | default = ['std'] 29 | std = [ 30 | 'log/std', 31 | 'codec/std', 32 | 'frame-support/std', 33 | 'frame-system/std', 34 | ] 35 | runtime-benchmarks = [ 36 | 'frame-benchmarking', 37 | 'frame-support/runtime-benchmarks', 38 | 'frame-system/runtime-benchmarks', 39 | ] 40 | 41 | [package.metadata.docs.rs] 42 | targets = ['x86_64-unknown-linux-gnu'] 43 | -------------------------------------------------------------------------------- /pallets/committee/README.md: -------------------------------------------------------------------------------- 1 | License: LGPL-3.0-only 2 | -------------------------------------------------------------------------------- /pallets/committee/src/benchmarking.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | use super::*; 4 | use frame_benchmarking::{account, benchmarks, vec, Box}; 5 | use frame_support::{ 6 | assert_noop, assert_ok, 7 | traits::{EnsureOrigin, Get, Hooks, UnfilteredDispatchable}, 8 | }; 9 | use frame_system::{ensure_signed, Call as SystemCall, Pallet as System, RawOrigin as SystemOrigin}; 10 | 11 | fn submit_proposal(origin: ::Origin) -> pallet::Proposal { 12 | let action: T::Action = SystemCall::::remark { remark: vec![0; 0] }.into(); 13 | let expected_nonce = pallet::ProposalCount::::get(); 14 | 15 | let account_id = ensure_signed(origin.clone()).unwrap(); 16 | assert_ok!(>::add_constituent(SystemOrigin::Root.into(), account_id.clone())); 17 | >::set_block_number( 18 | >::block_number() + 19 | ::VotingPeriod::get() + 20 | ::ProposalSubmissionPeriod::get() + 21 | 1_u32.into(), 22 | ); 23 | 24 | let call = Call::::propose { action: Box::new(action.clone()) }; 25 | assert_ok!(call.dispatch_bypass_filter(origin)); 26 | 27 | pallet::Proposal::::new(action, account_id, expected_nonce, ProposalStatus::Active) 28 | } 29 | 30 | fn run_to_block(n: T::BlockNumber) { 31 | while System::::block_number() < n { 32 | System::::set_block_number(System::::block_number() + 1u32.into()); 33 | Pallet::::on_initialize(System::::block_number()); 34 | } 35 | } 36 | 37 | benchmarks! { 38 | propose { 39 | let origin = T::ProposalSubmissionOrigin::successful_origin(); 40 | let proposal = submit_proposal::(origin.clone()); 41 | let call = Call::::propose{action: Box::new(SystemCall::::remark{remark:vec![0; 0]}.into())}; 42 | }: { 43 | call.dispatch_bypass_filter(origin)? 44 | } verify { 45 | assert!(>::get_proposal(&proposal.hash()) == Some(proposal)); 46 | } 47 | 48 | vote { 49 | let origin = T::ProposalSubmissionOrigin::successful_origin(); 50 | let proposal = submit_proposal::(origin.clone()); 51 | 52 | // run to voting period 53 | >::set_block_number( 54 | >::block_number() 55 | + ::VotingPeriod::get() 56 | + ::ProposalSubmissionPeriod::get() + 1_u32.into(), 57 | ); 58 | 59 | // construct call 60 | let call = Call::::vote{ proposal_hash: proposal.hash(), vote: VoteKind::Abstain}; 61 | }: { 62 | call.dispatch_bypass_filter(origin)? 63 | } verify { 64 | assert_eq!( 65 | >::get_votes_for(&proposal.hash()).unwrap().votes.len(), 66 | 1, 67 | ); 68 | } 69 | 70 | close { 71 | let proposal: pallet::Proposal = submit_proposal::(T::ProposalSubmissionOrigin::successful_origin()); 72 | 73 | // vote 74 | for i in 0..5 { 75 | let voter: T::AccountId = account("voter", i, 0); 76 | assert_ok!(Votes::::try_mutate(&proposal.hash(), |votes| { 77 | if let Some(votes) = votes { 78 | votes.cast_vote( 79 | MemberVote::new(CommitteeMember::new(voter, MemberType::Council), VoteKind::Aye), 80 | ); 81 | Ok(()) 82 | } else { 83 | Err(Error::::NoProposalWithHash) 84 | } 85 | })); 86 | } 87 | 88 | // run out of voting period 89 | >::set_block_number( 90 | >::block_number() 91 | + ::VotingPeriod::get() * 2_u32.into() 92 | + ::ProposalSubmissionPeriod::get() 93 | + 1_u32.into() 94 | ); 95 | 96 | // construct call 97 | let call = Call::::close{proposal_hash: proposal.hash()}; 98 | }: { 99 | call.dispatch_bypass_filter(T::ProposalExecutionOrigin::successful_origin())? 100 | } verify { 101 | assert_noop!( 102 | >::close(T::ProposalExecutionOrigin::successful_origin(), proposal.hash()), 103 | >::ProposalAlreadyExecuted 104 | ); 105 | } 106 | 107 | add_constituent { 108 | let constituent: T::AccountId = account("constituent", 0, 0); 109 | }: _( 110 | SystemOrigin::Root, 111 | constituent.clone() 112 | ) verify { 113 | assert!(>::contains_key(constituent)); 114 | } 115 | 116 | remove_member { 117 | let constituent: T::AccountId = account("constituent", 0, 0); 118 | assert_ok!(>::add_constituent(SystemOrigin::Root.into(), constituent.clone())); 119 | }: _( 120 | SystemOrigin::Root, 121 | constituent.clone() 122 | ) verify { 123 | assert!(!>::contains_key(constituent)); 124 | } 125 | 126 | set_voting_period { 127 | let two_weeks: T::BlockNumber = (10u32 * 60 * 24 * 7 * 2).into(); 128 | }: _( 129 | SystemOrigin::Root, 130 | two_weeks 131 | ) verify { 132 | run_to_block::(::VotingPeriod::get()); 133 | assert_eq!(pallet::VotingPeriod::::get(), two_weeks); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /pallets/committee/src/traits.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | /// A type to abstract the range of voting period 5 | pub trait VotingPeriodRange { 6 | /// The minimum value of the voting period range 7 | fn min() -> BlockNumber; 8 | 9 | /// The maximum value of the voting period range 10 | fn max() -> BlockNumber; 11 | } 12 | -------------------------------------------------------------------------------- /pallets/committee/src/utils.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | use frame_support::sp_runtime::traits::{CheckedAdd, CheckedDiv, CheckedMul, One}; 5 | 6 | // Proposal submissions and voting follow set cycles e.g. 7 | // 8 | // ---v0--||-----s1----|--v1--||-----s2----|--v2--|... 9 | // 10 | // Proposals submitted in s1 are voted upon in v1 and after that 11 | // they may or may not be executed and then are dropped from the ActiveProposals 12 | // set. 13 | // 14 | // Proposals submitted during v0 fall into the next submission period and 15 | // should be voted on in v1. To simplify implementation we assume the cycle 16 | // begins with an initial dummy voting period. 17 | // 18 | // Will return an None if any of the arithmetic operations fail due to 19 | // overflow/underflow 20 | // 21 | pub fn get_vote_end( 22 | current_block: &T, 23 | voting_period: &T, 24 | proposal_period: &T, 25 | ) -> Option { 26 | let epoch_period = voting_period.checked_add(proposal_period)?; 27 | 28 | // [(current_block // period) + 1] * period + voting_period 29 | // return the block at the end of the next voting period after the current one 30 | current_block 31 | .checked_div(&epoch_period)? 32 | .checked_add(&T::one())? 33 | .checked_mul(&epoch_period)? 34 | .checked_add(voting_period) 35 | } 36 | 37 | #[cfg(test)] 38 | mod tests { 39 | use super::*; 40 | use std::iter; 41 | 42 | const VOTE_P: i32 = 2; 43 | const PROPOSAL_P: i32 = 3; 44 | 45 | #[test] 46 | // A proposal made during the start dummpy period must have votes submitted 47 | // before the end of v1 48 | fn test_proposal_in_v0() { 49 | assert_eq!(get_vote_end(&0, &VOTE_P, &PROPOSAL_P), Some(VOTE_P + PROPOSAL_P + VOTE_P)) 50 | } 51 | 52 | #[test] 53 | // A proposal made during s1 must have votes submitted before 54 | // the end of v1 55 | fn test_proposal_in_s1() { 56 | assert_eq!(get_vote_end(&4, &VOTE_P, &PROPOSAL_P), Some(VOTE_P + PROPOSAL_P + VOTE_P)) 57 | } 58 | 59 | #[test] 60 | // A proposal made during v1 must have votes submitted before 61 | // the end of v2 62 | fn test_proposal_in_v1() { 63 | assert_eq!(get_vote_end(&9, &VOTE_P, &PROPOSAL_P), Some(VOTE_P + 2 * (PROPOSAL_P + VOTE_P))) 64 | } 65 | 66 | #[test] 67 | // Check a range of blocks are as expected 68 | fn test_proposal_range() { 69 | let result: Vec = (0..15).map(|i| get_vote_end(&i, &VOTE_P, &PROPOSAL_P).unwrap()).collect(); 70 | 71 | let expected: Vec = iter::empty() 72 | .chain(iter::repeat(VOTE_P + PROPOSAL_P + VOTE_P).take(5)) 73 | .chain(iter::repeat(VOTE_P + 2 * (PROPOSAL_P + VOTE_P)).take(5)) 74 | .chain(iter::repeat(VOTE_P + 3 * (PROPOSAL_P + VOTE_P)).take(5)) 75 | .collect(); 76 | 77 | assert_eq!(result, expected) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /pallets/local-treasury/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ['ChainSafe Systems'] 3 | description = 'FRAME pallet to implement PINT local treasury.' 4 | edition = '2018' 5 | license = 'LGPL-3.0-only' 6 | name = 'pallet-local-treasury' 7 | readme = 'README.md' 8 | repository = 'https://github.com/ChainSafe/PINT/' 9 | version = '0.0.1' 10 | 11 | [dependencies] 12 | codec = { package = "parity-scale-codec", version = "2.3.1", default-features = false } 13 | scale-info = { version = "1.0", default-features = false, features = ["derive"] } 14 | 15 | # Substrate Dependencies 16 | frame-support = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 17 | frame-system = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 18 | frame-benchmarking = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false, optional = true } 19 | 20 | [dev-dependencies] 21 | serde = "1.0.130" 22 | sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 23 | sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 24 | sp-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 25 | frame-system = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 26 | frame-benchmarking = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 27 | sp-runtime = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 28 | 29 | pallet-balances = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 30 | 31 | [features] 32 | default = ['std'] 33 | std = [ 34 | 'codec/std', 35 | 'frame-support/std', 36 | 'frame-system/std', 37 | ] 38 | runtime-benchmarks = [ 39 | 'frame-benchmarking', 40 | 'frame-system/runtime-benchmarks', 41 | 'frame-support/runtime-benchmarks', 42 | ] 43 | 44 | [package.metadata.docs.rs] 45 | targets = ['x86_64-unknown-linux-gnu'] 46 | -------------------------------------------------------------------------------- /pallets/local-treasury/README.md: -------------------------------------------------------------------------------- 1 | License: LGPL-3.0-only -------------------------------------------------------------------------------- /pallets/local-treasury/src/benchmarking.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | use super::*; 4 | use frame_benchmarking::{account, benchmarks}; 5 | use frame_support::{sp_runtime::traits::AccountIdConversion, traits::Currency, PalletId}; 6 | use frame_system::Origin; 7 | 8 | benchmarks! { 9 | withdraw { 10 | let local_treasury: ::AccountId = PalletId(*b"Treasury").into_account(); 11 | T::Currency::deposit_creating(&local_treasury, 10_000_000_u32.into()); 12 | let admin: ::AccountId = account("admin", 0, 0); 13 | }: _( 14 | >::Root, 15 | 5_000_000_u32.into(), 16 | admin.clone() 17 | ) verify { 18 | assert_eq!( 19 | T::Currency::free_balance(&admin), 20 | 5_000_000_u32.into(), 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /pallets/local-treasury/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | //! # Local Treasury Pallet 5 | //! 6 | //! Manages PINT exclusively. The treasury is a single account which is derived from the configured 7 | //! `PalletId`. It maintains ownership of various assets and is controlled by the Governance 8 | //! Committee. Deposits to the Treasury can be done by simply transferring funds to its AccountId. 9 | //! The committee can execute proposals to withdraw funds from the Treasury. 10 | 11 | #![cfg_attr(not(feature = "std"), no_std)] 12 | 13 | pub use pallet::*; 14 | 15 | #[cfg(test)] 16 | mod mock; 17 | 18 | #[cfg(feature = "runtime-benchmarks")] 19 | mod benchmarking; 20 | #[cfg(test)] 21 | mod tests; 22 | 23 | // this is requires as the #[pallet::event] proc macro generates code that violates this lint 24 | #[allow(clippy::unused_unit)] 25 | #[frame_support::pallet] 26 | pub mod pallet { 27 | use frame_support::{ 28 | dispatch::DispatchResult, 29 | pallet_prelude::*, 30 | sp_runtime::traits::AccountIdConversion, 31 | traits::{Currency, ExistenceRequirement::AllowDeath, Get}, 32 | PalletId, 33 | }; 34 | use frame_system::pallet_prelude::*; 35 | 36 | type AccountIdFor = ::AccountId; 37 | type BalanceFor = <::Currency as Currency>>::Balance; 38 | 39 | #[pallet::config] 40 | pub trait Config: frame_system::Config { 41 | /// Origin that is allowed to manage the treasury balance and initiate 42 | /// withdrawals 43 | type AdminOrigin: EnsureOrigin; 44 | /// PalletId used to generate the `AccountId` which holds the balance of the 45 | /// treasury. 46 | #[pallet::constant] 47 | type PalletId: Get; 48 | /// The pallet to use as the base currency for this treasury 49 | type Currency: Currency; 50 | type Event: From> + IsType<::Event>; 51 | 52 | /// The weight for this pallet's extrinsics. 53 | type WeightInfo: WeightInfo; 54 | } 55 | 56 | #[pallet::pallet] 57 | #[pallet::generate_store(pub(super) trait Store)] 58 | pub struct Pallet(_); 59 | 60 | #[pallet::event] 61 | #[pallet::generate_deposit(pub(super) fn deposit_event)] 62 | pub enum Event { 63 | /// Admin successfully transferred some funds from the treasury to 64 | /// another account parameters. \[recipient, amount\] 65 | Withdrawn(AccountIdFor, BalanceFor), 66 | } 67 | 68 | #[pallet::hooks] 69 | impl Hooks> for Pallet {} 70 | 71 | #[pallet::extra_constants] 72 | impl Pallet { 73 | /// Returns the `AccountId` of the treasury account. 74 | pub fn treasury_account() -> T::AccountId { 75 | T::PalletId::get().into_account() 76 | } 77 | } 78 | 79 | #[pallet::call] 80 | impl Pallet { 81 | /// Transfer balance from the treasury to another account. 82 | /// 83 | /// Only callable by the AdminOrigin. 84 | #[pallet::weight(T::WeightInfo::withdraw())] 85 | pub fn withdraw(origin: OriginFor, amount: BalanceFor, recipient: AccountIdFor) -> DispatchResult { 86 | T::AdminOrigin::ensure_origin(origin)?; 87 | 88 | T::Currency::transfer(&Self::treasury_account(), &recipient, amount, AllowDeath)?; 89 | 90 | Self::deposit_event(Event::Withdrawn(recipient, amount)); 91 | 92 | Ok(()) 93 | } 94 | } 95 | 96 | /// Trait for the treasury pallet extrinsic weights. 97 | pub trait WeightInfo { 98 | fn withdraw() -> Weight; 99 | } 100 | 101 | /// For backwards compatibility and tests 102 | impl WeightInfo for () { 103 | fn withdraw() -> Weight { 104 | Default::default() 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /pallets/local-treasury/src/mock.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | // Required as construct_runtime! produces code that violates this lint 5 | #![allow(clippy::from_over_into)] 6 | 7 | use crate as pallet_local_treasury; 8 | use frame_support::{ord_parameter_types, parameter_types, traits::StorageMapShim, PalletId}; 9 | use frame_system as system; 10 | 11 | use frame_support::traits::Everything; 12 | use sp_core::H256; 13 | use sp_runtime::{ 14 | testing::Header, 15 | traits::{AccountIdConversion, BlakeTwo256, IdentityLookup}, 16 | }; 17 | 18 | type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; 19 | type Block = frame_system::mocking::MockBlock; 20 | 21 | // Configure a mock runtime to test the pallet. 22 | frame_support::construct_runtime!( 23 | pub enum Test where 24 | Block = Block, 25 | NodeBlock = Block, 26 | UncheckedExtrinsic = UncheckedExtrinsic, 27 | { 28 | System: frame_system::{Pallet, Call, Config, Storage, Event}, 29 | Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, 30 | LocalTreasury: pallet_local_treasury::{Pallet, Call, Storage, Event}, 31 | } 32 | ); 33 | 34 | parameter_types! { 35 | pub const BlockHashCount: u64 = 250; 36 | pub const SS58Prefix: u8 = 42; 37 | } 38 | 39 | pub(crate) type Balance = u64; 40 | pub(crate) type AccountId = u64; 41 | 42 | impl system::Config for Test { 43 | type BaseCallFilter = Everything; 44 | type BlockWeights = (); 45 | type BlockLength = (); 46 | type DbWeight = (); 47 | type Origin = Origin; 48 | type Call = Call; 49 | type Index = u64; 50 | type BlockNumber = u64; 51 | type Hash = H256; 52 | type Hashing = BlakeTwo256; 53 | type AccountId = AccountId; 54 | type Lookup = IdentityLookup; 55 | type Header = Header; 56 | type Event = Event; 57 | type BlockHashCount = BlockHashCount; 58 | type Version = (); 59 | type PalletInfo = PalletInfo; 60 | type AccountData = (); 61 | type OnNewAccount = (); 62 | type OnKilledAccount = (); 63 | type SystemWeightInfo = (); 64 | type SS58Prefix = SS58Prefix; 65 | type OnSetCode = (); 66 | } 67 | 68 | // param types for balances 69 | parameter_types! { 70 | pub const MaxLocks: u32 = 1024; 71 | pub static ExistentialDeposit: Balance = 0; 72 | } 73 | 74 | impl pallet_balances::Config for Test { 75 | type Balance = Balance; 76 | type DustRemoval = (); 77 | type Event = Event; 78 | type ExistentialDeposit = ExistentialDeposit; 79 | type AccountStore = StorageMapShim< 80 | pallet_balances::Account, 81 | system::Provider, 82 | Balance, 83 | pallet_balances::AccountData, 84 | >; 85 | type MaxLocks = MaxLocks; 86 | type MaxReserves = (); 87 | type ReserveIdentifier = [u8; 8]; 88 | type WeightInfo = (); 89 | } 90 | 91 | pub(crate) const LOCAL_TREASURE_PALLET_ID: PalletId = PalletId(*b"12345678"); 92 | pub(crate) const ADMIN_ACCOUNT_ID: AccountId = 88; 93 | 94 | parameter_types! { 95 | pub const TestPalletId: PalletId = LOCAL_TREASURE_PALLET_ID; 96 | } 97 | ord_parameter_types! { 98 | pub const AdminAccountId: AccountId = ADMIN_ACCOUNT_ID; 99 | } 100 | 101 | impl pallet_local_treasury::Config for Test { 102 | type AdminOrigin = frame_system::EnsureSignedBy; 103 | type PalletId = TestPalletId; 104 | type Currency = Balances; 105 | type Event = Event; 106 | type WeightInfo = (); 107 | } 108 | 109 | pub fn local_treasury_account_id() -> AccountId { 110 | LOCAL_TREASURE_PALLET_ID.into_account() 111 | } 112 | 113 | // Build genesis storage according to the mock runtime. 114 | pub fn new_test_ext(balances: Vec<(AccountId, Balance)>) -> sp_io::TestExternalities { 115 | let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); 116 | pallet_balances::GenesisConfig:: { 117 | // Assign initial balances to accounts 118 | balances, 119 | } 120 | .assimilate_storage(&mut t) 121 | .unwrap(); 122 | t.into() 123 | } 124 | -------------------------------------------------------------------------------- /pallets/local-treasury/src/tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | use crate::mock::*; 5 | use frame_support::{assert_noop, assert_ok}; 6 | use pallet_balances::Error as BalancesError; 7 | use sp_runtime::traits::BadOrigin; 8 | 9 | const ASHLEY: AccountId = 0; 10 | 11 | fn assert_balances(balances: &[(AccountId, Balance)]) { 12 | for (account, balance) in balances { 13 | assert_eq!(&Balances::free_balance(account), balance) 14 | } 15 | } 16 | 17 | #[test] 18 | fn unprivileged_account_can_deposit() { 19 | const INITIAL_BALANCE: Balance = 100; 20 | const AMOUNT: Balance = 10; 21 | 22 | let initial_balances: Vec<(u64, u64)> = vec![(local_treasury_account_id(), 0), (ASHLEY, INITIAL_BALANCE)]; 23 | 24 | let final_balances: Vec<(u64, u64)> = 25 | vec![(local_treasury_account_id(), AMOUNT), (ASHLEY, INITIAL_BALANCE - AMOUNT)]; 26 | 27 | new_test_ext(initial_balances).execute_with(|| { 28 | assert_ok!(Balances::transfer(Origin::signed(ASHLEY), local_treasury_account_id(), AMOUNT)); 29 | assert_balances(&final_balances); 30 | }); 31 | } 32 | 33 | #[test] 34 | fn unprivileged_account_cannot_withdraw() { 35 | const INITIAL_BALANCE: Balance = 100; 36 | const AMOUNT: Balance = 10; 37 | 38 | let initial_balances: Vec<(u64, u64)> = vec![(local_treasury_account_id(), 0), (ASHLEY, INITIAL_BALANCE)]; 39 | 40 | new_test_ext(initial_balances.clone()).execute_with(|| { 41 | assert_noop!(LocalTreasury::withdraw(Origin::signed(ASHLEY), AMOUNT, ASHLEY), BadOrigin); 42 | assert_balances(&initial_balances); 43 | }); 44 | } 45 | 46 | #[test] 47 | fn admin_account_can_withdraw() { 48 | const INITIAL_BALANCE: Balance = 100; 49 | const AMOUNT: Balance = 1; 50 | 51 | let initial_balances: Vec<(u64, u64)> = vec![(local_treasury_account_id(), INITIAL_BALANCE), (ADMIN_ACCOUNT_ID, 0)]; 52 | 53 | let final_balances: Vec<(u64, u64)> = 54 | vec![(local_treasury_account_id(), INITIAL_BALANCE - AMOUNT), (ADMIN_ACCOUNT_ID, AMOUNT)]; 55 | 56 | new_test_ext(initial_balances).execute_with(|| { 57 | assert_ok!(LocalTreasury::withdraw(Origin::signed(ADMIN_ACCOUNT_ID), AMOUNT, ADMIN_ACCOUNT_ID)); 58 | assert_balances(&final_balances); 59 | }); 60 | } 61 | 62 | #[test] 63 | fn admin_account_can_withdraw_to_zero() { 64 | const INITIAL_BALANCE: Balance = 100; 65 | const AMOUNT: Balance = 100; 66 | 67 | let initial_balances: Vec<(u64, u64)> = vec![(local_treasury_account_id(), INITIAL_BALANCE), (ADMIN_ACCOUNT_ID, 0)]; 68 | 69 | let final_balances: Vec<(u64, u64)> = vec![(local_treasury_account_id(), 0), (ADMIN_ACCOUNT_ID, AMOUNT)]; 70 | 71 | new_test_ext(initial_balances).execute_with(|| { 72 | assert_ok!(LocalTreasury::withdraw(Origin::signed(ADMIN_ACCOUNT_ID), AMOUNT, ADMIN_ACCOUNT_ID)); 73 | assert_balances(&final_balances); 74 | }); 75 | } 76 | 77 | #[test] 78 | fn admin_account_overdraw_fails() { 79 | const INITIAL_BALANCE: Balance = 100; 80 | const AMOUNT: Balance = 101; 81 | 82 | let initial_balances: Vec<(u64, u64)> = vec![(local_treasury_account_id(), INITIAL_BALANCE), (ADMIN_ACCOUNT_ID, 0)]; 83 | 84 | new_test_ext(initial_balances.clone()).execute_with(|| { 85 | assert_noop!( 86 | LocalTreasury::withdraw(Origin::signed(ADMIN_ACCOUNT_ID), AMOUNT, ADMIN_ACCOUNT_ID), 87 | BalancesError::::InsufficientBalance 88 | ); 89 | assert_balances(&initial_balances); 90 | }); 91 | } 92 | -------------------------------------------------------------------------------- /pallets/price-feed/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ['ChainSafe Systems'] 3 | description = 'FRAME pallet to implement PINT price feeds.' 4 | edition = '2018' 5 | license = 'LGPL-3.0-only' 6 | name = 'pallet-price-feed' 7 | readme = 'README.md' 8 | repository = 'https://github.com/ChainSafe/PINT/' 9 | version = '0.0.1' 10 | 11 | [dependencies] 12 | serde = { version = "1.0.130", optional = true } 13 | codec = { package = "parity-scale-codec", version = "2.3.1", default-features = false } 14 | scale-info = { version = "1.0", default-features = false, features = ["derive"] } 15 | 16 | # Substrate Dependencies 17 | frame-support = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 18 | frame-system = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 19 | frame-benchmarking = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false, optional = true } 20 | 21 | # PINT dependencies 22 | pallet-chainlink-feed = { git = 'https://github.com/smartcontractkit/chainlink-polkadot', branch = 'polkadot-v0.9.13', default-features = false } 23 | primitives = { path = "../../primitives/primitives", default-features = false } 24 | 25 | [dev-dependencies] 26 | serde = "1.0.130" 27 | sp-core = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 28 | sp-io = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 29 | sp-runtime = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 30 | 31 | pallet-balances = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 32 | pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = 'polkadot-v0.9.13' } 33 | 34 | [features] 35 | default = ['std'] 36 | std = [ 37 | 'serde', 38 | 'codec/std', 39 | 'frame-support/std', 40 | 'frame-system/std', 41 | 'pallet-chainlink-feed/std', 42 | 'primitives/std', 43 | ] 44 | runtime-benchmarks = [ 45 | 'frame-benchmarking', 46 | 'frame-support/runtime-benchmarks', 47 | 'pallet-chainlink-feed/runtime-benchmarks', 48 | 'primitives/runtime-benchmarks', 49 | ] 50 | 51 | [package.metadata.docs.rs] 52 | targets = ['x86_64-unknown-linux-gnu'] 53 | -------------------------------------------------------------------------------- /pallets/price-feed/README.md: -------------------------------------------------------------------------------- 1 | License: LGPL-3.0-only -------------------------------------------------------------------------------- /pallets/price-feed/src/benchmarking.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | #![cfg(feature = "runtime-benchmarks")] 5 | 6 | use super::*; 7 | use frame_benchmarking::benchmarks; 8 | use frame_support::{assert_ok, dispatch::UnfilteredDispatchable, sp_std::convert::TryInto, traits::EnsureOrigin}; 9 | 10 | use crate::Pallet as PriceFeed; 11 | 12 | benchmarks! { 13 | map_asset_price_feed { 14 | let asset_id :T::AssetId = T::try_convert(2u8).unwrap(); 15 | let origin = T::AdminOrigin::successful_origin(); 16 | let feed_id = 0u32.try_into().ok().unwrap(); 17 | let call = Call::::map_asset_price_feed { 18 | asset_id: asset_id.clone(), 19 | feed_id: feed_id 20 | }; 21 | }: { call.dispatch_bypass_filter(origin)? } verify { 22 | assert_eq!( 23 | PriceFeed::::asset_feed(asset_id), 24 | Some(feed_id) 25 | ); 26 | } 27 | 28 | unmap_asset_price_feed { 29 | let asset_id :T::AssetId = T::try_convert(2u8).unwrap(); 30 | let origin = T::AdminOrigin::successful_origin(); 31 | let feed_id = 0u32.try_into().ok().unwrap(); 32 | assert_ok!(PriceFeed::::map_asset_price_feed(origin.clone(), asset_id.clone(), feed_id)); 33 | let call = Call::::unmap_asset_price_feed { 34 | asset_id: asset_id.clone(), 35 | }; 36 | }: { call.dispatch_bypass_filter(origin)? } verify { 37 | assert_eq!( 38 | PriceFeed::::asset_feed(asset_id), 39 | None 40 | ); 41 | } 42 | } 43 | 44 | #[cfg(test)] 45 | mod tests { 46 | use frame_support::assert_ok; 47 | 48 | use crate::mock::{new_test_ext, FeedBuilder, Test}; 49 | 50 | use super::*; 51 | 52 | #[test] 53 | fn map_asset_price_feed() { 54 | new_test_ext().execute_with(|| { 55 | assert_ok!(FeedBuilder::new().description(b"X".to_vec()).build_and_store()); 56 | assert_ok!(Pallet::::test_benchmark_map_asset_price_feed()); 57 | }); 58 | } 59 | 60 | #[test] 61 | fn unmap_asset_price_feed() { 62 | new_test_ext().execute_with(|| { 63 | assert_ok!(FeedBuilder::new().description(b"X".to_vec()).build_and_store()); 64 | assert_ok!(Pallet::::test_benchmark_unmap_asset_price_feed()); 65 | }); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /pallets/price-feed/src/tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | use crate as pallet; 5 | use crate::{mock::*, Error}; 6 | use frame_support::{assert_noop, assert_ok}; 7 | use pallet::PriceFeed as _; 8 | use primitives::Price; 9 | use sp_runtime::{traits::BadOrigin, FixedPointNumber}; 10 | 11 | const ASSET_X_ID: AssetId = 2; 12 | const ASSET_Y_ID: AssetId = 3; 13 | 14 | #[test] 15 | fn feed_creation_and_mapping_should_work() { 16 | new_test_ext().execute_with(|| { 17 | // insert two feeds 18 | assert_ok!(FeedBuilder::new().description(b"X".to_vec()).build_and_store()); 19 | assert_ok!(FeedBuilder::new().description(b"Y".to_vec()).build_and_store()); 20 | 21 | // PINT asset id is not tracked yet 22 | assert_noop!(PriceFeed::get_price(ASSET_X_ID), Error::::AssetPriceFeedNotFound); 23 | 24 | // map feed 0 to PINT 25 | assert_ok!(PriceFeed::map_asset_price_feed(Origin::signed(ADMIN_ACCOUNT_ID), ASSET_X_ID, 0)); 26 | 27 | // map feed 1 to assetId 2 28 | assert_ok!(PriceFeed::map_asset_price_feed(Origin::signed(ADMIN_ACCOUNT_ID), ASSET_Y_ID, 1)); 29 | 30 | assert_ok!(PriceFeed::unmap_asset_price_feed(Origin::signed(ADMIN_ACCOUNT_ID), ASSET_Y_ID)); 31 | }); 32 | } 33 | 34 | #[test] 35 | fn non_admin_cannot_map_feeds() { 36 | new_test_ext().execute_with(|| { 37 | assert_ok!(FeedBuilder::new().description(b"PINT".to_vec()).build_and_store()); 38 | 39 | assert_noop!(PriceFeed::map_asset_price_feed(Origin::signed(1), PINTAssetId::get(), 0), BadOrigin); 40 | }) 41 | } 42 | 43 | #[test] 44 | fn cannot_get_price_pair_for_feed_without_valid_round() { 45 | new_test_ext().execute_with(|| { 46 | // insert two feeds 47 | assert_ok!(FeedBuilder::new().description(b"PINT".to_vec()).build_and_store()); 48 | assert_ok!(FeedBuilder::new().description(b"X".to_vec()).build_and_store()); 49 | 50 | assert_ok!(PriceFeed::map_asset_price_feed(Origin::signed(ADMIN_ACCOUNT_ID), PINTAssetId::get(), 0)); 51 | assert_ok!(PriceFeed::map_asset_price_feed(Origin::signed(ADMIN_ACCOUNT_ID), ASSET_X_ID, 1)); 52 | assert_noop!(PriceFeed::get_price(ASSET_X_ID), Error::::InvalidFeedValue); 53 | }) 54 | } 55 | 56 | #[test] 57 | fn price_pair_should_be_available() { 58 | new_test_ext().execute_with(|| { 59 | // insert two feeds 60 | let decimals = 6; 61 | assert_ok!(FeedBuilder::new() 62 | .description(b"X".to_vec()) 63 | .min_submissions(1) 64 | .decimals(decimals as u8) 65 | .value_bounds(0, 1_000_000_000_000) 66 | .build_and_store()); 67 | assert_ok!(FeedBuilder::new().description(b"Y".to_vec()).min_submissions(1).decimals(0).build_and_store()); 68 | 69 | assert_ok!(PriceFeed::map_asset_price_feed(Origin::signed(ADMIN_ACCOUNT_ID), ASSET_X_ID, 0)); 70 | assert_ok!(PriceFeed::map_asset_price_feed(Origin::signed(ADMIN_ACCOUNT_ID), ASSET_Y_ID, 1)); 71 | 72 | // insert round feed 1 73 | let feed_id = 0; 74 | let round_id = 1; 75 | let oracle = 2; 76 | let base_submission = 1_000_000_000; 77 | let precision = 10u128.pow(decimals); 78 | assert_ok!(ChainlinkFeed::submit(Origin::signed(oracle), feed_id, round_id, base_submission)); 79 | 80 | // insert round feed 2 81 | let feed_id = 1; 82 | let round_id = 1; 83 | let oracle = 2; 84 | let quote_submission = 200; 85 | assert_ok!(ChainlinkFeed::submit(Origin::signed(oracle), feed_id, round_id, quote_submission)); 86 | 87 | let base_price = PriceFeed::get_price(ASSET_X_ID).expect("price pair should be available"); 88 | assert_eq!(base_price, Price::saturating_from_integer((base_submission as u128) / precision)); 89 | 90 | let quote_price = PriceFeed::get_price(ASSET_Y_ID).expect("price pair should be available"); 91 | assert_eq!(quote_price, Price::saturating_from_integer(quote_submission as u128)); 92 | 93 | let pair = PriceFeed::get_relative_price_pair(ASSET_X_ID, ASSET_Y_ID).expect("relative price available"); 94 | 95 | assert_eq!( 96 | pair.price, 97 | Price::saturating_from_rational((base_submission as u128) / precision, quote_submission) 98 | ); 99 | }) 100 | } 101 | -------------------------------------------------------------------------------- /pallets/price-feed/src/traits.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | #[cfg(feature = "runtime-benchmarks")] 5 | use frame_support::dispatch::DispatchResultWithPostInfo; 6 | 7 | use frame_support::dispatch::DispatchError; 8 | use primitives::{AssetPricePair, Price}; 9 | 10 | /// An interface to access price data 11 | pub trait PriceFeed { 12 | /// Returns the current price for the given asset measured in the constant denominating asset 13 | /// which is used as the quote currency, whereas the price of the `base` Asset will be the base 14 | /// currency for the price pair. *Note*: this returns the price for 1 basic unit 15 | fn get_price(base: AssetId) -> Result; 16 | 17 | /// Returns the current price pair for the prices of the base and quote asset in the form of 18 | /// `base/quote` 19 | fn get_relative_price_pair(base: AssetId, quote: AssetId) -> Result, DispatchError>; 20 | } 21 | 22 | #[cfg(feature = "runtime-benchmarks")] 23 | pub trait PriceFeedBenchmarks { 24 | fn create_feed(caller: AccountId, asset_id: AssetId) -> DispatchResultWithPostInfo; 25 | } 26 | -------------------------------------------------------------------------------- /pallets/price-feed/src/types.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | use frame_support::pallet_prelude::*; 5 | 6 | /// Represents an answer of a feed at a certain point of time 7 | #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] 8 | pub struct TimestampedValue { 9 | /// The timestamped value 10 | pub value: Value, 11 | /// Timestamp when the answer was first received 12 | pub moment: Moment, 13 | } 14 | -------------------------------------------------------------------------------- /pallets/remote-asset-manager/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ['ChainSafe Systems'] 3 | description = 'FRAME pallet to bond/unbond and transfer assets on other chains.' 4 | edition = '2018' 5 | license = 'LGPL-3.0-only' 6 | name = 'pallet-remote-asset-manager' 7 | readme = 'README.md' 8 | repository = 'https://github.com/ChainSafe/PINT/' 9 | version = '0.0.1' 10 | 11 | [dependencies] 12 | log = { version = "0.4.14", default-features = false } 13 | serde = { version = "1.0.130", features = ["derive"], optional = true } 14 | codec = { package = "parity-scale-codec", version = "2.3.1", default-features = false } 15 | scale-info = { version = "1.0", default-features = false, features = ["derive"] } 16 | 17 | # Substrate Dependencies 18 | frame-support = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 19 | frame-system = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 20 | frame-benchmarking = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false, optional = true } 21 | pallet-staking = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 22 | 23 | # Polkadot Dependencies 24 | xcm = { git = 'https://github.com/paritytech/polkadot', branch = 'release-v0.9.13', default-features = false } 25 | xcm-executor = { git = 'https://github.com/paritytech/polkadot', branch = 'release-v0.9.13', default-features = false } 26 | 27 | # Cumulus dependencies 28 | cumulus-pallet-xcm = { git = 'https://github.com/paritytech/cumulus', branch = 'polkadot-v0.9.13', default-features = false } 29 | cumulus-primitives-core = { git = 'https://github.com/paritytech/cumulus', branch = 'polkadot-v0.9.13', default-features = false } 30 | 31 | # PINT dependencies 32 | xcm-calls = {path = "../../primitives/xcm-calls", default-features = false } 33 | primitives = { path = "../../primitives/primitives", default-features = false } 34 | 35 | # orml Dependencies 36 | orml-traits = { git = 'https://github.com/open-web3-stack/open-runtime-module-library', branch = 'master', default-features = false } 37 | orml-xtokens = { git = 'https://github.com/open-web3-stack/open-runtime-module-library', branch = 'master', default-features = false } 38 | 39 | 40 | [features] 41 | default = ['std'] 42 | std = [ 43 | 'serde', 44 | 'codec/std', 45 | 'log/std', 46 | 'frame-support/std', 47 | 'frame-system/std', 48 | 'pallet-staking/std', 49 | 'xcm/std', 50 | 51 | 'xcm-calls/std', 52 | 'primitives/std', 53 | 54 | 'xcm-executor/std', 55 | 'cumulus-pallet-xcm/std', 56 | 'cumulus-primitives-core/std', 57 | 58 | 'orml-traits/std', 59 | 'orml-xtokens/std', 60 | ] 61 | # this feature is only for compilation now 62 | runtime-benchmarks = [ 63 | 'frame-benchmarking', 64 | 'frame-support/runtime-benchmarks', 65 | 'frame-system/runtime-benchmarks', 66 | 'primitives/runtime-benchmarks', 67 | ] 68 | 69 | [package.metadata.docs.rs] 70 | targets = ['x86_64-unknown-linux-gnu'] 71 | -------------------------------------------------------------------------------- /pallets/remote-asset-manager/README.md: -------------------------------------------------------------------------------- 1 | License: LGPL-3.0-only -------------------------------------------------------------------------------- /pallets/remote-asset-manager/src/traits.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | use frame_support::dispatch::DispatchResult; 5 | use orml_traits::GetByKey; 6 | 7 | /// The trait that provides balances related info about the parachain's various 8 | /// sovereign accounts. 9 | /// 10 | /// Definitions: 11 | /// - *Sovereign Account* is an account controlled by a particular Consensus System, within some 12 | /// other Consensus System: The account on the relay chain controlled by the PINT parachain. 13 | /// - *Stash Account* holds funds bonded for staking. If a remote asset (DOT) supports staking then 14 | /// PINT can bond funds that it holds in the sovereign account on the remote chain. 15 | /// Meaning as soon as remote assets are bonded from PINT's sovereign account 16 | /// on a target chain this sovereign account becomes a *stash account*. Both 17 | /// terms now describe one and the same account and are therefore used in the 18 | /// following interchangeably for the same account, even if the remote asset 19 | /// does not support staking. 20 | /// 21 | /// Staking rewards are not tracked since it is intended that the generated 22 | /// staking rewards are routinely exchanged via an AMM for PINT. Some of the 23 | /// resulting PINT will be allocated to the Treasury, with the 24 | /// remainder being burned. This does not affect the staked funds itself, so we 25 | /// only consider two states the funds can have: either free (not bonded), or 26 | /// not free (bonded or unbonded but not withdrawn yet.) 27 | pub trait BalanceMeter { 28 | /// The assumed balance of the PINT's parachain sovereign account on the 29 | /// asset's native chain that is currently not bonded or otherwise locked. 30 | fn free_stash_balance(asset: AssetId) -> Balance; 31 | 32 | /// Ensures that the given amount can be removed from the parachain's 33 | /// sovereign account without falling below the configured 34 | /// `minimum_stash_balance` 35 | fn ensure_free_stash(asset: AssetId, amount: Balance) -> DispatchResult; 36 | 37 | /// Returns the configured minimum stash balance below which the parachain's 38 | /// sovereign account balance must not fall. 39 | fn minimum_free_stash_balance(asset: &AssetId) -> Balance; 40 | } 41 | 42 | /// A type to abstract several staking related thresholds 43 | pub trait StakingCap { 44 | /// The minimum amount that should be held in stash (must remain 45 | /// unbonded). 46 | /// Withdrawals are only authorized if the updated stash balance does 47 | /// exceeds this. 48 | /// 49 | /// This must be at least the `ExistentialDeposit` as configured on the 50 | /// asset's native chain (e.g. DOT/Polkadot) 51 | fn minimum_reserve_balance(asset: AssetId) -> Balance; 52 | 53 | /// The minimum required amount to justify an additional `bond_extra` XCM call to stake 54 | /// additional funds. 55 | fn minimum_bond_extra(asset: AssetId) -> Balance; 56 | } 57 | 58 | // Convenience impl for orml `parameter_type_with_key!` impls 59 | impl StakingCap for (ReserveMinimum, BondExtra) 60 | where 61 | ReserveMinimum: GetByKey, 62 | BondExtra: GetByKey, 63 | { 64 | fn minimum_reserve_balance(asset: AssetId) -> Balance { 65 | ReserveMinimum::get(&asset) 66 | } 67 | 68 | fn minimum_bond_extra(asset: AssetId) -> Balance { 69 | BondExtra::get(&asset) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /pallets/remote-asset-manager/src/types.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | use codec::{Decode, Encode}; 5 | use frame_support::{sp_runtime::traits::AtLeast32BitUnsigned, RuntimeDebug}; 6 | use xcm::v1::{AssetId, Fungibility, Junction, Junctions, MultiAsset, MultiLocation}; 7 | 8 | /// Represents all XCM calls of the `pallet_staking` pallet transacted on a parachain 9 | #[derive(Default, Encode, Decode, Clone, PartialEq, RuntimeDebug, scale_info::TypeInfo)] 10 | pub struct XcmStakingMessageCount { 11 | /// Total number of all `pallet_staking::Pallet::bond_extra` calls transacted 12 | pub bond_extra: u32, 13 | /// Total number of all `pallet_staking::Pallet::unbond` calls transacted 14 | pub unbond: u32, 15 | /// Total number of all `pallet_staking::Pallet::withdraw_unbonded` calls transacted 16 | pub withdraw_unbonded: u32, 17 | } 18 | 19 | /// Represents the different balances of an asset 20 | #[derive(Default, Encode, Decode, Clone, PartialEq, RuntimeDebug, scale_info::TypeInfo)] 21 | pub struct AssetLedger { 22 | /// The real deposits contributed to the index 23 | pub deposited: Balance, 24 | /// the amount of the asset about to be withdrawn 25 | pub pending_redemption: Balance, 26 | } 27 | 28 | impl AssetLedger 29 | where 30 | Balance: AtLeast32BitUnsigned + Copy, 31 | { 32 | /// Cancel each balance out, after which at least 1 balance is zero. 33 | pub fn consolidate(&mut self) { 34 | let deposited = self.deposited; 35 | self.deposited = self.deposited.saturating_sub(self.pending_redemption); 36 | self.pending_redemption = self.pending_redemption.saturating_sub(deposited); 37 | } 38 | } 39 | 40 | /// Represents the config for the statemint parachain 41 | #[derive(Encode, Decode, Clone, PartialEq, RuntimeDebug, scale_info::TypeInfo)] 42 | #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] 43 | pub struct StatemintConfig { 44 | /// The id of the `statemint` parachain 45 | /// 46 | /// *NOTE* using `u32` here instead of location, since `MultiLocation` has 47 | /// no serde support 48 | pub parachain_id: u32, 49 | /// Whether interacting with the parachain is currently active 50 | pub enabled: bool, 51 | } 52 | 53 | impl StatemintConfig { 54 | /// The path to the `statemint` parachain 55 | /// 56 | /// *NOTE:* this is not the full path to the asset on the statemint chain 57 | pub fn parahain_location(&self) -> MultiLocation { 58 | MultiLocation::new(1, Junctions::X1(Junction::Parachain(self.parachain_id))) 59 | } 60 | } 61 | impl StatemintConfig { 62 | /// The XCM `MultiAsset` the statemint parachain expects in order to convert it correctly to the 63 | /// pint asset 64 | pub fn multi_asset(&self, amount: u128) -> MultiAsset { 65 | // TODO simplify when on polkadot-v0.9.9 (xcm-latest) with the correct asset id converter: 66 | // AsPrefixedGeneralIndex::reverse_ref(&self.pint_asset_id.into()) 67 | // where Local is MultiLocation = Junctions::Here.into() 68 | MultiAsset { id: AssetId::Concrete(MultiLocation::here()), fun: Fungibility::Fungible(amount) } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /pallets/remote-treasury/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ['ChainSafe Systems'] 3 | description = 'FRAME pallet to implement PINT remote treasury.' 4 | edition = '2018' 5 | license = 'LGPL-3.0-only' 6 | name = 'pallet-remote-treasury' 7 | readme = 'README.md' 8 | repository = 'https://github.com/ChainSafe/PINT/' 9 | version = '0.0.1' 10 | 11 | [dependencies] 12 | log = { version = "0.4.14", default-features = false } 13 | serde = { version = "1.0.130", features = ["derive"], optional = true } 14 | codec = { package = "parity-scale-codec", version = "2.3.1", default-features = false } 15 | scale-info = { version = "1.0", default-features = false, features = ["derive"] } 16 | 17 | # Substrate Dependencies 18 | frame-support = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 19 | frame-system = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 20 | frame-benchmarking = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false, optional = true } 21 | 22 | # Polkadot Dependencies 23 | xcm = { git = 'https://github.com/paritytech/polkadot', branch = 'release-v0.9.13', default-features = false } 24 | xcm-executor = { git = 'https://github.com/paritytech/polkadot', branch = 'release-v0.9.13', default-features = false } 25 | 26 | # PINT dependencies 27 | primitives = { path = "../../primitives/primitives", default-features = false } 28 | 29 | # orml Dependencies 30 | orml-traits = { git = 'https://github.com/open-web3-stack/open-runtime-module-library', branch = 'master', default-features = false } 31 | orml-xtokens = { git = 'https://github.com/open-web3-stack/open-runtime-module-library', branch = 'master', default-features = false } 32 | 33 | [dev-dependencies] 34 | serde = "1.0.130" 35 | sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 36 | sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 37 | sp-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 38 | frame-system = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 39 | frame-benchmarking = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 40 | 41 | pallet-balances = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 42 | 43 | [features] 44 | default = ['std'] 45 | std = [ 46 | 'serde', 47 | 'codec/std', 48 | 'log/std', 49 | 'frame-support/std', 50 | 'frame-system/std', 51 | 52 | 'xcm/std', 53 | 'xcm-executor/std', 54 | 55 | 'primitives/std', 56 | 57 | 'orml-traits/std', 58 | 'orml-xtokens/std', 59 | ] 60 | runtime-benchmarks = [ 61 | 'frame-benchmarking', 62 | 'frame-support/runtime-benchmarks', 63 | 'primitives/runtime-benchmarks', 64 | ] 65 | 66 | [package.metadata.docs.rs] 67 | targets = ['x86_64-unknown-linux-gnu'] 68 | -------------------------------------------------------------------------------- /pallets/remote-treasury/README.md: -------------------------------------------------------------------------------- 1 | License: LGPL-3.0-only -------------------------------------------------------------------------------- /pallets/saft-registry/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ['ChainSafe Systems'] 3 | description = 'FRAME pallet to implement PINT SAFT registry.' 4 | edition = '2018' 5 | license = 'LGPL-3.0-only' 6 | name = 'pallet-saft-registry' 7 | readme = 'README.md' 8 | repository = 'https://github.com/ChainSafe/PINT/' 9 | version = '0.0.1' 10 | 11 | [dependencies] 12 | codec = { package = "parity-scale-codec", version = "2.3.1", default-features = false } 13 | scale-info = { version = "1.0", default-features = false, features = ["derive"] } 14 | 15 | # Substrate Dependencies 16 | frame-support = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 17 | frame-system = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 18 | frame-benchmarking = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false, optional = true } 19 | 20 | # polkadot 21 | xcm = { git = 'https://github.com/paritytech/polkadot', branch = 'release-v0.9.13', default-features = false } 22 | 23 | # PINT dependencies 24 | pallet-asset-index = {path = "../asset-index", default-features = false } 25 | primitives = { path = "../../primitives/primitives", default-features = false } 26 | 27 | [dev-dependencies] 28 | serde = "1.0.130" 29 | 30 | # substrate 31 | sp-core = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 32 | sp-io = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 33 | sp-runtime = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 34 | 35 | pallet-balances = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 36 | 37 | pallet-asset-index= { path = "../asset-index" } 38 | pallet-remote-asset-manager = { path = "../remote-asset-manager" } 39 | pallet-price-feed = { path = "../price-feed" } 40 | 41 | # ORML Dependencies 42 | orml-traits = { git = 'https://github.com/open-web3-stack/open-runtime-module-library', branch = 'master' } 43 | orml-tokens = { git = 'https://github.com/open-web3-stack/open-runtime-module-library', branch = 'master' } 44 | 45 | [package.metadata.docs.rs] 46 | targets = ['x86_64-unknown-linux-gnu'] 47 | 48 | [features] 49 | default = ['std'] 50 | std = [ 51 | 'codec/std', 52 | 'frame-support/std', 53 | 'frame-system/std', 54 | 55 | 'xcm/std', 56 | 57 | 'primitives/std' 58 | ] 59 | runtime-benchmarks = [ 60 | 'frame-benchmarking', 61 | 'frame-support/runtime-benchmarks', 62 | 'pallet-asset-index/runtime-benchmarks', 63 | 'primitives/runtime-benchmarks', 64 | ] 65 | -------------------------------------------------------------------------------- /pallets/saft-registry/README.md: -------------------------------------------------------------------------------- 1 | License: LGPL-3.0-only -------------------------------------------------------------------------------- /pallets/saft-registry/src/benchmarking.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | #![cfg(feature = "runtime-benchmarks")] 5 | 6 | use frame_benchmarking::benchmarks; 7 | use frame_support::{assert_ok, dispatch::UnfilteredDispatchable, sp_runtime::traits::Zero, traits::EnsureOrigin}; 8 | use primitives::traits::AssetRecorderBenchmarks; 9 | use xcm::v1::{Junction, MultiLocation}; 10 | 11 | use crate::Pallet as SaftRegistry; 12 | 13 | use super::*; 14 | 15 | const MAX_SAFT_RECORDS: u32 = 100; 16 | 17 | benchmarks! { 18 | add_saft { 19 | let asset: T::AssetId = T::try_convert(2u8).unwrap(); 20 | let origin = T::AdminOrigin::successful_origin(); 21 | 22 | assert_ok!(T::AssetRecorderBenchmarks::add_asset( 23 | T::try_convert(3u8).unwrap(), 24 | 100u32.into(), 25 | MultiLocation::default(), 26 | 1000u32.into() 27 | )); 28 | 29 | let call = Call::::add_saft { 30 | asset_id: asset, 31 | nav: 100u32.into(), 32 | units: 20u32.into() 33 | }; 34 | }: { call.dispatch_bypass_filter(origin)? } 35 | verify { 36 | let id = SaftRegistry::::saft_counter(asset) - 1; 37 | assert_eq!( 38 | SaftRegistry::::active_safts(asset, id), 39 | Some(SAFTRecord::new(100_u32.into(), 20_u32.into())) 40 | ); 41 | } 42 | 43 | remove_saft { 44 | let asset: T::AssetId = T::try_convert(2u8).unwrap(); 45 | let origin = T::AdminOrigin::successful_origin(); 46 | let nav = 100u32.into(); 47 | let units = 20u32.into(); 48 | 49 | assert_ok!(T::AssetRecorderBenchmarks::add_asset( 50 | T::try_convert(3u8).unwrap(), 51 | 100u32.into(), 52 | MultiLocation::default(), 53 | 1000u32.into() 54 | )); 55 | 56 | assert_ok!(T::AssetRecorderBenchmarks::deposit_saft_equivalent(nav)); 57 | assert_ok!(SaftRegistry::::add_saft(origin.clone(), asset, nav, units)); 58 | 59 | let call = Call::::remove_saft { 60 | asset_id: asset, 61 | saft_id: 0u32 62 | } ; 63 | }: { call.dispatch_bypass_filter(origin)? } 64 | verify { 65 | assert!( 66 | SaftRegistry::::active_safts(asset, 0).is_none() 67 | ) 68 | } 69 | 70 | report_nav { 71 | let asset: T::AssetId = T::try_convert(2u8).unwrap(); 72 | let origin = T::AdminOrigin::successful_origin(); 73 | 74 | assert_ok!(T::AssetRecorderBenchmarks::add_asset( 75 | T::try_convert(3u8).unwrap(), 76 | 100u32.into(), 77 | MultiLocation::default(), 78 | 1000u32.into() 79 | )); 80 | 81 | assert_ok!(SaftRegistry::::add_saft( 82 | origin.clone(), 83 | asset, 84 | 100_u32.into(), 85 | 20_u32.into(), 86 | )); 87 | 88 | let call = Call::::report_nav { 89 | asset_id: asset, 90 | saft_id: 0, 91 | latest_nav: 1000_u32.into() 92 | }; 93 | }: { call.dispatch_bypass_filter(origin)? } 94 | verify { 95 | assert_eq!( 96 | SaftRegistry::::active_safts(asset, 0u32), 97 | Some(SAFTRecord::new(1000_u32.into(), 20_u32.into())) 98 | ); 99 | } 100 | 101 | convert_to_liquid { 102 | let o in 1 .. MAX_SAFT_RECORDS; 103 | 104 | let nav = 1337u32; 105 | let units = 1234u32; 106 | let asset:T::AssetId = T::try_convert(5u8).unwrap(); 107 | let origin = T::AdminOrigin::successful_origin(); 108 | 109 | assert_ok!(T::AssetRecorderBenchmarks::add_asset( 110 | T::try_convert(3u8).unwrap(), 111 | 100u32.into(), 112 | MultiLocation::default(), 113 | 1000u32.into() 114 | )); 115 | 116 | assert_ok!(SaftRegistry::::add_saft( 117 | origin.clone(), 118 | asset, 119 | nav.into(), 120 | units.into(), 121 | )); 122 | 123 | assert_ok!(>::try_mutate(asset, |counter: &mut u32| -> Result<(), ()> { 124 | *counter = o; 125 | Ok(()) 126 | })); 127 | 128 | let call = Call::::convert_to_liquid { 129 | asset_id: asset, 130 | location: (Junction::Parachain(100)).into() 131 | }; 132 | }: { call.dispatch_bypass_filter(origin)? } verify { 133 | assert_eq!( 134 | SaftRegistry::::saft_counter(asset), 135 | 0 136 | ); 137 | assert!( 138 | SaftRegistry::::saft_nav(asset).is_zero() 139 | ); 140 | } 141 | } 142 | 143 | #[cfg(test)] 144 | mod tests { 145 | use frame_support::assert_ok; 146 | 147 | use crate::mock::{new_test_ext, Test}; 148 | 149 | use super::*; 150 | 151 | #[test] 152 | fn add_saft() { 153 | new_test_ext().execute_with(|| { 154 | assert_ok!(Pallet::::test_benchmark_add_saft()); 155 | }); 156 | } 157 | 158 | #[test] 159 | fn remove_saft() { 160 | new_test_ext().execute_with(|| { 161 | assert_ok!(Pallet::::test_benchmark_remove_saft()); 162 | }); 163 | } 164 | 165 | #[test] 166 | fn report_nav() { 167 | new_test_ext().execute_with(|| { 168 | assert_ok!(Pallet::::test_benchmark_report_nav()); 169 | }); 170 | } 171 | 172 | #[test] 173 | fn convert_to_liquid() { 174 | new_test_ext().execute_with(|| { 175 | assert_ok!(Pallet::::test_benchmark_convert_to_liquid()); 176 | }); 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /pallets/saft-registry/src/traits.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | // TODO: This will be moved into the AssetIndex pallet when that is implemented 5 | // Required here for mock and testing the SAFT registry 6 | #![allow(dead_code)] 7 | 8 | use frame_support::sp_runtime::DispatchError; 9 | 10 | pub enum AssetAvailability { 11 | Liquid, 12 | SAFT, 13 | } 14 | 15 | pub trait AssetRecorder { 16 | /// Add an asset to the recorder. If an asset with the given AssetId already exists 17 | /// then the added asset units will be combined. 18 | /// The provided NAV parameter is the Net Asset Value of the total units provided 19 | /// given in units of some stable asset. In the case of an AssetId that already exists the 20 | /// newly provided NAV will be used to re-value the existing units and compute a total NAV 21 | fn add_asset( 22 | id: &AssetId, 23 | units: &Balance, 24 | availability: &AssetAvailability, 25 | nav: &Balance, 26 | ) -> Result<(), DispatchError>; 27 | 28 | fn remove_asset(id: &AssetId) -> Result<(), DispatchError>; 29 | 30 | fn update_nav(id: &AssetId, nav: &Balance) -> Result<(), DispatchError>; 31 | } 32 | -------------------------------------------------------------------------------- /primitives/derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ['ChainSafe Systems'] 3 | description = 'PINT proc-macros' 4 | edition = "2018" 5 | license = 'LGPL-3.0-only' 6 | name = "derive" 7 | repository = 'https://github.com/ChainSafe/PINT/' 8 | version = "0.0.1" 9 | 10 | [lib] 11 | proc-macro = true 12 | 13 | [dependencies] 14 | proc-macro2 = "1.0.32" 15 | quote = "1.0.10" 16 | syn = { version = "1.0.81", features = ["full"] } 17 | -------------------------------------------------------------------------------- /primitives/derive/README.md: -------------------------------------------------------------------------------- 1 | # derive 2 | 3 | This module contains `proc-macro`s for developing and testing. 4 | 5 | ## #[xcm_error] 6 | 7 | Provides a `From` implementation, could be used for `pallet::Error`. 8 | 9 | For example: 10 | 11 | ```rust 12 | #[pallet:error] 13 | #[xcm_error] 14 | pub enum Error { 15 | // ... 16 | } 17 | ``` 18 | -------------------------------------------------------------------------------- /primitives/derive/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | //! PINT proc-macros 4 | extern crate proc_macro; 5 | 6 | // mod derive; 7 | mod xcm; 8 | 9 | use proc_macro::TokenStream; 10 | 11 | /// `#[xcm_error]` 12 | /// 13 | /// This macro is used for expand errors of xcm::v0::Error 14 | #[proc_macro_attribute] 15 | pub fn xcm_error(_attr: TokenStream, item: TokenStream) -> TokenStream { 16 | xcm::error(item) 17 | } 18 | -------------------------------------------------------------------------------- /primitives/derive/src/xcm/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | //! XCM macros 4 | mod result; 5 | 6 | pub use result::error; 7 | -------------------------------------------------------------------------------- /primitives/derive/src/xcm/result.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | //! XCM errors 4 | use proc_macro::TokenStream; 5 | use proc_macro2::Span; 6 | use quote::quote; 7 | use syn::{ 8 | parse_macro_input, punctuated::Punctuated, token::Comma, Arm, DeriveInput, Expr, ExprMatch, Ident, Pat, PatTuple, 9 | PatTupleStruct, Path, PathArguments, PathSegment, 10 | }; 11 | 12 | const XCM_ERRORS: [&str; 27] = [ 13 | "Undefined", 14 | "Unimplemented", 15 | "Overflow", 16 | "UnhandledXcmVersion", 17 | "UnhandledXcmMessage", 18 | "UnhandledEffect", 19 | "EscalationOfPrivilege", 20 | "UntrustedReserveLocation", 21 | "UntrustedTeleportLocation", 22 | "DestinationBufferOverflow", 23 | "SendFailed(_)", 24 | "CannotReachDestination(_, _)", 25 | "MultiLocationFull", 26 | "FailedToDecode", 27 | "BadOrigin", 28 | "ExceedsMaxMessageSize", 29 | "FailedToTransactAsset(_)", 30 | "WeightLimitReached(_)", 31 | "Wildcard", 32 | "TooMuchWeightRequired", 33 | "NotHoldingFees", 34 | "WeightNotComputable", 35 | "Barrier", 36 | "NotWithdrawable", 37 | "LocationCannotHold", 38 | "TooExpensive", 39 | "AssetNotFound", 40 | ]; 41 | 42 | /// Expand xcm errors 43 | pub fn expand_errors() -> Vec { 44 | XCM_ERRORS 45 | .iter() 46 | .map(|i| { 47 | let ident = Ident::new(if let Some(idx) = i.find('(') { &i[0..idx] } else { i }, Span::call_site()); 48 | let (body, pat) = (ident.clone(), { 49 | let count = i.matches('_').count(); 50 | if count == 0 { 51 | Pat::Verbatim(quote! { XcmError::#ident }) 52 | } else { 53 | let mut elems = Punctuated::new(); 54 | for _ in 0..count { 55 | elems.push(Pat::Verbatim(quote! { _ })); 56 | } 57 | 58 | let mut segments = Punctuated::new(); 59 | segments.push(PathSegment { ident, arguments: PathArguments::None }); 60 | 61 | let ts = Pat::TupleStruct(PatTupleStruct { 62 | attrs: Default::default(), 63 | path: Path { leading_colon: None, segments }, 64 | pat: PatTuple { attrs: Default::default(), paren_token: Default::default(), elems }, 65 | }); 66 | 67 | Pat::Verbatim(quote! { XcmError::#ts }) 68 | } 69 | }); 70 | 71 | Arm { 72 | attrs: Default::default(), 73 | pat, 74 | guard: None, 75 | fat_arrow_token: Default::default(), 76 | body: Box::new(Expr::Verbatim(quote! { Self::#body })), 77 | comma: Some(Comma::default()), 78 | } 79 | }) 80 | .collect() 81 | } 82 | 83 | fn expand_match(arms: Vec) -> ExprMatch { 84 | ExprMatch { 85 | attrs: Default::default(), 86 | match_token: Default::default(), 87 | expr: Box::new(Expr::Verbatim(quote! {e})), 88 | brace_token: Default::default(), 89 | arms, 90 | } 91 | } 92 | 93 | /// Extends xcm errors 94 | pub fn error(input: TokenStream) -> TokenStream { 95 | let input = parse_macro_input!(input as DeriveInput); 96 | 97 | // construct expr match 98 | let xcm_match = expand_match(expand_errors()); 99 | 100 | // get generics 101 | let ident = &input.ident; 102 | let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); 103 | 104 | let expanded = quote! { 105 | use xcm::v0::Error as XcmError; 106 | 107 | #input 108 | 109 | impl #impl_generics From for #ident #ty_generics #where_clause { 110 | fn from(e: XcmError) -> Self { 111 | #xcm_match 112 | } 113 | } 114 | }; 115 | 116 | TokenStream::from(expanded) 117 | } 118 | -------------------------------------------------------------------------------- /primitives/primitives/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ['ChainSafe Systems'] 3 | description = 'Primitive types and traits for PINT.' 4 | edition = '2018' 5 | license = 'LGPL-3.0-only' 6 | name = 'primitives' 7 | readme = 'README.md' 8 | repository = 'https://github.com/ChainSafe/PINT/' 9 | version = '0.0.1' 10 | 11 | [dependencies] 12 | serde = { version = "1.0.130", features = ["derive"], optional = true } 13 | codec = { package = "parity-scale-codec", version = "2.3.1", default-features = false, features = ['derive'] } 14 | scale-info = { version = "1.0", default-features = false, features = ["derive"] } 15 | frame-support = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 16 | frame-system = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 17 | 18 | # Polkadot Dependencies 19 | xcm = { git = 'https://github.com/paritytech/polkadot', branch = 'release-v0.9.13', default-features = false } 20 | 21 | [features] 22 | default = ['std'] 23 | std = [ 24 | 'serde', 25 | 'codec/std', 26 | 'frame-support/std', 27 | 'frame-system/std', 28 | 'xcm/std', 29 | ] 30 | runtime-benchmarks = [] 31 | 32 | [package.metadata.docs.rs] 33 | targets = ['x86_64-unknown-linux-gnu'] 34 | -------------------------------------------------------------------------------- /primitives/primitives/README.md: -------------------------------------------------------------------------------- 1 | License: LGPL-3.0-only -------------------------------------------------------------------------------- /primitives/primitives/src/fee.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | //! Fee types used in PINT pallets 5 | 6 | use codec::{Decode, Encode}; 7 | use frame_support::sp_runtime::traits::AtLeast32Bit; 8 | 9 | /// Represents the fee rate where fee_rate = numerator / denominator 10 | #[derive(Debug, Encode, Decode, Copy, Clone, PartialEq, Eq, scale_info::TypeInfo)] 11 | #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] 12 | pub struct FeeRate { 13 | pub numerator: u32, 14 | pub denominator: u32, 15 | } 16 | 17 | impl Default for FeeRate { 18 | fn default() -> Self { 19 | // 0.3% 20 | Self { numerator: 3, denominator: 1_000 } 21 | } 22 | } 23 | 24 | pub trait BaseFee 25 | where 26 | Self: Sized, 27 | { 28 | /// Returns the given amount after applying the fee rate: `self - fee` 29 | fn without_fee(&self, rate: FeeRate) -> Option; 30 | 31 | /// Returns the fees only. 32 | fn fee(&self, rate: FeeRate) -> Option; 33 | } 34 | 35 | impl BaseFee for u128 { 36 | fn without_fee(&self, rate: FeeRate) -> Option { 37 | self.checked_mul(rate.denominator as Self)?.checked_div(rate.denominator as Self + rate.numerator as Self) 38 | } 39 | 40 | fn fee(&self, rate: FeeRate) -> Option { 41 | self.checked_mul(rate.numerator as Self)?.checked_div(rate.denominator as Self) 42 | } 43 | } 44 | 45 | /// Determines the fee upon index token redemptions from range 46 | #[derive(Clone, Decode, Debug, Default, Encode, PartialEq, Eq, scale_info::TypeInfo)] 47 | pub struct RedemptionFeeRange { 48 | pub range: [(BlockNumber, FeeRate); 2], 49 | pub default_fee: FeeRate, 50 | } 51 | 52 | impl RedemptionFeeRange { 53 | /// get fee rate by spent time 54 | fn get_rate(&self, spent_time: BlockNumber) -> FeeRate { 55 | if spent_time < self.range[0].0 { 56 | self.range[0].1 57 | } else if spent_time <= self.range[1].0 { 58 | self.range[1].1 59 | } else { 60 | self.default_fee 61 | } 62 | } 63 | 64 | /// Determines the redemption fee based on how long the given amount were held in the index 65 | /// 66 | /// Parameters: 67 | /// - `time_spent`: The number of blocks the amount were held in the index. This is `current 68 | /// block - deposit`. 69 | /// - `amount`: The amount of index tokens withdrawn 70 | pub fn redemption_fee(&self, time_spent: BlockNumber, amount: Balance) -> Option { 71 | amount.fee(self.get_rate(time_spent)) 72 | } 73 | } 74 | 75 | #[cfg(test)] 76 | mod tests { 77 | use super::*; 78 | 79 | #[test] 80 | fn test_fee_calculations() { 81 | let rate = FeeRate { numerator: 3, denominator: 1_000 }; 82 | 83 | assert_eq!(1_003.without_fee(rate), Some(1_000)); 84 | assert_eq!(1_003.fee(rate), Some(3)); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /primitives/primitives/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | //! Primitive types used within PINT 5 | #![cfg_attr(not(feature = "std"), no_std)] 6 | 7 | pub mod fee; 8 | pub mod traits; 9 | pub mod types; 10 | 11 | pub use types::*; 12 | -------------------------------------------------------------------------------- /primitives/xcm-calls/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ['ChainSafe Systems'] 3 | description = 'FRAME pallet with XCM bindings to FRAME pallets.' 4 | edition = '2018' 5 | license = 'LGPL-3.0-only' 6 | name = 'xcm-calls' 7 | readme = 'README.md' 8 | repository = 'https://github.com/ChainSafe/PINT/' 9 | version = '0.0.1' 10 | 11 | [dependencies] 12 | serde = { version = "1.0.130", features = ["derive"], optional = true } 13 | codec = { package = "parity-scale-codec", version = "2.3.1", default-features = false, features = ['derive'] } 14 | scale-info = { version = "1.0", default-features = false, features = ["derive"] } 15 | frame-support = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 16 | frame-system = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 17 | 18 | [dev-dependencies] 19 | sp-core = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 20 | sp-runtime = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 21 | sp-staking = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 22 | frame-election-provider-support = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 23 | 24 | 25 | ## Substrate Pallet Dependencies 26 | pallet-assets = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 27 | pallet-staking = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 28 | pallet-proxy = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 29 | pallet-utility = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 30 | pallet-balances = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13'} 31 | pallet-staking-reward-curve = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 32 | pallet-timestamp = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 33 | pallet-session = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 34 | pallet-bags-list = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 35 | sp-npos-elections = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13' } 36 | 37 | # Polkadot Dependencies 38 | xcm = { git = 'https://github.com/paritytech/polkadot', branch = 'release-v0.9.13' } 39 | 40 | [features] 41 | default = ['std'] 42 | std = [ 43 | 'serde', 44 | 'codec/std', 45 | 'frame-support/std', 46 | 'frame-system/std' 47 | ] 48 | # this feature is only for compilation now 49 | runtime-benchmarks = [] 50 | 51 | [package.metadata.docs.rs] 52 | targets = ['x86_64-unknown-linux-gnu'] 53 | -------------------------------------------------------------------------------- /primitives/xcm-calls/README.md: -------------------------------------------------------------------------------- 1 | # Primitives for cross chain Messages 2 | 3 | This module contains bindings for calls of various FRAME pallets: 4 | 5 | * [Assets Pallet](https://crates.parity.io/pallet_assets/pallet/index.html) 6 | * [Proxy Pallet](https://crates.parity.io/pallet_proxy/pallet/index.html) 7 | * [Staking Pallet](https://crates.parity.io/pallet_staking/index.html) 8 | 9 | Since the generic datatypes of a pallet are dependent on their runtime configuration of a parachains, the encoding to use when sending a [`Xcm::Transact`](https://github.com/paritytech/xcm-format#transact) is depending on the destination of a cross chain message. 10 | 11 | In order for the call to be decodable on the target chain (see Polkadot's [`XcmExecutor`](https://github.com/paritytech/polkadot/tree/master/xcm/xcm-executor)), it must be encoded with the corresponding index of the pallet, which also depends on the runtime configuration of the parachain. 12 | 13 | This provides module provides an excerpt from each pallet's call variants that are used for PINT's cross chain operations. 14 | Each Pallet includes their own encoder type that expects encoders for every generic datatype of the pallet. -------------------------------------------------------------------------------- /primitives/xcm-calls/src/encode_with.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | //! Additional types for the remote asset manager pallet 5 | 6 | use codec::{Encode, EncodeAsRef, HasCompact, Output}; 7 | use frame_support::{sp_runtime::MultiAddress, sp_std::marker::PhantomData}; 8 | 9 | /// A helper to encode an item using the provided context 10 | pub trait EncodeWith { 11 | /// Same as `Encode::encode_to` but with additional context 12 | fn encode_to_with(input: &Input, ctx: &Context, dest: &mut T); 13 | } 14 | 15 | /// Encodes the type as it is 16 | pub struct PassthroughEncoder(PhantomData<(I, T)>); 17 | 18 | impl EncodeWith for PassthroughEncoder { 19 | fn encode_to_with(input: &I, _: &Context, dest: &mut T) { 20 | input.encode_to(dest) 21 | } 22 | } 23 | 24 | /// Encodes the type as it is but compact 25 | pub struct PassthroughCompactEncoder(PhantomData<(I, T)>); 26 | 27 | impl EncodeWith for PassthroughCompactEncoder { 28 | fn encode_to_with(input: &I, _: &Context, dest: &mut T) { 29 | <::Type as EncodeAsRef<'_, I>>::RefType::from(input).encode_to(dest) 30 | } 31 | } 32 | 33 | /// Encodes an `AccountId` as `Multiaddress` regardless of the asset id 34 | pub struct MultiAddressLookupSourceEncoder( 35 | PhantomData<(AccountId, AccountIndex, Context)>, 36 | ); 37 | 38 | impl EncodeWith 39 | for MultiAddressLookupSourceEncoder 40 | where 41 | AccountId: Encode + Clone, 42 | AccountIndex: HasCompact, 43 | { 44 | fn encode_to_with(account: &AccountId, _: &Context, dest: &mut T) { 45 | MultiAddress::::from(account.clone()).encode_to(dest) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /primitives/xcm-calls/src/proxy.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | //! Xcm support for dispatching `pallet_proxy` pallet calls 5 | 6 | use codec::{Decode, Encode, MaxEncodedLen, Output}; 7 | use frame_support::{sp_std::vec::Vec, weights::Weight, RuntimeDebug}; 8 | #[cfg(feature = "std")] 9 | use serde::{Deserialize, Serialize}; 10 | 11 | use crate::{CallEncoder, EncodeWith, PalletCall, PalletCallEncoder}; 12 | 13 | /// The index of `pallet_proxy` in the polkadot runtime 14 | pub const POLKADOT_PALLET_PROXY_INDEX: u8 = 29u8; 15 | 16 | /// The identifier the `ProxyType::Staking` variant encodes to 17 | pub const POLKADOT_PALLET_PROXY_TYPE_STAKING_INDEX: u8 = 3u8; 18 | 19 | /// Denotes an enum based (identified by an `u8`) proxy type 20 | #[derive( 21 | Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, MaxEncodedLen, scale_info::TypeInfo, 22 | )] 23 | pub struct ProxyType(pub u8); 24 | 25 | impl From for ProxyType { 26 | fn from(x: u8) -> Self { 27 | ProxyType(x) 28 | } 29 | } 30 | 31 | impl ProxyType { 32 | /// Represents the `Staking` variant of the polkadot `ProxyType` enum 33 | pub const fn polkadot_staking() -> Self { 34 | ProxyType(POLKADOT_PALLET_PROXY_TYPE_STAKING_INDEX) 35 | } 36 | } 37 | 38 | /// Provides encoder types to encode the associated types of the 39 | /// `pallet_proxy::Config` trait depending on the configured Context. 40 | pub trait ProxyCallEncoder: PalletCallEncoder { 41 | /// Encodes the `::AccountId` depending on the context 42 | type AccountIdEncoder: EncodeWith; 43 | 44 | /// Encodes the `::ProxyType` depending on the context 45 | type ProxyTypeEncoder: EncodeWith; 46 | 47 | /// Encodes the `::BlockNumber` depending on the 48 | /// context 49 | type BlockNumberEncoder: EncodeWith; 50 | } 51 | 52 | impl<'a, 'b, AccountId, ProxyType, BlockNumber, Config> Encode 53 | for CallEncoder<'a, 'b, ProxyCall, Config> 54 | where 55 | Config: ProxyCallEncoder, 56 | { 57 | fn encode_to(&self, dest: &mut T) { 58 | // include the pallet identifier 59 | dest.push_byte(self.call.pallet_call_index()); 60 | match self.call { 61 | ProxyCall::AddProxy(params) | ProxyCall::RemoveProxy(params) => { 62 | Config::AccountIdEncoder::encode_to_with(¶ms.delegate, self.ctx, dest); 63 | Config::ProxyTypeEncoder::encode_to_with(¶ms.proxy_type, self.ctx, dest); 64 | Config::BlockNumberEncoder::encode_to_with(¶ms.delay, self.ctx, dest); 65 | } 66 | } 67 | } 68 | } 69 | 70 | /// Represents dispatchable calls of the FRAME `pallet_proxy` pallet. 71 | /// 72 | /// This is a generic version of the `pallet_proxy::Call` enum generated by the substrate pallet 73 | /// macros 74 | #[derive(Clone, PartialEq, RuntimeDebug, scale_info::TypeInfo)] 75 | pub enum ProxyCall { 76 | /// The [`add_proxy`](https://crates.parity.io/pallet_proxy/pallet/enum.Call.html#variant.add_proxy) extrinsic. 77 | /// 78 | /// Register a proxy account for the sender that is able to make calls on 79 | /// its behalf. 80 | AddProxy(ProxyParams), 81 | /// The [`remove_proxy`](https://crates.parity.io/pallet_proxy/pallet/enum.Call.html#variant.remove_proxy) extrinsic. 82 | /// 83 | /// Unregister a proxy account for the sender.. 84 | RemoveProxy(ProxyParams), 85 | } 86 | 87 | #[derive(Clone, PartialEq, RuntimeDebug, scale_info::TypeInfo)] 88 | pub struct ProxyParams { 89 | /// The account that the `caller` would like to make a proxy. 90 | pub delegate: AccountId, 91 | /// The permissions to add/remove for this proxy account. 92 | pub proxy_type: ProxyType, 93 | /// The announcement period required of the initial proxy. Will generally be 94 | /// zero 95 | pub delay: BlockNumber, 96 | } 97 | 98 | impl PalletCall for ProxyCall { 99 | /// the indices of the corresponding calls within the `pallet_proxy` 100 | fn pallet_call_index(&self) -> u8 { 101 | match self { 102 | ProxyCall::AddProxy(_) => 1, 103 | ProxyCall::RemoveProxy(_) => 2, 104 | } 105 | } 106 | } 107 | 108 | /// Denotes the current state of proxies for the PINT chain's account 109 | #[derive(Encode, Decode, Clone, PartialEq, RuntimeDebug, Default, scale_info::TypeInfo)] 110 | pub struct ProxyState { 111 | /// All the added Proxy types 112 | pub added: Vec, 113 | } 114 | 115 | impl ProxyState { 116 | /// Whether the given proxy is already set 117 | pub fn contains(&self, proxy: &ProxyType) -> bool { 118 | self.added.contains(proxy) 119 | } 120 | 121 | /// Adds the proxy to the list 122 | /// 123 | /// *NOTE:* the caller must check `contains` first 124 | pub fn add(&mut self, proxy: ProxyType) { 125 | self.added.push(proxy) 126 | } 127 | } 128 | 129 | /// The `pallet_proxy` configuration for a particular chain 130 | #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] 131 | #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] 132 | pub struct ProxyConfig { 133 | /// The index of `pallet_index` within the parachain's runtime 134 | pub pallet_index: u8, 135 | /// The configured weights for `pallet_proxy` 136 | pub weights: ProxyWeights, 137 | } 138 | 139 | /// Represents an excerpt from the `pallet_proxy` weights 140 | #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] 141 | #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] 142 | pub struct ProxyWeights { 143 | /// Weight for `add_proxy` extrinsic 144 | pub add_proxy: Weight, 145 | /// Weight for `remove_proxy` extrinsic 146 | pub remove_proxy: Weight, 147 | } 148 | -------------------------------------------------------------------------------- /primitives/xcm-calls/src/utility.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | //! Xcm support for dispatching `pallet_utility` pallet calls 5 | 6 | use codec::{Decode, Encode, Output}; 7 | use frame_support::{sp_std::vec::Vec, RuntimeDebug}; 8 | 9 | use crate::{CallEncoder, PalletCall, PalletCallEncoder}; 10 | 11 | /// The index of `pallet_utility` in the polkadot runtime 12 | pub const POLKADOT_PALLET_UTILITY_INDEX: u8 = 26u8; 13 | 14 | /// The index of `pallet_utility` in the polkadot runtime 15 | pub const KUSAMA_PALLET_UTILITY_INDEX: u8 = 24u8; 16 | 17 | pub trait UtilityCallEncoder: PalletCallEncoder {} 18 | 19 | impl<'a, 'b, Config> Encode for CallEncoder<'a, 'b, UtilityCall, Config> 20 | where 21 | Config: UtilityCallEncoder, 22 | { 23 | fn encode_to(&self, dest: &mut T) { 24 | // include the pallet identifier 25 | dest.push_byte(self.call.pallet_call_index()); 26 | self.call.encode_to(dest) 27 | } 28 | } 29 | 30 | /// Represents dispatchable calls of the FRAME `pallet_utility` pallet. 31 | /// 32 | /// This is a generic version of the `pallet_utility::Call` enum generated by the substrate pallet 33 | /// macros 34 | #[derive(Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] 35 | pub enum UtilityCall { 36 | #[codec(index = 1)] 37 | AsDerivative(u16, Vec), 38 | #[codec(index = 2)] 39 | BatchAll(Vec>), 40 | } 41 | 42 | impl PalletCall for UtilityCall { 43 | /// the indices of the corresponding calls within the `pallet_utility` 44 | fn pallet_call_index(&self) -> u8 { 45 | match self { 46 | UtilityCall::AsDerivative(_, _) => 1, 47 | UtilityCall::BatchAll(_) => 2, 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /resources/README.md: -------------------------------------------------------------------------------- 1 | This folder contains: 2 | 3 | * [types.json](./types.json): The specific type configuration and custom datatypes the PINT runtime uses. This is 4 | required for the polkadot JS UI in order to properly connect to a running node. This also includes all custom types 5 | used by the [chainlink-feed-pallet](https://github.com/smartcontractkit/chainlink-polkadot) 6 | 7 | ## Chain Specs 8 | 9 | _These are for demonstration purposes only for configuring the Genesis state for palettes and should be exported and 10 | modified from the compiled chain with:_ 11 | 12 | ```bash 13 | ./target/debug/pint build-spec --dev --disable-default-bootnode > resources/pint-dev.json 14 | ``` 15 | 16 | * [pint-dev.json](pint-dev.json) Basic chain sepc. All developer accounts are prefunded with `1 << 60` units. This can 17 | easily be adjusted to something else and then started as dev chain 18 | with `./target/debug/pint --tmp --chain pint-local-plain.json --instant-sealing ` 19 | * [pint-dev-with-chainlink-feed.json](pint-dev-with-chainlink-feed.json) contains a chainlink feed at genesis as 20 | described [here](https://github.com/smartcontractkit/chainlink-polkadot/tree/master/substrate-node-example/specs). -------------------------------------------------------------------------------- /resources/types.json: -------------------------------------------------------------------------------- 1 | { 2 | "Address": "MultiAddress", 3 | "LookupSource": "MultiAddress", 4 | "LookupSourceFor": "LookupSource", 5 | "Action": "Call", 6 | "AccountIdFor": "AccountId", 7 | "AccountBalance": { 8 | "available": "Balance", 9 | "reserved": "Balance" 10 | }, 11 | "Amount": "i128", 12 | "AssetAvailability": { 13 | "_enum": { 14 | "Liquid": "MultiLocation", 15 | "Saft": null 16 | } 17 | }, 18 | "AssetConfig": { 19 | "pallet_index": "u8", 20 | "weights": "AssetsWeights" 21 | }, 22 | "AssetId": "u32", 23 | "AssetsWeights": { 24 | "mint": "Weight", 25 | "burn": "Weight", 26 | "transfer": "Weight", 27 | "force_transfer": "Weight", 28 | "freeze": "Weight", 29 | "thaw": "Weight", 30 | "freeze_asset": "Weight", 31 | "thaw_asset": "Weight", 32 | "approve_transfer": "Weight", 33 | "cancel_approval": "Weight", 34 | "transfer_approved": "Weight" 35 | }, 36 | "AssetMetadata": { 37 | "name": "BoundedString", 38 | "symbol": "BoundedString", 39 | "decimals": "u8" 40 | }, 41 | "AssetWithdrawal": { 42 | "asset": "AssetId", 43 | "reserved": "Balance", 44 | "units": "Balance", 45 | "withdrawn": "bool" 46 | }, 47 | "Balance": "u128", 48 | "BalanceFor": "Balance", 49 | "BoundedString": "BoundedVec", 50 | "CommitteeMember": { 51 | "account_id": "AccountId", 52 | "member_type": "MemberType" 53 | }, 54 | "CurrencyId": "AssetId", 55 | "CurrencyIdOf": "CurrencyId", 56 | "DepositRange": { 57 | "minimum": "Balance", 58 | "maximum": "Balance" 59 | }, 60 | "FeeRate": { 61 | "numerator": "u32", 62 | "denominator": "u32" 63 | }, 64 | "FeedId": "u64", 65 | "FeedIdFor": "FeedId", 66 | "HashFor": "Hash", 67 | "IndexAssetData": { 68 | "units": "Balance", 69 | "availability": "AssetAvailability" 70 | }, 71 | "MemberType": { 72 | "_enum": { 73 | "Council": null, 74 | "Constituent": null 75 | } 76 | }, 77 | "MemberVote": { 78 | "member": "CommitteeMember", 79 | "vote": "VoteKind" 80 | }, 81 | "OrmlAccountData": { 82 | "free": "Balance", 83 | "frozen": "Balance", 84 | "reserved": "Balance" 85 | }, 86 | "PendingRedemption": { 87 | "end_block": "BlockNumber", 88 | "assets": "Vec" 89 | }, 90 | "Proposal": { 91 | "nonce": "ProposalNonce", 92 | "action": "Call", 93 | "status": "ProposalStatus" 94 | }, 95 | "ProposalStatus": { 96 | "_enum": [ 97 | "Active", 98 | "Executed", 99 | "Timeout" 100 | ] 101 | }, 102 | "ProposalNonce": "u32", 103 | "ProxyType": { 104 | "_enum": [ 105 | "Any", 106 | "NonTransfer", 107 | "Governance", 108 | "Staking" 109 | ] 110 | }, 111 | "ProxyState": { 112 | "added": "Vec" 113 | }, 114 | "ProxyWeights": { 115 | "add_proxy": "Weight", 116 | "remove_proxy": "Weight" 117 | }, 118 | "RedemptionFeeRange": { 119 | "range": "[(BlockNumber, FeeRate); 2]", 120 | "default_fee": "FeeRate" 121 | }, 122 | "RedemptionState": { 123 | "_enum": { 124 | "Initiated": null, 125 | "Unbonding": null, 126 | "Transferred": null 127 | } 128 | }, 129 | "SAFTId": "u32", 130 | "SAFTRecord": { 131 | "nav": "Balance", 132 | "units": "Balance" 133 | }, 134 | "StakingLedger": { 135 | "controller": "LookupSourceFor", 136 | "active": "Balance", 137 | "total": "Balance", 138 | "unlocking": "Vec" 139 | }, 140 | "StakingLedgerFor": "StakingLedger", 141 | "StakingWeights": { 142 | "bond": "Weight", 143 | "bond_extra": "Weight", 144 | "unbond": "Weight", 145 | "withdraw_unbonded": "Weight" 146 | }, 147 | "StatemintConfig": { 148 | "parachain_id": "u32", 149 | "enabled": "bool", 150 | "pint_asset_id": "AssetId" 151 | }, 152 | "UnlockChunk": { 153 | "value": "Balance", 154 | "end": "BlockNumber" 155 | }, 156 | "VoteKind": { 157 | "_enum": { 158 | "Aye": null, 159 | "Nay": null, 160 | "Abstain": null 161 | } 162 | }, 163 | "VoteAggregate": { 164 | "votes": "Vec", 165 | "end": "BlockNumber" 166 | } 167 | } -------------------------------------------------------------------------------- /rpc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ['ChainSafe Systems'] 3 | description = 'PINT specific RPC.' 4 | edition = '2018' 5 | license = 'LGPL-3.0-only' 6 | name = 'pint-rpc' 7 | repository = 'https://github.com/ChainSafe/PINT/' 8 | version = '0.0.1' 9 | 10 | [dependencies] 11 | jsonrpc-core = "18.0.0" 12 | codec = { package = "parity-scale-codec", version = "2.3.1" } 13 | sp-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 14 | sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 15 | sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 16 | sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 17 | sc-transaction-pool-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 18 | #sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 19 | sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 20 | sc-rpc = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 21 | sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 22 | substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 23 | pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } 24 | 25 | # PINT dependencies 26 | pallet-asset-index-rpc= { path = "../pallets/asset-index/rpc" } 27 | primitives = { path = "../primitives/primitives" } 28 | 29 | [package.metadata.docs.rs] 30 | targets = ['x86_64-unknown-linux-gnu'] 31 | -------------------------------------------------------------------------------- /rpc/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | //! PINT-specific RPCs implementation. 5 | 6 | #![warn(missing_docs)] 7 | 8 | use primitives::{AccountId, AssetId, Balance, Block, Nonce}; 9 | pub use sc_rpc_api::DenyUnsafe; 10 | use sc_transaction_pool_api::TransactionPool; 11 | use sp_api::ProvideRuntimeApi; 12 | use sp_block_builder::BlockBuilder; 13 | use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; 14 | use std::sync::Arc; 15 | 16 | pub use sc_rpc::SubscriptionTaskExecutor; 17 | 18 | /// A type representing all RPC extensions. 19 | pub type RpcExtension = jsonrpc_core::IoHandler; 20 | 21 | /// Full client dependencies. 22 | pub struct FullDeps { 23 | /// The client instance to use. 24 | pub client: Arc, 25 | /// Transaction pool instance. 26 | pub pool: Arc

, 27 | /// Whether to deny unsafe calls 28 | pub deny_unsafe: DenyUnsafe, 29 | } 30 | 31 | /// Instantiate all Full RPC extensions. 32 | pub fn create_full(deps: FullDeps) -> RpcExtension 33 | where 34 | C: ProvideRuntimeApi, 35 | C: HeaderBackend + HeaderMetadata, 36 | C: Send + Sync + 'static, 37 | C::Api: substrate_frame_rpc_system::AccountNonceApi, 38 | C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, 39 | C::Api: pallet_asset_index_rpc::AssetIndexRuntimeApi, 40 | C::Api: BlockBuilder, 41 | P: TransactionPool + Sync + Send + 'static, 42 | { 43 | use pallet_asset_index_rpc::{AssetIndexApi, AssetIndexBackend}; 44 | use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; 45 | use substrate_frame_rpc_system::{FullSystem, SystemApi}; 46 | 47 | let mut io = jsonrpc_core::IoHandler::default(); 48 | let FullDeps { client, pool, deny_unsafe } = deps; 49 | 50 | io.extend_with(SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe))); 51 | io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new(client.clone()))); 52 | // Making synchronous calls in light client freezes the browser currently, 53 | // more context: https://github.com/paritytech/substrate/pull/3480 54 | // These RPCs should use an asynchronous caller instead. 55 | io.extend_with(AssetIndexApi::to_delegate(AssetIndexBackend::new(client))); 56 | io 57 | } 58 | -------------------------------------------------------------------------------- /runtime/common/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ['ChainSafe Systems'] 3 | edition = '2018' 4 | homepage = 'https://github.com/ChainSafe/PINT' 5 | license = 'LGPL-3.0-only' 6 | name = 'runtime-common' 7 | repository = 'https://github.com/substrate-developer-hub/substrate-parachain-template' 8 | version = '0.0.1' 9 | 10 | [dependencies] 11 | codec = { package = "parity-scale-codec", version = "2.3.1", default-features = false, features = ['derive'] } 12 | scale-info = { version = "1.0", default-features = false, features = ["derive"] } 13 | 14 | frame-support = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 15 | frame-system = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 16 | sp-std = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.13', default-features = false } 17 | 18 | # xcm 19 | xcm = { git = 'https://github.com/paritytech/polkadot', branch = 'release-v0.9.13', default-features = false } 20 | xcm-calls = { path = "../../primitives/xcm-calls", default-features = false } 21 | cumulus-pallet-xcm = { git = 'https://github.com/paritytech/cumulus', branch = 'polkadot-v0.9.13', default-features = false } 22 | 23 | # orml 24 | orml-traits = { git = 'https://github.com/open-web3-stack/open-runtime-module-library', branch = 'master', default-features = false } 25 | 26 | # chainlink 27 | pallet-chainlink-feed = { git = 'https://github.com/smartcontractkit/chainlink-polkadot', branch = 'polkadot-v0.9.13', default-features = false } 28 | 29 | # pint 30 | primitives = { path = '../../primitives/primitives', default-features = false } 31 | pallet-committee = {path = '../../pallets/committee', default-features = false } 32 | pallet-local-treasury = {path = '../../pallets/local-treasury', default-features = false } 33 | pallet-asset-index = {path = '../../pallets/asset-index', default-features = false } 34 | pallet-saft-registry = {path = '../../pallets/saft-registry', default-features = false } 35 | pallet-price-feed = {path = '../../pallets/price-feed', default-features = false } 36 | pallet-remote-asset-manager = { path = '../../pallets/remote-asset-manager', default-features = false } 37 | 38 | 39 | [features] 40 | default = ['std'] 41 | std = [ 42 | 'codec/std', 43 | "frame-support/std", 44 | 'frame-system/std', 45 | 'sp-std/std', 46 | 'scale-info/std', 47 | 48 | "xcm/std", 49 | "xcm-calls/std", 50 | "cumulus-pallet-xcm/std", 51 | 52 | "orml-traits/std", 53 | 54 | 'pallet-asset-index/std', 55 | 'pallet-committee/std', 56 | 'pallet-local-treasury/std', 57 | 'pallet-price-feed/std', 58 | 'pallet-remote-asset-manager/std', 59 | 'pallet-saft-registry/std', 60 | 'pallet-chainlink-feed/std', 61 | "primitives/std", 62 | ] 63 | -------------------------------------------------------------------------------- /runtime/common/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | //! PINT runtime common 4 | 5 | #![cfg_attr(not(feature = "std"), no_std)] 6 | pub mod constants; 7 | pub mod payment; 8 | pub mod traits; 9 | pub mod types; 10 | pub mod weights; 11 | -------------------------------------------------------------------------------- /runtime/common/src/payment.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ChainSafe Systems 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | //! Multiasset related fungibles adapter to allow payments in multiple assets 5 | 6 | use frame_support::{sp_runtime::DispatchError, traits::tokens::BalanceConversion}; 7 | use primitives::{traits::NavProvider, AssetId, Balance}; 8 | use sp_std::marker::PhantomData; 9 | 10 | /// Converts a balance value into an asset balance based on the current index token NAV. 11 | pub struct BalanceToAssetBalance