├── .gitattributes ├── screenshot.png ├── README.md ├── dependencies.js ├── utils └── index.html ├── custom.css ├── balance-transfer ├── balance-transfer.js └── index.html ├── LICENSE ├── metadata ├── metadata.js └── index.html ├── index.html └── runtime-storage ├── index.html └── runtime-storage.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shawntabrizi/substrate-rpc-examples/HEAD/screenshot.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # substrate-rpc-examples 2 | A simple set of examples to help you play with your Substrate RPC endpoint. 3 | -------------------------------------------------------------------------------- /dependencies.js: -------------------------------------------------------------------------------- 1 | // browserify dependencies.js > bundle.js 2 | 3 | let util = require('@polkadot/util'); 4 | let util_crypto = require('@polkadot/util-crypto'); 5 | let keyring = require('@polkadot/keyring'); 6 | 7 | window.util = util; 8 | window.util_crypto = util_crypto; 9 | window.keyring = keyring; 10 | -------------------------------------------------------------------------------- /utils/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

Moved utils to: https://www.shawntabrizi.com/substrate-js-utilities/

8 | 9 | -------------------------------------------------------------------------------- /custom.css: -------------------------------------------------------------------------------- 1 | /* Custom page CSS 2 | -------------------------------------------------- */ 3 | /* Not required for template or sticky footer method. */ 4 | 5 | .container { 6 | width: auto; 7 | padding: 15px; 8 | } 9 | 10 | .footer { 11 | background-color: #f5f5f5; 12 | } 13 | 14 | pre { 15 | white-space: pre-wrap; /* Since CSS 2.1 */ 16 | white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ 17 | white-space: -pre-wrap; /* Opera 4-6 */ 18 | white-space: -o-pre-wrap; /* Opera 7 */ 19 | word-wrap: break-word; /* Internet Explorer 5.5+ */ 20 | } 21 | 22 | h4 { 23 | padding-top: 20px; 24 | } -------------------------------------------------------------------------------- /balance-transfer/balance-transfer.js: -------------------------------------------------------------------------------- 1 | const BOB = "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"; 2 | 3 | function AliceKey() { 4 | const k = new keyring.Keyring({ type: "sr25519" }); 5 | 6 | } 7 | 8 | async function transfer() { 9 | // Instantiate the API 10 | const api = await ApiPromise.create(); 11 | 12 | // Constuct the keying after the API (crypto has an async init) 13 | const keyring = new keyring.Keyring({ type: "sr25519" }); 14 | 15 | // Add alice to our keyring with a hard-deived path (empty phrase, so uses dev) 16 | const alice = keyring.addFromUri("//Alice"); 17 | 18 | // Create a extrinsic, transferring 12345 units to Bob 19 | const transfer = api.tx.balances.transfer(BOB, 12345); 20 | 21 | // Sign and send the transaction using our account 22 | const hash = await transfer.signAndSend(alice); 23 | 24 | console.log("Transfer sent with hash", hash.toHex()); 25 | } 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Shawn Tabrizi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /balance-transfer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Substrate RPC Examples 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 |

Balance Transfer

22 |

To do.

23 |

24 | 		
25 |
26 | 27 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /metadata/metadata.js: -------------------------------------------------------------------------------- 1 | let output_raw = document.getElementById("metadata-output-raw"); 2 | let output_decoded = document.getElementById("metadata-output-decoded"); 3 | 4 | function get_metadata_request(endpoint) { 5 | let request = new Request(endpoint, { 6 | method: "POST", 7 | body: JSON.stringify({ 8 | id: 1, 9 | jsonrpc: "2.0", 10 | method: "state_getMetadata" 11 | }), 12 | headers: { "Content-Type": "application/json" } 13 | }); 14 | return request; 15 | } 16 | 17 | function make_request(endpoint = "http://localhost:9933/") { 18 | let request = get_metadata_request(endpoint); 19 | fetch(request) 20 | .then(response => { 21 | if (response.status === 200) { 22 | return response.json(); 23 | } else { 24 | throw new Error("Something went wrong on api server!"); 25 | } 26 | }) 27 | .then(response => { 28 | print_metadata(response.result); 29 | console.debug(response); 30 | }) 31 | .catch(error => { 32 | if (endpoint == "http://localhost:9933/") { 33 | // Fallback to public endpoint 34 | make_request("https://rpc.polkadot.io/"); 35 | } else { 36 | console.error(error); 37 | } 38 | }); 39 | } 40 | 41 | function decode_metadata(metadata) { 42 | return new TextDecoder().decode(util.hexToU8a(metadata)); 43 | } 44 | 45 | function print_metadata(metadata) { 46 | output_raw.innerText += metadata; 47 | let decoded = decode_metadata(metadata); 48 | output_decoded.innerText += decoded; 49 | } 50 | 51 | make_request(); 52 | 53 | document.getElementById( 54 | "metadata-request" 55 | ).innerText = get_metadata_request.toString(); 56 | 57 | document.getElementById( 58 | "metadata-decoder" 59 | ).innerText = decode_metadata.toString(); 60 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Substrate RPC Examples 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 |

Substrate RPC Examples

22 |

Click any of the links below to see an example of calling the Substrate RPC endpoint.

23 | 34 |
35 | 40 |
41 |
42 | 43 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /metadata/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Substrate RPC Examples 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 |

Metadata

22 |

This is an example of calling the state_getMetadata rpc endpoint.

23 |
24 |
25 |

RPC Request

26 |

27 | 					

Raw Metadata

28 |

29 | 				
30 |
31 |

Naive Text Decoding

32 |

33 | 					

Decoded Metadata

34 |

35 | 				
36 |
37 |
38 |
39 | 40 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /runtime-storage/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Substrate RPC Examples 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 |

Runtime Storage

22 |

This is an example of calling the state_getStorage rpc endpoint.

23 |
24 |
25 | Parameters 26 |
27 | 29 | 31 | 33 |
34 |

35 | 		
36 |
37 | 38 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /runtime-storage/runtime-storage.js: -------------------------------------------------------------------------------- 1 | /* Start Setup Stuff */ 2 | let runtime_storage = { 3 | module_name: document.getElementById("runtime-storage-module-name"), 4 | function_name: document.getElementById("runtime-storage-function-name"), 5 | key_1: document.getElementById("runtime-storage-key-1"), 6 | output: document.getElementById("runtime-storage-output") 7 | }; 8 | 9 | runtime_storage.module_name.addEventListener("input", print_runtime_storage); 10 | runtime_storage.function_name.addEventListener("input", print_runtime_storage); 11 | runtime_storage.key_1.addEventListener("input", print_runtime_storage); 12 | 13 | print_runtime_storage(); 14 | /* End Setup Stuff */ 15 | 16 | async function print_runtime_storage() { 17 | // Clear output field 18 | runtime_storage.output.innerText = ""; 19 | runtime_storage.output.innerText += 20 | "// First we need to generate the storage key (`parameter`)" + "\n"; 21 | let parameter = get_runtime_storage_parameter( 22 | runtime_storage.module_name.value, 23 | runtime_storage.function_name.value, 24 | runtime_storage.key_1.value, 25 | ); 26 | 27 | runtime_storage.output.innerText += "Storage Key Parameter: " + parameter + "\n"; 28 | let new_request = get_storage_request(0, parameter); 29 | runtime_storage.output.innerText += 30 | "Request: " + (await new_request.text()) + "\n"; 31 | make_request(parameter); 32 | } 33 | 34 | function get_runtime_storage_parameter(module_name, function_name, key_1) { 35 | runtime_storage.output.innerText += 36 | "// We do this using the `module_name`, `function_name`, and `key` (optional)" + 37 | "\n"; 38 | if (key_1) { 39 | runtime_storage.output.innerText += 40 | "// A `key` is provided in this example, so this is how we generate the storage parameter:" + 41 | "\n"; 42 | runtime_storage.output.innerText += 43 | "\n" + get_runtime_storage_parameter_with_key.toString() + "\n\n"; 44 | return get_runtime_storage_parameter_with_key( 45 | module_name, 46 | function_name, 47 | key_1 48 | ); 49 | } else { 50 | runtime_storage.output.innerText += 51 | "// No `key` is provided in this example." + "\n"; 52 | runtime_storage.output.innerText += 53 | "\n" + get_runtime_storage_parameter_without_key.toString() + "\n\n"; 54 | return get_runtime_storage_parameter_without_key( 55 | module_name, 56 | function_name 57 | ); 58 | } 59 | } 60 | 61 | function get_runtime_storage_parameter_with_key( 62 | module_name, 63 | function_name, 64 | key 65 | ) { 66 | // We use xxhash 128 for strings the runtime developer can control 67 | let module_hash = util_crypto.xxhashAsU8a(module_name, 128); 68 | let function_hash = util_crypto.xxhashAsU8a(function_name, 128); 69 | 70 | // We use blake2 256 for strings the end user can control 71 | let key_hash = util_crypto.blake2AsU8a(keyToBytes(key)); 72 | 73 | // Special syntax to concatenate Uint8Array 74 | let final_key = new Uint8Array([ 75 | ...module_hash, 76 | ...function_hash, 77 | ...key_hash, 78 | ]); 79 | 80 | // Return a hex string 81 | return util.u8aToHex(final_key); 82 | } 83 | 84 | function get_runtime_storage_parameter_without_key(module_name, function_name) { 85 | // We use xxhash 128 for strings the runtime developer can control 86 | let module_hash = util_crypto.xxhashAsU8a(module_name, 128); 87 | let function_hash = util_crypto.xxhashAsU8a(function_name, 128); 88 | 89 | // Special syntax to concatenate Uint8Array 90 | let final_key = new Uint8Array([ 91 | ...module_hash, 92 | ...function_hash 93 | ]) 94 | 95 | // Return a hex string 96 | return util.u8aToHex(final_key); 97 | } 98 | 99 | function keyToBytes(key) { 100 | let key_bytes = keyring.decodeAddress(key) 101 | ? keyring.decodeAddress(key) 102 | : util.stringToU8a(key); 103 | return key_bytes; 104 | } 105 | 106 | function get_storage_request(endpoint, parameter) { 107 | let request = new Request(endpoint, { 108 | method: "POST", 109 | body: JSON.stringify({ 110 | id: 1, 111 | jsonrpc: "2.0", 112 | method: "state_getStorage", 113 | params: [parameter] 114 | }), 115 | headers: { "Content-Type": "application/json" } 116 | }); 117 | return request; 118 | } 119 | 120 | function make_request(parameter, endpoint = "http://localhost:9933/") { 121 | let request = get_storage_request(endpoint, parameter); 122 | fetch(request) 123 | .then(response => { 124 | if (response.status === 200) { 125 | return response.json(); 126 | } else { 127 | throw new Error("Something went wrong on api server!"); 128 | } 129 | }) 130 | .then(response => { 131 | runtime_storage.output.innerText += 132 | "Response: " + JSON.stringify(response) + "\n"; 133 | console.debug(response); 134 | }) 135 | .catch(error => { 136 | if (endpoint == "http://localhost:9933/") { 137 | // Fallback to public endpoint 138 | make_request( 139 | parameter, 140 | "https://dev-node.substrate.dev:9933/" 141 | ); 142 | } else { 143 | console.error(error); 144 | } 145 | }); 146 | } 147 | --------------------------------------------------------------------------------