如何使用 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
  }
})