如何使用 polkadot.js 解码基板上的事件帮助?
How to decode events help on substrate using polkadot.js?
我在 rust
中有一个包含包管理器 cargo
的基础智能合约。在那个智能合约中,我有一些事件是我在函数调用时发出的。为了列出这些事件,我在 java script
中提供了一项服务,但我不确定如何在使用该智能合约的区块链中发生交易时解码由合约触发的事件。我有一个 link 从那里我可以解码 https://github.com/polkadot-js/api/blob/f701c398c349159d5afd7344ea38c1d52e4aab56/packages/api-contract/src/Abi/index.ts#L111
但我已经实现了但无法解码事件。我在这里粘贴我的合同和服务,如果您有什么建议或建议,请告诉我。
合同
#![cfg_attr(not(feature = "std"), no_std)]
use ink_lang as ink;
#[ink::contract]
mod test {
/// Defines the storage of your contract.
/// Add new fields to the below struct in order
/// to add new static storage fields to your contract.
#[ink(storage)]
pub struct Test {
/// Stores a single `bool` value on the storage.
value: bool,
}
/// Event emitted when a token transfer occurs.
#[ink(event)]
pub struct Transfer {
#[ink(topic)]
from: Option<AccountId>,
#[ink(topic)]
to: Option<AccountId>,
value: Balance,
}
impl Test {
/// Constructor that initializes the `bool` value to the given `init_value`.
#[ink(constructor)]
pub fn new(init_value: bool) -> Self {
Self { value: init_value }
}
/// Constructor that initializes the `bool` value to `false`.
///
/// Constructors can delegate to other constructors.
#[ink(constructor)]
pub fn default() -> Self {
Self::new(Default::default())
}
/// A message that can be called on instantiated contracts.
/// This one flips the value of the stored `bool` from `true`
/// to `false` and vice versa.
#[ink(message)]
pub fn flip(&mut self) {
self.value = !self.value;
Self::env().emit_event(Transfer {
from: None,
to: None,
value: 10000,
});
}
/// Simply returns the current value of our `bool`.
#[ink(message)]
pub fn get(&self) {
Self::env().emit_event(Transfer {
from: None,
to: None,
value: 10000,
});
}
}
/// Unit tests in Rust are normally defined within such a `#[cfg(test)]`
/// module and test functions are marked with a `#[test]` attribute.
/// The below code is technically just normal Rust code.
#[cfg(test)]
mod tests {
/// Imports all the definitions from the outer scope so we can use them here.
use super::*;
/// Imports `ink_lang` so we can use `#[ink::test]`.
use ink_lang as ink;
/// We test if the default constructor does its job.
#[ink::test]
fn default_works() {
let test = Test::default();
assert_eq!(test.get(), false);
}
/// We test a simple use case of our contract.
#[ink::test]
fn it_works() {
let mut test = Test::new(false);
assert_eq!(test.get(), false);
test.flip();
assert_eq!(test.get(), true);
}
}
}
Service.js
const { ApiPromise, WsProvider } = require('@polkadot/api')
const { ContractPromise, Abi } = require('@polkadot/api-contract')
const {
assert,
assertReturn,
compactAddLength,
compactStripLength,
isNumber,
isObject,
isString,
logger,
stringCamelCase,
stringify,
u8aConcat,
u8aToHex,
} = require('@polkadot/util')
// Import the test keyring (already has dev keys for Alice, Bob, Charlie, Eve & Ferdie)
const { Keyring } = require('@polkadot/keyring')
const bridgePerr = require('./flipper/examples/test/target/ink/metadata.json')
const Contract_Address_Peer = '5FfwrjcXmWsCZCtzRJPwtPBS3AEnPKJy9c2yEi17mFa5hhS3'
// Acc :- 30 may 11:33
const Peer_Private_key =
'0xb0969cc635d807e6d6bfcb05cad88758c64df2da338050ce2103815653d05606'
const PeerProvider = new WsProvider('ws://127.0.0.1:9944')
// const self = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
const to = '5Gue2tLHMZrfaeX6gDNs8EAPm64mpAnHsWWw5TWhGsb3Fkxo'
const AMOUNT = 1000000000000
async function main() {
const api = await ApiPromise.create({ PeerProvider })
//ed25519 edwards
const keyring = new Keyring({ type: 'ed25519' })
const PeerBridge = new ContractPromise(api, bridgePerr, Contract_Address_Peer)
// the address we are going to query
// Find the actual keypair in the keyring
// const alicePair = keyring.getPair(target)
const userPair = keyring.addFromUri(Peer_Private_key)
console.log('Sending', AMOUNT, 'from', userPair.address, 'to', to)
PeerBridge.tx
.get({
value: 0,
gasLimit: -1,
})
.signAndSend(userPair, ({ events = [], status }) => {
console.log('Transaction status:', status.type)
if (status.isInBlock) {
console.log('Included at block hash', status.asInBlock.toHex())
console.log('Events:')
events.forEach(({ event: { data, method, section }, phase }) => {
console.log(
'\t',
phase.toString(),
`: ${section}.${method}`,
data.toString(),
)
})
} else if (status.isFinalized) {
console.log('Finalized block hash', status.asFinalized.toHex())
process.exit(0)
}
})
}
main()
日志
Transaction status: Ready
Transaction status: InBlock
Included at block hash 0x20da51303e5e1518e90844be6823f85e51666cc27ee652960d25b65902a97e59
Events:
{"applyExtrinsic":1} : balances.Withdraw ["5Cht6EkuACEXLrF8XBywqZPDCL9AEgSQXS4MB6dwgZAeqCVc",2828033563974]
{"applyExtrinsic":1} : contracts.ContractEmitted ["5DskQxeMsqqueJzauUsbh8xYiiDKR4x7e5Kz29pkCJ1EKmwZ","0x00000010270000000000000000000000000000"]
{"applyExtrinsic":1} : balances.Deposit ["5Cht6EkuACEXLrF8XBywqZPDCL9AEgSQXS4MB6dwgZAeqCVc",1268853627292]
{"applyExtrinsic":1} : balances.Deposit ["5EYCAe5ijiYfyeZ2JJCGq56LmPyNRAKzpG4QkoQkkQNB5e6Z",1247343949345]
{"applyExtrinsic":1} : treasury.Deposit [1247343949345]
{"applyExtrinsic":1} : balances.Deposit ["5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY",311835987337]
{"applyExtrinsic":1} : system.ExtrinsicSuccess [{"weight":9072880260,"class":"Normal","paysFee":"Yes"}]
Transaction status: Finalized
Finalized
block hash 0x20da51303e5e1518e90844be6823f85e51666cc27ee652960d25b65902a97e59
任何人请在这方面提出建议或帮助我。
您想在 API 上解码来自 ContractEmitted. So you are half-way there in known that you can pass the Bytes
to the decodeEvent 的数据。
在大多数情况下 pseudo-code,您需要调整事件检查循环 -
const { Abi } = require('@polkadot/api-contract')
events.forEach(({ event, phase }) => {
if (api.events.contracts.ContractEmitted.is(event)) {
// we are dealing with a contract event
const [account_id, contract_evt] = event.data
// decode
const decoded = new Abi(bridgePerr).decodeEvent(contract_evt)
console.log(decoded)
// display results, etc.
...
} else {
// normal/other event logic
}
})
我在 rust
中有一个包含包管理器 cargo
的基础智能合约。在那个智能合约中,我有一些事件是我在函数调用时发出的。为了列出这些事件,我在 java script
中提供了一项服务,但我不确定如何在使用该智能合约的区块链中发生交易时解码由合约触发的事件。我有一个 link 从那里我可以解码 https://github.com/polkadot-js/api/blob/f701c398c349159d5afd7344ea38c1d52e4aab56/packages/api-contract/src/Abi/index.ts#L111
但我已经实现了但无法解码事件。我在这里粘贴我的合同和服务,如果您有什么建议或建议,请告诉我。
合同
#![cfg_attr(not(feature = "std"), no_std)]
use ink_lang as ink;
#[ink::contract]
mod test {
/// Defines the storage of your contract.
/// Add new fields to the below struct in order
/// to add new static storage fields to your contract.
#[ink(storage)]
pub struct Test {
/// Stores a single `bool` value on the storage.
value: bool,
}
/// Event emitted when a token transfer occurs.
#[ink(event)]
pub struct Transfer {
#[ink(topic)]
from: Option<AccountId>,
#[ink(topic)]
to: Option<AccountId>,
value: Balance,
}
impl Test {
/// Constructor that initializes the `bool` value to the given `init_value`.
#[ink(constructor)]
pub fn new(init_value: bool) -> Self {
Self { value: init_value }
}
/// Constructor that initializes the `bool` value to `false`.
///
/// Constructors can delegate to other constructors.
#[ink(constructor)]
pub fn default() -> Self {
Self::new(Default::default())
}
/// A message that can be called on instantiated contracts.
/// This one flips the value of the stored `bool` from `true`
/// to `false` and vice versa.
#[ink(message)]
pub fn flip(&mut self) {
self.value = !self.value;
Self::env().emit_event(Transfer {
from: None,
to: None,
value: 10000,
});
}
/// Simply returns the current value of our `bool`.
#[ink(message)]
pub fn get(&self) {
Self::env().emit_event(Transfer {
from: None,
to: None,
value: 10000,
});
}
}
/// Unit tests in Rust are normally defined within such a `#[cfg(test)]`
/// module and test functions are marked with a `#[test]` attribute.
/// The below code is technically just normal Rust code.
#[cfg(test)]
mod tests {
/// Imports all the definitions from the outer scope so we can use them here.
use super::*;
/// Imports `ink_lang` so we can use `#[ink::test]`.
use ink_lang as ink;
/// We test if the default constructor does its job.
#[ink::test]
fn default_works() {
let test = Test::default();
assert_eq!(test.get(), false);
}
/// We test a simple use case of our contract.
#[ink::test]
fn it_works() {
let mut test = Test::new(false);
assert_eq!(test.get(), false);
test.flip();
assert_eq!(test.get(), true);
}
}
}
Service.js
const { ApiPromise, WsProvider } = require('@polkadot/api')
const { ContractPromise, Abi } = require('@polkadot/api-contract')
const {
assert,
assertReturn,
compactAddLength,
compactStripLength,
isNumber,
isObject,
isString,
logger,
stringCamelCase,
stringify,
u8aConcat,
u8aToHex,
} = require('@polkadot/util')
// Import the test keyring (already has dev keys for Alice, Bob, Charlie, Eve & Ferdie)
const { Keyring } = require('@polkadot/keyring')
const bridgePerr = require('./flipper/examples/test/target/ink/metadata.json')
const Contract_Address_Peer = '5FfwrjcXmWsCZCtzRJPwtPBS3AEnPKJy9c2yEi17mFa5hhS3'
// Acc :- 30 may 11:33
const Peer_Private_key =
'0xb0969cc635d807e6d6bfcb05cad88758c64df2da338050ce2103815653d05606'
const PeerProvider = new WsProvider('ws://127.0.0.1:9944')
// const self = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
const to = '5Gue2tLHMZrfaeX6gDNs8EAPm64mpAnHsWWw5TWhGsb3Fkxo'
const AMOUNT = 1000000000000
async function main() {
const api = await ApiPromise.create({ PeerProvider })
//ed25519 edwards
const keyring = new Keyring({ type: 'ed25519' })
const PeerBridge = new ContractPromise(api, bridgePerr, Contract_Address_Peer)
// the address we are going to query
// Find the actual keypair in the keyring
// const alicePair = keyring.getPair(target)
const userPair = keyring.addFromUri(Peer_Private_key)
console.log('Sending', AMOUNT, 'from', userPair.address, 'to', to)
PeerBridge.tx
.get({
value: 0,
gasLimit: -1,
})
.signAndSend(userPair, ({ events = [], status }) => {
console.log('Transaction status:', status.type)
if (status.isInBlock) {
console.log('Included at block hash', status.asInBlock.toHex())
console.log('Events:')
events.forEach(({ event: { data, method, section }, phase }) => {
console.log(
'\t',
phase.toString(),
`: ${section}.${method}`,
data.toString(),
)
})
} else if (status.isFinalized) {
console.log('Finalized block hash', status.asFinalized.toHex())
process.exit(0)
}
})
}
main()
日志
Transaction status: Ready
Transaction status: InBlock
Included at block hash 0x20da51303e5e1518e90844be6823f85e51666cc27ee652960d25b65902a97e59
Events:
{"applyExtrinsic":1} : balances.Withdraw ["5Cht6EkuACEXLrF8XBywqZPDCL9AEgSQXS4MB6dwgZAeqCVc",2828033563974]
{"applyExtrinsic":1} : contracts.ContractEmitted ["5DskQxeMsqqueJzauUsbh8xYiiDKR4x7e5Kz29pkCJ1EKmwZ","0x00000010270000000000000000000000000000"]
{"applyExtrinsic":1} : balances.Deposit ["5Cht6EkuACEXLrF8XBywqZPDCL9AEgSQXS4MB6dwgZAeqCVc",1268853627292]
{"applyExtrinsic":1} : balances.Deposit ["5EYCAe5ijiYfyeZ2JJCGq56LmPyNRAKzpG4QkoQkkQNB5e6Z",1247343949345]
{"applyExtrinsic":1} : treasury.Deposit [1247343949345]
{"applyExtrinsic":1} : balances.Deposit ["5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY",311835987337]
{"applyExtrinsic":1} : system.ExtrinsicSuccess [{"weight":9072880260,"class":"Normal","paysFee":"Yes"}]
Transaction status: Finalized
Finalized
block hash 0x20da51303e5e1518e90844be6823f85e51666cc27ee652960d25b65902a97e59
任何人请在这方面提出建议或帮助我。
您想在 API 上解码来自 ContractEmitted. So you are half-way there in known that you can pass the Bytes
to the decodeEvent 的数据。
在大多数情况下 pseudo-code,您需要调整事件检查循环 -
const { Abi } = require('@polkadot/api-contract')
events.forEach(({ event, phase }) => {
if (api.events.contracts.ContractEmitted.is(event)) {
// we are dealing with a contract event
const [account_id, contract_evt] = event.data
// decode
const decoded = new Abi(bridgePerr).decodeEvent(contract_evt)
console.log(decoded)
// display results, etc.
...
} else {
// normal/other event logic
}
})