kardiachain / go-kardia

Golang implementation of KardiaChain Decentralize Network
https://kardiachain.io
GNU Lesser General Public License v3.0
33 stars 18 forks source link

Need a abigen tool to bind KardiaChain smart contracts to a golang package #148

Closed trinhdn97 closed 3 years ago

trinhdn97 commented 3 years ago

This PR is an initial stab at a web3 equivalent Go binding generator. It creates a abigen command that takes a contract ABI and input and generates a Go package/file as output containing all type safe wrapper code to interact with an instance of the particular contract on the blockchain.

Some of the features it includes:

This PR also expands the generated code with new types and methods to support filtering past contract events, and subscribing to a stream of future events!

For every event present in the contract, abigen will create a Go counterpart. E.g. for the Transfer event in the token contract:

event Transfer(address indexed from, address indexed to, uint256 value);
// Krc721Transfer represents a Transfer event raised by the Krc721 contract.
type Krc721Transfer struct {
    From    common.Address
    To      common.Address
    TokenId *big.Int
    Raw     types.Log // Blockchain specific contextual infos
}

For each event, abigen will generate a Filter<event name> method to retrieve past logs. As you can see below, the topics being filtered for are strongly typed Go types, not topic hashes as all other APIs surface. This allows calling code to be meaningfully read and understood without having to guess what some cryptic numbers mean. abigen will generate all the necessary code to convert the user types into topic filter criteria under the hood.

The log filterer method returns an iterator that can be used to iterate over the found logs, each already unpacked from its raw Kardia RLP encoded form (and topic form) into strongly typed Go structs like Krc721Transfer listed above.

// FilterTransfer is a free log retrieval operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef.
//
// Solidity: event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)
func (_Krc721 *Krc721Filterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address, tokenId []*big.Int) (*Krc721TransferIterator, error) {

Similarly, for each event, abigen will generate a Watch<event name> method to subscribe to future logs and similarly to filtering past events, subscribing to future ones can be done via strongly typed criteria.

The method also takes a sink channel as an argument to deliver newly found contract events on, and returns a subscription which can be used to tear down the watcher constructs. As with past event subscriptions, the events streamed in the user-provided channel are strongly typed like Krc721Transfer above.

// WatchTransfer is a free log subscription operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef.
//
// Solidity: event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)
func (_Krc721 *Krc721Filterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *Krc721Transfer, from []common.Address, to []common.Address, tokenId []*big.Int) (event.Subscription, error) {

Caveats

Filtering for past log events returns an iterator for future API stability. The current implementation under the hood runs the entire user filtering in one big go, caches the entire results and then uses the iterator to simulate streaming filtering. This will be replaced eventually, but to avoid breaking the API then, we're enforcing this future mode of operation in user code already now.

Watching for future log events has an optional parameter for specifying the starting block number. abigen will naively be able to use it without API changes.

trinhdn97 commented 3 years ago

Implemented at https://github.com/kardiachain/go-kardia/pull/147