-
Notifications
You must be signed in to change notification settings - Fork 536
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added multisig, account abstraction, block abstraction
- Loading branch information
1 parent
2e467f8
commit 76e76d1
Showing
25 changed files
with
1,522 additions
and
596 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { SDK, Keyring, Account, WaitFor } from "./../../src/index" | ||
|
||
const main = async () => { | ||
const providerEndpoint = "ws://127.0.0.1:9944" | ||
const sdk = await SDK.New(providerEndpoint) | ||
const alice = new Keyring({ type: "sr25519" }).addFromUri("//Alice") | ||
|
||
/* | ||
Sometimes the existing sdk functions can be too low level and cumbersome to use. | ||
The Account class tries to remedy that by providing a similar interface but | ||
with less parameters. | ||
Account related data like balance, nonce and associated app keys can all be accessed | ||
by calling `getBalance`, `getNonceState`, and `getAppKeys` respectively. | ||
*/ | ||
const account = new Account(sdk, alice) | ||
console.log((await account.getBalance()).free.toString()) | ||
console.log(await account.getNonceNode()) | ||
console.log(await account.getNonceState()) | ||
console.log(await account.getAppKeys()) | ||
|
||
/* | ||
Three most common transactions are as well part of the Account interface. | ||
`balanceTransfer` (`balanceTransferNoWait`) | ||
`createApplicationKey` (`createApplicationKeyNoWait`) | ||
`submitData` (`submitDataNoWait`) | ||
*/ | ||
const _r1 = await account.balanceTransfer("5HGjWAeFDfFCWPsjFQdVV2Msvz2XtMktvgocEZcCj68kUMaw", account.oneAvail()) | ||
const r2 = await account.createApplicationKey("Alice Key") | ||
if (r2.isErr) { | ||
process.exit(1) | ||
} | ||
|
||
/* | ||
Setting app id, nonce, and the waitfor method can be easily done by calling | ||
`setAppId`, `setNonce`, and `setWaitFor` respectively. | ||
These values are sticky which means they will persist until you change them again. | ||
*/ | ||
account.setAppId(parseInt(r2.event.id)) | ||
account.setNonce(await account.getNonceNode()) | ||
account.setWaitFor(WaitFor.BlockInclusion) | ||
const _r3 = await account.submitData("My Data") | ||
|
||
/* | ||
To make sure that we don't use the same app id and the same nonce for our next | ||
call we reset them to null (default value) | ||
*/ | ||
account.setAppId(null) | ||
account.setNonce(null) | ||
const _r4 = await account.submitDataNoWait("My Data") | ||
|
||
process.exit() | ||
} | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import { SDK, Block, sdkBlock, Keyring, Account } from "./../../src/index" | ||
|
||
const main = async () => { | ||
const providerEndpoint = "ws://127.0.0.1:9944" | ||
const sdk = await SDK.New(providerEndpoint) | ||
const account = new Account(sdk, new Keyring({ type: "sr25519" }).addFromUri("//Alice")) | ||
|
||
// Submitting data that we will query later | ||
const tx = await account.submitData("aabbcc") | ||
if (tx.isErr) { | ||
process.exit(0) | ||
} | ||
const { blockHash, txHash, txIndex } = tx | ||
console.log("Reference hex value: " + tx.txData.data) | ||
|
||
/* | ||
Data Submissions from a block can be fetched in two ways: | ||
- Using the Block object | ||
- Using helper functions | ||
*/ | ||
|
||
/* | ||
The block abstraction object has helper functions to get data from | ||
submit data transactions. | ||
*/ | ||
const block = await Block.New(sdk.api, blockHash) | ||
const r1 = block.getSubmitDataAll() | ||
console.log(r1) | ||
const r2 = block.getSubmitDataHash(txHash) | ||
if (r2.isOk()) { | ||
console.log(r2.value) | ||
} | ||
const r3 = block.getSubmitDataIndex(txIndex) | ||
if (r3.isOk()) { | ||
console.log(r3.value) | ||
} | ||
|
||
/// The Signed block can be accessed if necessary. | ||
const _signedBlock = block.signedBlock | ||
|
||
/* | ||
The same interface can be found as free functions inside | ||
sdkBlock namespace. | ||
Block can as well be instated if `signedBlock` is available. | ||
const _block = new Block(signedBlock) | ||
*/ | ||
const signedBlock = await sdk.api.rpc.chain.getBlock(blockHash) | ||
const r4 = sdkBlock.getSubmitDataAll(signedBlock) | ||
console.log(r4) | ||
const r5 = sdkBlock.getSubmitDataHash(signedBlock, txHash) | ||
if (r5.isOk()) { | ||
console.log(r5.value) | ||
} | ||
const r6 = sdkBlock.getSubmitDataIndex(signedBlock, txIndex) | ||
if (r6.isErr()) { | ||
process.exit(1) | ||
} | ||
const dataSubmission = r6.value | ||
|
||
/* | ||
DataSubmission structure: | ||
{ | ||
"txHash": "0x2965fa2a2df6f818f0725be2b92b0dd399f1cf1e1620e1477fcc2b3e9ba9f491", | ||
"txIndex": 1, | ||
"hexData": "616162626363" | ||
"txSigner": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", | ||
} | ||
*/ | ||
console.log("Tx Hash: " + dataSubmission.txHash.toString()) | ||
console.log("Tx Index: " + dataSubmission.txIndex) | ||
console.log("Hex data: " + dataSubmission.hexData) | ||
console.log("Tx Signer: " + dataSubmission.txSigner) | ||
|
||
/* | ||
There is a helper function to get the Ascii version of the hex data | ||
*/ | ||
console.log("Ascii data: " + dataSubmission.toAscii()) | ||
|
||
process.exit() | ||
} | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
import { SDK, WaitFor, Keyring, BN, KeyringPair, Weight, TxResultDetails, MultisigTimepoint } from "./../../src/index" | ||
|
||
const main = async () => { | ||
const providerEndpoint = "ws://127.0.0.1:9944" | ||
const sdk = await SDK.New(providerEndpoint) | ||
|
||
// Multisig Signatures | ||
const alice = new Keyring({ type: "sr25519" }).addFromUri("//Alice") | ||
const bob = new Keyring({ type: "sr25519" }).addFromUri("//Bob") | ||
const charlie = new Keyring({ type: "sr25519" }).addFromUri("//Charlie") | ||
|
||
// Create Multisig Account | ||
const threshold = 3 | ||
const multisigAddress = sdk.util.generateMultisig([alice.address, bob.address, charlie.address], threshold) | ||
await fundMultisigAccount(sdk, alice, multisigAddress) | ||
|
||
// Define what action will be taken by the multisig account | ||
const amount = SDK.oneAvail() | ||
const call = sdk.api.tx.balances.transferKeepAlive(multisigAddress, amount) | ||
// Data needed for multisig approval and execution | ||
const callHash = call.method.hash.toString() | ||
const callData = call.unwrap().toHex() | ||
const maxWeight = (await call.paymentInfo(alice.address)).weight | ||
|
||
/* | ||
The first signature creates and approves the multisig transaction. All the next signatures (besides the last one) should | ||
use the `nextApproval` function to approve the tx. The last signature should use the `lastApproval` function to approve | ||
and execute the multisig tx. | ||
In practice it means the following: | ||
- If the threshold is 2 do the following: | ||
- firstApproval | ||
- lastApproval | ||
- If the threshold is 4 do the following: | ||
- firstApproval | ||
- nextApproval | ||
- nextApproval | ||
- lastApproval | ||
*/ | ||
|
||
// Create New Multisig | ||
const call1signatures = sdk.util.sortMultisigAddresses([bob.address, charlie.address]) | ||
const firstResult = await firstApproval(sdk, alice, threshold, call1signatures, callHash, maxWeight) | ||
|
||
// Approve existing Multisig | ||
const timepoint: MultisigTimepoint = { height: firstResult.blockNumber, index: firstResult.txIndex } | ||
const call2signatures = sdk.util.sortMultisigAddresses([alice.address, charlie.address]) | ||
const _secondResult = await nextApproval(sdk, bob, threshold, call2signatures, timepoint, callHash, maxWeight) | ||
|
||
// Execute Multisig | ||
const call3signatures = sdk.util.sortMultisigAddresses([alice.address, bob.address]) | ||
const _thirdResult = await lastApproval(sdk, charlie, threshold, call3signatures, timepoint, callData, maxWeight) | ||
|
||
process.exit() | ||
} | ||
|
||
async function fundMultisigAccount(sdk: SDK, alice: KeyringPair, multisigAddress: string): Promise<string> { | ||
console.log("Funding multisig account...") | ||
const amount = new BN(10).pow(new BN(18)).mul(new BN(100)) // 100 Avail | ||
const result = await sdk.tx.balances.transferKeepAlive(multisigAddress, amount, WaitFor.BlockInclusion, alice) | ||
if (result.isErr) { | ||
console.log(result.reason) | ||
process.exit(1) | ||
} | ||
|
||
return multisigAddress | ||
} | ||
|
||
async function firstApproval( | ||
sdk: SDK, | ||
account: KeyringPair, | ||
threshold: number, | ||
otherSignatures: string[], | ||
callHash: string, | ||
maxWeight: Weight, | ||
): Promise<TxResultDetails> { | ||
console.log("Alice is creating a Multisig Transaction...") | ||
|
||
const maybeTxResult = await sdk.tx.multisig.approveAsMulti( | ||
threshold, | ||
otherSignatures, | ||
null, | ||
callHash, | ||
maxWeight, | ||
WaitFor.BlockInclusion, | ||
account, | ||
) | ||
if (maybeTxResult.isErr()) { | ||
console.log(maybeTxResult.error) | ||
process.exit(1) | ||
} | ||
|
||
return maybeTxResult.value.details | ||
} | ||
|
||
async function nextApproval( | ||
sdk: SDK, | ||
account: KeyringPair, | ||
threshold: number, | ||
otherSignatures: string[], | ||
timepoint: MultisigTimepoint, | ||
callHash: string, | ||
maxWeight: Weight, | ||
): Promise<TxResultDetails> { | ||
console.log("Bob is approving the existing Multisig Transaction...") | ||
|
||
const maybeTxResult = await sdk.tx.multisig.approveAsMulti( | ||
threshold, | ||
otherSignatures, | ||
timepoint, | ||
callHash, | ||
maxWeight, | ||
WaitFor.BlockInclusion, | ||
account, | ||
) | ||
if (maybeTxResult.isErr()) { | ||
console.log(maybeTxResult.error) | ||
process.exit(1) | ||
} | ||
|
||
return maybeTxResult.value.details | ||
} | ||
|
||
async function lastApproval( | ||
sdk: SDK, | ||
account: KeyringPair, | ||
threshold: number, | ||
otherSignatures: string[], | ||
timepoint: MultisigTimepoint, | ||
callData: string, | ||
maxWeight: Weight, | ||
): Promise<TxResultDetails> { | ||
console.log("Charlie is approving and executing the existing Multisig Transaction...") | ||
|
||
const maybeTxResult = await sdk.tx.multisig.asMulti( | ||
threshold, | ||
otherSignatures, | ||
timepoint, | ||
callData, | ||
maxWeight, | ||
WaitFor.BlockInclusion, | ||
account, | ||
) | ||
if (maybeTxResult.isErr()) { | ||
console.log(maybeTxResult.error) | ||
process.exit(1) | ||
} | ||
|
||
return maybeTxResult.value.details | ||
} | ||
|
||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { SDK, WaitFor, Keyring, TransactionOptions } from "./../../src/index" | ||
|
||
const main = async () => { | ||
const providerEndpoint = "ws://127.0.0.1:9944" | ||
const sdk = await SDK.New(providerEndpoint) | ||
|
||
const alice = new Keyring({ type: "sr25519" }).addFromUri("//Alice") | ||
|
||
/* | ||
The SDK provides two easy to use but slightly different nonce functions. | ||
- `getNonceState` - Returns nonce from the state of network. This only changes | ||
on a per block basis | ||
- `getNonceNode` - Returns nonce from the node's storage. This gets the nonce | ||
from the state and it updates it if there are existing | ||
transactions already in the mem pool. | ||
If in doubt, use `getNonceNode`. | ||
*/ | ||
let nonceState1 = await sdk.util.getNonceState(alice.address) | ||
let nonceNode1 = await sdk.util.getNonceNode(alice.address) | ||
console.log(`Nonce State: ${nonceState1}, Nonce Node: ${nonceNode1}`) | ||
let _result = await sdk.tx.dataAvailability.submitDataNoWait("Data", alice) | ||
let nonceState2 = await sdk.util.getNonceState(alice.address) | ||
let nonceNode2 = await sdk.util.getNonceNode(alice.address) | ||
console.log(`Nonce State: ${nonceState2}, Nonce Node: ${nonceNode2}`) | ||
|
||
process.exit() | ||
} | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { SDK, WaitFor, Keyring, TransactionOptions } from "./../../src/index" | ||
|
||
const main = async () => { | ||
const providerEndpoint = "ws://127.0.0.1:9944" | ||
const sdk = await SDK.New(providerEndpoint) | ||
const alice = new Keyring({ type: "sr25519" }).addFromUri("//Alice") | ||
|
||
/* | ||
Setting up application id and/or nonce for any transaction is as simple as just defining them | ||
and passing them as the last argument to any sdk transaction call. | ||
TransactionOptions interface has the following fields: | ||
- app_id?: number | ||
- nonce?: number | ||
- era?: number | ||
- blockHash?: H256 | ||
*/ | ||
let nonce = await sdk.util.getNonceNode(alice.address) | ||
let options: TransactionOptions = { app_id: 1, nonce } | ||
let result = await sdk.tx.dataAvailability.submitData("Data", WaitFor.BlockInclusion, alice, options) | ||
|
||
console.log(JSON.stringify(result, null, 2)) | ||
|
||
process.exit() | ||
} | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { SDK, Keyring } from "../../src/index" | ||
|
||
const main = async () => { | ||
const providerEndpoint = "ws://127.0.0.1:9944" | ||
const sdk = await SDK.New(providerEndpoint) | ||
|
||
// Input | ||
const account = new Keyring({ type: "sr25519" }).addFromUri("//Alice") | ||
const dest = "5HGjWAeFDfFCWPsjFQdVV2Msvz2XtMktvgocEZcCj68kUMaw" // Eve | ||
const keepAlive = true | ||
|
||
const txHash = await sdk.tx.balances.transferAllNoWait(dest, keepAlive, account) | ||
|
||
console.log(JSON.stringify(txHash, null, 2)) | ||
process.exit() | ||
} | ||
main() |
17 changes: 17 additions & 0 deletions
17
avail-js/docs/extrinsics/balances_tranfer_allow_death_no_wait.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { SDK, Keyring } from "../../src/index" | ||
|
||
const main = async () => { | ||
const providerEndpoint = "ws://127.0.0.1:9944" | ||
const sdk = await SDK.New(providerEndpoint) | ||
|
||
// Input | ||
const account = new Keyring({ type: "sr25519" }).addFromUri("//Alice") | ||
const dest = "5HGjWAeFDfFCWPsjFQdVV2Msvz2XtMktvgocEZcCj68kUMaw" // Eve | ||
const amount = SDK.oneAvail() | ||
|
||
const txHash = await sdk.tx.balances.transferAllowDeathNoWait(dest, amount, account) | ||
|
||
console.log(JSON.stringify(txHash, null, 2)) | ||
process.exit() | ||
} | ||
main() |
Oops, something went wrong.