Come emettere e catturare eventi in Phat Contract

pigro85
Phala Italia
Published in
3 min readJan 31, 2024

Gli eventi e i log sono importanti per gli sviluppatori di Web3 perché facilitano la comunicazione tra gli smart contract e le loro interfacce utente. Come altri smart contract, Phat Contract può emettere eventi per comunicare che qualcosa è accaduto. A differenza di altri smart contract, gli eventi di Phat Contract sono disponibili solo all’interno del cluster. È necessario utilizzare il nostro JS-SDK per catturare questi eventi e intraprendere azioni quando si verificano.

Ecco un esempio di implementazione ERC-20 da ink-examples che può essere distribuito su Phala Network, è possibile testarlo sulla PoC6 Testnet.

L’esempio completo di codice è disponibile qui: https://github.com/Leechael/phat-contract-events-example/

Come emettere eventi da un Phat Contract

Per prima cosa è necessario dichiarare una definizione di evento

#[ink(event)]
pub struct Transfer {
#[ink(topic)]
from: Option<AccountId>,
#[ink(topic)]
to: Option<AccountId>,
value: Balance,
}

Per definire un evento Ink! è necessario aggiungere la macro #[ink(event)] alla definizione struct. Inoltre, applicare il tag di attributo #[ink(topic)] a ciascun elemento dell’evento che si desidera contrassegnare come “da indicizzare”. Si noti che è possibile indicizzare un massimo di quattro attributi.

Emettere eventi in un Constructor

Si può usare Self::env().emit_event() per emettere eventi in una funzione constructor:

#[ink(constructor)]
pub fn new(initial_supply: Balance) -> Self {
let caller = Self::env().caller();
let mut balances = Mapping::default();
balances.insert(caller, &initial_supply);
    Self::env().emit_event(Transfer {
from: None,
to: Some(caller),
value: initial_supply,
});
Self {
total_supply: initial_supply,
balances,
allowances: Mapping::default(),
}
}

Emettere eventi in un messaggio

Si può usare self.env().emit_event() per emettere eventi in una funzione messaggio con il segno &mut:

self.env().emit_event(Transfer {
from: Some(*from),
to: Some(*to),
value,
});

💡Gli eventi possono essere emessi solo dalle transazioni. Non è possibile emettere un evento da un messaggio off-chain, il che significa che si DEVE usare il marchio &mut self.

Catturare gli eventi con JS-SDK

Una volta che abbiamo l’istanza di Phat Contract che emette eventi, possiamo catturare gli eventi in un’applicazione web3 con il nostro JS-SDK.

È necessario caricare prima l’ABI JSON:

const fs = require('fs')
const abi = fs.readFileSync('./target/ink/erc20.json', 'utf8')

Poiché gli eventi si verificano solo all’interno del cluster e non vengono trasmessi on-chain, è possibile utilizzare il logger per catturarli:

const ws = argv['--ws'] || process.env.WS || 'wss://poc6.phala.network/ws'
const logger = await getLogger({ transport: ws })
// Or you already use `getClient` before:
const client = await getClient({ transport: ws })
const

L’oggetto logger consente di accedere al flusso di log da un nodo PRuntime specificato. Ora è possibile chiamare logger.tail(1000) per recuperare le ultime 1000 voci di log. Per ulteriori informazioni sull’utilizzo si può consultare la documentazione del JS-SDK e l’esempio tail.js.

Attualmente, se si vuole catturare l’evento dopo l’invio della transazione è necessario un po’ più di codice di base:

const { blockNumber } = await client.phactory.getInfo({})
const result = await contract.send.transfer(
{ cert, address: cert.address, pair },
toAddress,
value
)
await result.waitFinalized()
const { records } = await logger.tail(10000, {
contract: contract.address.toHex(),
abi,
type: ['Event'] as LogTypeLiteral[],
})
const matched = records.filter(i => (i as SerMessageEventWithDecoded).blockNumber >= blockNumber)
console.assert(matched.length === 1, 'It should only one matched event.')
for (const record of matched) {
let rec = record as SerMessageEventWithDecoded
prettyPrint(rec)
}

La struct SerMessageEventWithDecoded rappresenta un evento che include dati decodificati ed ha la seguente struttura:

interface SerMessageEventWithDecoded {
type: 'Event'
sequence: number
blockNumber: number
contract: string
topics: string[]
payload: string
decoded?: {
args: Codec[];
event: {
args: {
name: string;
type: TypeDef;
}[];
docs: string[];
fromU8a: (data: Uint8Array) => DecodedEvent;
identifier: string;
index: number;
}
}
}

Conclusione

Gli eventi sono un aspetto cruciale dello sviluppo di Phat Contract, in quanto consentono di determinare il successo o il fallimento della transazione e forniscono preziose informazioni sull’attività del cluster. È importante familiarizzare con lo schema degli eventi per poterli utilizzare in modo efficace.

A proposito di Phala

Phala Network è un cloud decentralizzato che offre un’elaborazione sicura e scalabile per il Web3.

Con Phat Contracts, un modello di programmazione innovativo che consente di effettuare calcoli trustless off-chain, gli sviluppatori possono creare nuovi casi d’uso del Web3.

Subscribe | Twitter | Youtube | Github | Discord | Forum | Telegram

--

--

pigro85
Phala Italia

Passionate about retro gaming and blockchain. I feel like a digital nomad.