Easinteraction For Cadence(WIP)
Easinteraction is a tool that help users to generate code for easier contract interaction.
This version is for Cadence(Flow Blockchain)
and Golang
.
Get Started
Installation
$ go install github.com/LemonNekoGH/easinteraction-for-cadence/cmd/easi-gen@latest
# or use brew if you do not have go installed
$ brew tap LemonNekoGH/tap
$ brew install easi-gen
Homebrew is a package manager for macOS.
Usage
$ easi-gen --source NekosMerge.cdc --output nekosmerge.go --pkg-name nekosmerge
Now easi-gen
will read your Cadence
code from NekosMerge.cdc
, then parse the code, then generate Go
code with package name nekosmerge
and output to nekosmerge.go
.
If no --pkg-name
flag specified, it will use mypackage
as default.
If no --source
flag specified, it will read from standard input.
If no --output
flag specified, it will output to standard output.
So you can also use it like this:
$ cat NekosMerge.cdc | easi-gen --pkg-name nekosmerge > nekosmerge.go
Result Preview
Cadence code:
pub contract UserProfiles {
access(self) let usernames: {Address:String}
pub fun setName(_ acc: AuthAccount, _ name: String) {
self.usernames[acc.address] = name
}
pub fun getName(_ addr: Address): String {
return self.usernames[addr] ?? ""
}
init() {
self.usernames = {}
}
}
Go code:
package mypackage
import (
"context"
"fmt"
"github.com/LemonNekoGH/godence"
"github.com/onflow/cadence"
flowSdk "github.com/onflow/flow-go-sdk"
flowGrpc "github.com/onflow/flow-go-sdk/access/grpc"
flowCrypto "github.com/onflow/flow-go-sdk/crypto"
)
type ContractUserProfiles struct {
address string
flowCli *flowGrpc.Client
}
// NewUserProfilesContract construct a new ContractUserProfiles instance.
func NewUserProfilesContract(address string, flowCli *flowGrpc.Client) (*ContractUserProfiles, error) {
// prepare script
script := fmt.Sprintf(`import UserProfiles from %s
pub fun main(){}
`, address)
// send a script to ensure contract address is correct
_, err := flowCli.ExecuteScriptAtLatestBlock(context.Background(), []byte(script), nil)
if err != nil {
return nil, err
}
return &ContractUserProfiles{
address: address,
flowCli: flowCli,
}, nil
}
// SetName will change Flow blockchain's state.
// Signature: pub fun setName(user acc: AuthAccount,to name: String)
func (c *ContractUserProfiles) SetName(
arg1 string,
authorizer0, payer, proposer flowSdk.Address,
authorizerKeyIndex, payerKeyIndex, proposalKeyIndex int,
authorizerSigner, payerSigner flowCrypto.Signer,
) (*flowSdk.Identifier, error) {
// get reference id
block, err := c.flowCli.GetLatestBlock(context.Background(), true)
if err != nil {
return nil, err
}
// get proposer sequence number
propAcct, err := c.flowCli.GetAccount(context.Background(), proposer)
if err != nil {
return nil, err
}
// gen script
script := fmt.Sprintf(`import UserProfiles from %s
transaction(arg1: String) {
prepare(arg0: AuthAccount) {
UserProfiles.setName(user:arg0,to:arg1)
}
}
`, c.address)
// construct tx
tx := flowSdk.NewTransaction().
SetScript([]byte(script)).
AddAuthorizer(authorizer0).
SetPayer(payer).
SetProposalKey(proposer, proposalKeyIndex, propAcct.Keys[proposalKeyIndex].SequenceNumber).
SetReferenceBlockID(block.ID).
SetGasLimit(9999)
// add argument
argCdc1, err := godence.ToCadence(
arg1,
)
if err != nil {
return nil, err
}
err = tx.AddArgument(argCdc1)
if err != nil {
return nil, err
}
if authorizer0.String() != payer.String() {
// sign payload
err = tx.SignPayload(authorizer0, authorizerKeyIndex, authorizerSigner)
if err != nil {
return nil, err
}
}
// sign envelop
err = tx.SignEnvelope(payer, payerKeyIndex, payerSigner)
if err != nil {
return nil, err
}
// send
err = c.flowCli.SendTransaction(context.Background(), *tx)
if err != nil {
return nil, err
}
id := tx.ID()
return &id, nil
}
// GetName will query from Flow blockchain.
// Signature: pub fun getName(_ addr: Address): String
func (c *ContractUserProfiles) GetName(
arg0 string,
) (*string, error) {
// gen script
script := fmt.Sprintf(`import UserProfiles from %s
pub fun main(arg0: Address): String{
return UserProfiles.getName(arg0)
}
`, c.address)
// prepare args
args := []cadence.Value{}
argCdc0, err := godence.ToCadence(
godence.Address(arg0),
)
if err != nil {
return nil, err
}
args = append(args, argCdc0)
// send query
result, err := c.flowCli.ExecuteScriptAtLatestBlock(context.Background(), []byte(script), args)
if err != nil {
return nil, err
}
// covert result
var ret string
err = godence.ToGo(result, &ret)
if err != nil {
return nil, err
}
return &ret, nil
}
Contributing
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement".
Don't forget to give the project a star! Thanks again!
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature
)
- Commit your Changes (
git commit -m 'Add some AmazingFeature'
)
- Push to the Branch (
git push origin feature/AmazingFeature
)
- Open a Pull Request
Testing
Requirements
- Flow CLI: Use to emulate Flow blockchain network.