| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923 |
- package main
- import (
- "context"
- "crypto/ecdsa"
- "errors"
- "fmt"
- "log"
- "math/big"
- "os"
- "strings"
- "time"
- "github.com/ethereum/go-ethereum/accounts/abi"
- "github.com/ethereum/go-ethereum/accounts/abi/bind"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethclient"
- "github.com/joho/godotenv"
- "github.com/spf13/cobra"
- )
- var (
- rpcURL string
- coinAddr string
- tokenAddr string
- pkHex string
- )
- func loadEnv() {
- _ = godotenv.Load("../.env")
- _ = godotenv.Load(".env")
- if rpcURL == "" {
- rpcURL = os.Getenv("RPC_URL")
- if rpcURL == "" {
- rpcURL = os.Getenv("POLYGON_RPC_URL")
- if rpcURL == "" {
- rpcURL = os.Getenv("AMOY_RPC_URL")
- }
- }
- }
- if coinAddr == "" {
- coinAddr = os.Getenv("EASY_COIN_ADDR")
- }
- if tokenAddr == "" {
- tokenAddr = os.Getenv("EASY_TOKEN_ADDR")
- }
- if pkHex == "" {
- pkHex = os.Getenv("PRIVATE_KEY")
- if pkHex == "" {
- pkHex = os.Getenv("EASY_ADMIN_PRIVATE_KEY")
- if pkHex == "" {
- pkHex = os.Getenv("EASY_ADMIM_PRIVATE_KEY") // fallback to example typo
- }
- }
- }
- }
- func mustClient(ctx context.Context) (*ethclient.Client, *big.Int) {
- if rpcURL == "" {
- log.Fatal("RPC URL not set: use --rpc or set RPC_URL/POLYGON_RPC_URL/AMOY_RPC_URL in .env")
- }
- c, err := ethclient.DialContext(ctx, rpcURL)
- if err != nil {
- log.Fatalf("dial rpc: %v", err)
- }
- chainID, err := c.ChainID(ctx)
- if err != nil {
- log.Fatalf("get chain id: %v", err)
- }
- return c, chainID
- }
- func mustPrivKey() *ecdsa.PrivateKey {
- if pkHex == "" {
- log.Fatal("Private key not set: use --pk or set PRIVATE_KEY/EASY_ADMIN_PRIVATE_KEY in .env")
- }
- pk, err := crypto.HexToECDSA(strings.TrimPrefix(pkHex, "0x"))
- if err != nil {
- log.Fatalf("invalid private key: %v", err)
- }
- return pk
- }
- func fromHex32(s string) ([32]byte, error) {
- var out [32]byte
- b := common.FromHex(s)
- if len(b) != 32 {
- return out, fmt.Errorf("expected 32 bytes, got %d", len(b))
- }
- copy(out[:], b)
- return out, nil
- }
- func roleID(name string) [32]byte {
- upper := strings.ToUpper(name)
- if upper == "DEFAULT_ADMIN_ROLE" || upper == "DEFAULT_ADMIN" || upper == "ADMIN" {
- return [32]byte{}
- }
- // roles are keccak256("<ROLE>"), e.g. "PAUSER_ROLE"
- h := crypto.Keccak256([]byte(upper))
- var out [32]byte
- copy(out[:], h)
- return out
- }
- func mustAddress(hex string, envName string) common.Address {
- if hex == "" {
- log.Fatalf("missing address: set %s or pass a flag", envName)
- }
- if !common.IsHexAddress(hex) {
- log.Fatalf("invalid address for %s: %s", envName, hex)
- }
- return common.HexToAddress(hex)
- }
- func toWei(amount string) (*big.Int, error) {
- // parse base-unit integer (no decimals handling here)
- if strings.Contains(amount, ".") {
- return nil, errors.New("amount must be an integer in base units (no decimal point)")
- }
- z := new(big.Int)
- _, ok := z.SetString(amount, 10)
- if !ok {
- return nil, fmt.Errorf("invalid amount: %s", amount)
- }
- return z, nil
- }
- func boundContract(addr common.Address, abiJSON string, c *ethclient.Client) *bind.BoundContract {
- parsed, err := abi.JSON(strings.NewReader(abiJSON))
- if err != nil {
- log.Fatalf("parse abi: %v", err)
- }
- return bind.NewBoundContract(addr, parsed, c, c, c)
- }
- func txOpts(ctx context.Context, c *ethclient.Client, chainID *big.Int) *bind.TransactOpts {
- pk := mustPrivKey()
- auth, err := bind.NewKeyedTransactorWithChainID(pk, chainID)
- if err != nil {
- log.Fatalf("transactor: %v", err)
- }
- auth.Context = ctx
- // let node estimate gas; we can set a reasonable timeout
- return auth
- }
- func callOpts(ctx context.Context) *bind.CallOpts {
- return &bind.CallOpts{Context: ctx}
- }
- // ABI call helpers compatible with go-ethereum v1.14 BoundContract.Call
- func callOut(ctx context.Context, con *bind.BoundContract, method string, args ...interface{}) ([]interface{}, error) {
- var out []interface{}
- if err := con.Call(callOpts(ctx), &out, method, args...); err != nil {
- return nil, err
- }
- return out, nil
- }
- func callString(ctx context.Context, con *bind.BoundContract, method string, args ...interface{}) (string, error) {
- out, err := callOut(ctx, con, method, args...)
- if err != nil { return "", err }
- v, ok := out[0].(string)
- if !ok { return "", fmt.Errorf("unexpected %T", out[0]) }
- return v, nil
- }
- func callBool(ctx context.Context, con *bind.BoundContract, method string, args ...interface{}) (bool, error) {
- out, err := callOut(ctx, con, method, args...)
- if err != nil { return false, err }
- v, ok := out[0].(bool)
- if !ok { return false, fmt.Errorf("unexpected %T", out[0]) }
- return v, nil
- }
- func callUint8(ctx context.Context, con *bind.BoundContract, method string, args ...interface{}) (uint8, error) {
- out, err := callOut(ctx, con, method, args...)
- if err != nil { return 0, err }
- v, ok := out[0].(uint8)
- if !ok { return 0, fmt.Errorf("unexpected %T", out[0]) }
- return v, nil
- }
- func callBig(ctx context.Context, con *bind.BoundContract, method string, args ...interface{}) (*big.Int, error) {
- out, err := callOut(ctx, con, method, args...)
- if err != nil { return nil, err }
- v, ok := out[0].(*big.Int)
- if !ok { return nil, fmt.Errorf("unexpected %T", out[0]) }
- return v, nil
- }
- func callAddress(ctx context.Context, con *bind.BoundContract, method string, args ...interface{}) (common.Address, error) {
- out, err := callOut(ctx, con, method, args...)
- if err != nil { return common.Address{}, err }
- v, ok := out[0].(common.Address)
- if !ok { return common.Address{}, fmt.Errorf("unexpected %T", out[0]) }
- return v, nil
- }
- func callBytes32(ctx context.Context, con *bind.BoundContract, method string, args ...interface{}) ([32]byte, error) {
- out, err := callOut(ctx, con, method, args...)
- if err != nil { return [32]byte{}, err }
- v, ok := out[0].([32]byte)
- if !ok { return [32]byte{}, fmt.Errorf("unexpected %T", out[0]) }
- return v, nil
- }
- func cmdCoin() *cobra.Command {
- coinCmd := &cobra.Command{
- Use: "coin",
- Short: "Interact with EasyBRL (ERC20)",
- }
- // info
- coinCmd.AddCommand(&cobra.Command{
- Use: "info",
- Short: "Show ERC20 name, symbol, decimals, totalSupply, paused",
- Run: func(cmd *cobra.Command, args []string) {
- loadEnv()
- ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
- defer cancel()
- c, _ := mustClient(ctx)
- addr := mustAddress(coinAddr, "EASY_COIN_ADDR")
- con := boundContract(addr, easyBRLStableABI, c)
- name, err := callString(ctx, con, "name"); if err != nil { log.Fatal(err) }
- symbol, err := callString(ctx, con, "symbol"); if err != nil { log.Fatal(err) }
- decimals, err := callUint8(ctx, con, "decimals"); if err != nil { log.Fatal(err) }
- total, err := callBig(ctx, con, "totalSupply"); if err != nil { log.Fatal(err) }
- paused, err := callBool(ctx, con, "paused"); if err != nil { log.Fatal(err) }
- fmt.Printf("name=%s symbol=%s decimals=%d totalSupply=%s paused=%v\n", name, symbol, decimals, total.String(), paused)
- },
- })
- // balance
- var balAddr string
- balCmd := &cobra.Command{
- Use: "balance",
- Short: "Get ERC20 balance of an address",
- Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if balAddr == "" { log.Fatal("--address required") }
- ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second); defer cancel()
- c, _ := mustClient(ctx)
- addr := mustAddress(coinAddr, "EASY_COIN_ADDR")
- con := boundContract(addr, easyBRLStableABI, c)
- bal, err := callBig(ctx, con, "balanceOf", common.HexToAddress(balAddr)); if err != nil { log.Fatal(err) }
- fmt.Println(bal.String())
- },
- }
- balCmd.Flags().StringVar(&balAddr, "address", "", "Address to query")
- coinCmd.AddCommand(balCmd)
- // transfer
- var trTo, trAmt string
- trCmd := &cobra.Command{
- Use: "transfer",
- Short: "Transfer ERC20 tokens (base units)",
- Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if trTo == "" || trAmt == "" { log.Fatal("--to and --amount required") }
- amt, err := toWei(trAmt); if err != nil { log.Fatal(err) }
- ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second); defer cancel()
- c, chain := mustClient(ctx)
- auth := txOpts(ctx, c, chain)
- addr := mustAddress(coinAddr, "EASY_COIN_ADDR")
- con := boundContract(addr, easyBRLStableABI, c)
- tx, err := con.Transact(auth, "transfer", common.HexToAddress(trTo), amt); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- },
- }
- trCmd.Flags().StringVar(&trTo, "to", "", "Recipient address")
- trCmd.Flags().StringVar(&trAmt, "amount", "", "Amount in base units")
- coinCmd.AddCommand(trCmd)
- // approve
- var apSp, apAmt string
- apCmd := &cobra.Command{
- Use: "approve",
- Short: "Approve spender (base units)",
- Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if apSp == "" || apAmt == "" { log.Fatal("--spender and --amount required") }
- amt, err := toWei(apAmt); if err != nil { log.Fatal(err) }
- ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- addr := mustAddress(coinAddr, "EASY_COIN_ADDR")
- con := boundContract(addr, easyBRLStableABI, c)
- tx, err := con.Transact(auth, "approve", common.HexToAddress(apSp), amt); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- },
- }
- apCmd.Flags().StringVar(&apSp, "spender", "", "Spender address")
- apCmd.Flags().StringVar(&apAmt, "amount", "", "Amount in base units")
- coinCmd.AddCommand(apCmd)
- // allowance
- var alOwn, alSp string
- alCmd := &cobra.Command{
- Use: "allowance",
- Short: "Check allowance(owner,spender)",
- Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if alOwn == "" || alSp == "" { log.Fatal("--owner and --spender required") }
- ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second); defer cancel()
- c, _ := mustClient(ctx)
- addr := mustAddress(coinAddr, "EASY_COIN_ADDR")
- con := boundContract(addr, easyBRLStableABI, c)
- v, err := callBig(ctx, con, "allowance", common.HexToAddress(alOwn), common.HexToAddress(alSp)); if err != nil { log.Fatal(err) }
- fmt.Println(v.String())
- },
- }
- alCmd.Flags().StringVar(&alOwn, "owner", "", "Owner address")
- alCmd.Flags().StringVar(&alSp, "spender", "", "Spender address")
- coinCmd.AddCommand(alCmd)
- // transfer-from
- var tfFrom, tfTo, tfAmt string
- tfCmd := &cobra.Command{
- Use: "transfer-from",
- Short: "Transfer from (requires allowance)",
- Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if tfFrom == "" || tfTo == "" || tfAmt == "" { log.Fatal("--from --to --amount required") }
- amt, err := toWei(tfAmt); if err != nil { log.Fatal(err) }
- ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- addr := mustAddress(coinAddr, "EASY_COIN_ADDR")
- con := boundContract(addr, easyBRLStableABI, c)
- tx, err := con.Transact(auth, "transferFrom", common.HexToAddress(tfFrom), common.HexToAddress(tfTo), amt); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- },
- }
- tfCmd.Flags().StringVar(&tfFrom, "from", "", "From address")
- tfCmd.Flags().StringVar(&tfTo, "to", "", "To address")
- tfCmd.Flags().StringVar(&tfAmt, "amount", "", "Amount in base units")
- coinCmd.AddCommand(tfCmd)
- // paused
- coinCmd.AddCommand(&cobra.Command{Use: "paused", Short: "Is paused?", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second); defer cancel()
- c, _ := mustClient(ctx)
- addr := mustAddress(coinAddr, "EASY_COIN_ADDR")
- con := boundContract(addr, easyBRLStableABI, c)
- p, err := callBool(ctx, con, "paused"); if err != nil { log.Fatal(err) }
- fmt.Println(p)
- }})
- // pause/unpause
- coinCmd.AddCommand(&cobra.Command{Use: "pause", Short: "Pause transfers", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- addr := mustAddress(coinAddr, "EASY_COIN_ADDR")
- con := boundContract(addr, easyBRLStableABI, c)
- tx, err := con.Transact(auth, "pause"); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- }})
- coinCmd.AddCommand(&cobra.Command{Use: "unpause", Short: "Unpause transfers", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- addr := mustAddress(coinAddr, "EASY_COIN_ADDR")
- con := boundContract(addr, easyBRLStableABI, c)
- tx, err := con.Transact(auth, "unpause"); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- }})
- // blacklist
- var blAcc string; var blStatus bool
- blCmd := &cobra.Command{Use: "set-blacklist", Short: "Set blacklist status", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if blAcc=="" { log.Fatal("--account required") }
- ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- addr := mustAddress(coinAddr, "EASY_COIN_ADDR")
- con := boundContract(addr, easyBRLStableABI, c)
- tx, err := con.Transact(auth, "setBlacklist", common.HexToAddress(blAcc), blStatus); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- }}
- blCmd.Flags().StringVar(&blAcc, "account", "", "Account address")
- blCmd.Flags().BoolVar(&blStatus, "status", false, "Blacklist status")
- coinCmd.AddCommand(blCmd)
- var qblAcc string
- {
- cmd := &cobra.Command{Use: "is-blacklisted", Short: "Check blacklist", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if qblAcc=="" { log.Fatal("--account required") }
- ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second); defer cancel()
- c, _ := mustClient(ctx)
- addr := mustAddress(coinAddr, "EASY_COIN_ADDR")
- con := boundContract(addr, easyBRLStableABI, c)
- v, err := callBool(ctx, con, "isBlacklisted", common.HexToAddress(qblAcc)); if err != nil { log.Fatal(err) }
- fmt.Println(v)
- }}
- cmd.Flags().StringVar(&qblAcc, "account", "", "Account address")
- coinCmd.AddCommand(cmd)
- }
- // mint
- var miTo, miAmt string
- miCmd := &cobra.Command{Use: "mint", Short: "Mint tokens (admin only)", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if miTo==""||miAmt=="" { log.Fatal("--to --amount required") }
- amt, err := toWei(miAmt); if err!=nil { log.Fatal(err) }
- ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- addr := mustAddress(coinAddr, "EASY_COIN_ADDR")
- con := boundContract(addr, easyBRLStableABI, c)
- tx, err := con.Transact(auth, "mint", common.HexToAddress(miTo), amt); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- }}
- miCmd.Flags().StringVar(&miTo, "to", "", "Recipient address")
- miCmd.Flags().StringVar(&miAmt, "amount", "", "Amount in base units")
- coinCmd.AddCommand(miCmd)
- // burn & burn-from
- var buAmt string
- {
- cmd := &cobra.Command{Use: "burn", Short: "Burn own balance (admin only)", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if buAmt=="" { log.Fatal("--amount required") }
- amt, err := toWei(buAmt); if err!=nil { log.Fatal(err) }
- ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- addr := mustAddress(coinAddr, "EASY_COIN_ADDR")
- con := boundContract(addr, easyBRLStableABI, c)
- tx, err := con.Transact(auth, "burn", amt); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- }}
- cmd.Flags().StringVar(&buAmt, "amount", "", "Amount in base units")
- coinCmd.AddCommand(cmd)
- }
- var bfAcc, bfAmt string
- bfCmd := &cobra.Command{Use: "burn-from", Short: "Burn from account (admin only)", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if bfAcc==""||bfAmt=="" { log.Fatal("--account --amount required") }
- amt, err := toWei(bfAmt); if err!=nil { log.Fatal(err) }
- ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- addr := mustAddress(coinAddr, "EASY_COIN_ADDR")
- con := boundContract(addr, easyBRLStableABI, c)
- tx, err := con.Transact(auth, "burnFrom", common.HexToAddress(bfAcc), amt); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- }}
- bfCmd.Flags().StringVar(&bfAcc, "account", "", "Account")
- bfCmd.Flags().StringVar(&bfAmt, "amount", "", "Amount in base units")
- coinCmd.AddCommand(bfCmd)
- // roles
- var rrRole, rrAcc string
- grCmd := &cobra.Command{Use: "grant-role", Short: "Grant role to account", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if rrRole==""||rrAcc=="" { log.Fatal("--role --account required") }
- ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- addr := mustAddress(coinAddr, "EASY_COIN_ADDR")
- con := boundContract(addr, easyBRLStableABI, c)
- role := roleID(rrRole)
- tx, err := con.Transact(auth, "grantRole", role, common.HexToAddress(rrAcc)); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- }}
- grCmd.Flags().StringVar(&rrRole, "role", "", "Role name (DEFAULT_ADMIN_ROLE, PAUSER_ROLE, MINTER_ROLE, COMPLIANCE_ROLE)")
- grCmd.Flags().StringVar(&rrAcc, "account", "", "Account address")
- coinCmd.AddCommand(grCmd)
- rrRole, rrAcc = "", ""
- rvCmd := &cobra.Command{Use: "revoke-role", Short: "Revoke role from account", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if rrRole==""||rrAcc=="" { log.Fatal("--role --account required") }
- ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- addr := mustAddress(coinAddr, "EASY_COIN_ADDR")
- con := boundContract(addr, easyBRLStableABI, c)
- role := roleID(rrRole)
- tx, err := con.Transact(auth, "revokeRole", role, common.HexToAddress(rrAcc)); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- }}
- rvCmd.Flags().StringVar(&rrRole, "role", "", "Role name")
- rvCmd.Flags().StringVar(&rrAcc, "account", "", "Account address")
- coinCmd.AddCommand(rvCmd)
- rrRole, rrAcc = "", ""
- hasCmd := &cobra.Command{Use: "has-role", Short: "Check role for account", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if rrRole==""||rrAcc=="" { log.Fatal("--role --account required") }
- ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second); defer cancel()
- c, _ := mustClient(ctx)
- addr := mustAddress(coinAddr, "EASY_COIN_ADDR")
- con := boundContract(addr, easyBRLStableABI, c)
- role := roleID(rrRole)
- v, err := callBool(ctx, con, "hasRole", role, common.HexToAddress(rrAcc)); if err != nil { log.Fatal(err) }
- fmt.Println(v)
- }}
- hasCmd.Flags().StringVar(&rrRole, "role", "", "Role name")
- hasCmd.Flags().StringVar(&rrAcc, "account", "", "Account address")
- coinCmd.AddCommand(hasCmd)
- var gcAcc string
- {
- cmd := &cobra.Command{Use: "grant-compliance-role", Short: "Grant COMPLIANCE_ROLE via helper", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if gcAcc=="" { log.Fatal("--account required") }
- ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- addr := mustAddress(coinAddr, "EASY_COIN_ADDR")
- con := boundContract(addr, easyBRLStableABI, c)
- tx, err := con.Transact(auth, "grantComplianceRole", common.HexToAddress(gcAcc)); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- }}
- cmd.Flags().StringVar(&gcAcc, "account", "", "Account address")
- coinCmd.AddCommand(cmd)
- }
- return coinCmd
- }
- func cmdToken() *cobra.Command {
- tokCmd := &cobra.Command{Use: "token", Short: "Interact with EasyToken (ERC721)"}
- // info
- tokCmd.AddCommand(&cobra.Command{Use: "info", Short: "Show ERC721 name, symbol, paused", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second); defer cancel()
- c, _ := mustClient(ctx)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- name, err := callString(ctx, con, "name"); if err != nil { log.Fatal(err) }
- symbol, err := callString(ctx, con, "symbol"); if err != nil { log.Fatal(err) }
- paused, err := callBool(ctx, con, "paused"); if err != nil { log.Fatal(err) }
- fmt.Printf("name=%s symbol=%s paused=%v\n", name, symbol, paused)
- }})
- // owner-of
- var ooID string
- {
- cmd := &cobra.Command{Use: "owner-of", Short: "Owner of tokenId", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if ooID=="" { log.Fatal("--token-id required") }
- id, ok := new(big.Int).SetString(ooID, 10); if !ok { log.Fatal("invalid token-id") }
- ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second); defer cancel()
- c, _ := mustClient(ctx)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- owner, err := callAddress(ctx, con, "ownerOf", id); if err != nil { log.Fatal(err) }
- fmt.Println(owner.Hex())
- }}
- cmd.Flags().StringVar(&ooID, "token-id", "", "Token ID")
- tokCmd.AddCommand(cmd)
- }
- // balance
- var tbAddr string
- {
- cmd := &cobra.Command{Use: "balance", Short: "Number of NFTs for address", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if tbAddr=="" { log.Fatal("--address required") }
- ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second); defer cancel()
- c, _ := mustClient(ctx)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- bal, err := callBig(ctx, con, "balanceOf", common.HexToAddress(tbAddr)); if err != nil { log.Fatal(err) }
- fmt.Println(bal.String())
- }}
- cmd.Flags().StringVar(&tbAddr, "address", "", "Address")
- tokCmd.AddCommand(cmd)
- }
- // token-uri
- var tuID string
- {
- cmd := &cobra.Command{Use: "token-uri", Short: "Get tokenURI", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if tuID=="" { log.Fatal("--token-id required") }
- id, ok := new(big.Int).SetString(tuID, 10); if !ok { log.Fatal("invalid token-id") }
- ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second); defer cancel()
- c, _ := mustClient(ctx)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- uri, err := callString(ctx, con, "tokenURI", id); if err != nil { log.Fatal(err) }
- fmt.Println(uri)
- }}
- cmd.Flags().StringVar(&tuID, "token-id", "", "Token ID")
- tokCmd.AddCommand(cmd)
- }
- // doc-hash
- var dhID string
- {
- cmd := &cobra.Command{Use: "doc-hash", Short: "Get document hash", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if dhID=="" { log.Fatal("--token-id required") }
- id, ok := new(big.Int).SetString(dhID, 10); if !ok { log.Fatal("invalid token-id") }
- ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second); defer cancel()
- c, _ := mustClient(ctx)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- h, err := callBytes32(ctx, con, "documentHashOf", id); if err != nil { log.Fatal(err) }
- fmt.Println("0x" + common.Bytes2Hex(h[:]))
- }}
- cmd.Flags().StringVar(&dhID, "token-id", "", "Token ID")
- tokCmd.AddCommand(cmd)
- }
- // appraisal
- var apID string
- {
- cmd := &cobra.Command{Use: "appraisal", Short: "Get appraisal value (base units)", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if apID=="" { log.Fatal("--token-id required") }
- id, ok := new(big.Int).SetString(apID, 10); if !ok { log.Fatal("invalid token-id") }
- ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second); defer cancel()
- c, _ := mustClient(ctx)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- v, err := callBig(ctx, con, "appraisalOf", id); if err != nil { log.Fatal(err) }
- fmt.Println(v.String())
- }}
- cmd.Flags().StringVar(&apID, "token-id", "", "Token ID")
- tokCmd.AddCommand(cmd)
- }
- // set-token-uri
- var stuID, stuURI string
- {
- cmd := &cobra.Command{Use: "set-token-uri", Short: "Set token URI (METADATA_ROLE)", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if stuID==""||stuURI=="" { log.Fatal("--token-id --uri required") }
- id, ok := new(big.Int).SetString(stuID, 10); if !ok { log.Fatal("invalid token-id") }
- ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- tx, err := con.Transact(auth, "setTokenURI", id, stuURI); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- }}
- cmd.Flags().StringVar(&stuID, "token-id", "", "Token ID")
- cmd.Flags().StringVar(&stuURI, "uri", "", "New URI")
- tokCmd.AddCommand(cmd)
- }
- // set-appraisal
- var sapID, sapVal string
- {
- cmd := &cobra.Command{Use: "set-appraisal", Short: "Set appraisal value (base units)", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if sapID==""||sapVal=="" { log.Fatal("--token-id --value required") }
- id, ok := new(big.Int).SetString(sapID, 10); if !ok { log.Fatal("invalid token-id") }
- val, err := toWei(sapVal); if err != nil { log.Fatal(err) }
- ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- tx, err := con.Transact(auth, "setAppraisal", id, val); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- }}
- cmd.Flags().StringVar(&sapID, "token-id", "", "Token ID")
- cmd.Flags().StringVar(&sapVal, "value", "", "Appraisal in base units")
- tokCmd.AddCommand(cmd)
- }
- // safe-mint
- var smTo, smURI, smHash, smVal string
- {
- cmd := &cobra.Command{Use: "safe-mint", Short: "Mint new document NFT", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if smTo==""||smURI==""||smHash==""||smVal=="" { log.Fatal("--to --uri --hash --value required") }
- h, err := fromHex32(smHash); if err != nil { log.Fatal(err) }
- v, err := toWei(smVal); if err != nil { log.Fatal(err) }
- ctx, cancel := context.WithTimeout(context.Background(), 240*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- tx, err := con.Transact(auth, "safeMint", common.HexToAddress(smTo), smURI, h, v); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- }}
- cmd.Flags().StringVar(&smTo, "to", "", "Recipient address")
- cmd.Flags().StringVar(&smURI, "uri", "", "Document URL")
- cmd.Flags().StringVar(&smHash, "hash", "", "Document hash (0x + 64 hex)")
- cmd.Flags().StringVar(&smVal, "value", "", "Appraisal in base units")
- tokCmd.AddCommand(cmd)
- }
- // transfer & safe-transfer
- var ttTo, ttID string
- {
- cmd := &cobra.Command{Use: "transfer", Short: "transferFrom(sender,to,tokenId)", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if ttTo==""||ttID=="" { log.Fatal("--to --token-id required") }
- id, ok := new(big.Int).SetString(ttID, 10); if !ok { log.Fatal("invalid token-id") }
- ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- sender := crypto.PubkeyToAddress(mustPrivKey().PublicKey)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- tx, err := con.Transact(auth, "safeTransferFrom", sender, common.HexToAddress(ttTo), id); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- }}
- cmd.Flags().StringVar(&ttTo, "to", "", "Recipient address")
- cmd.Flags().StringVar(&ttID, "token-id", "", "Token ID")
- tokCmd.AddCommand(cmd)
- }
- var stTo, stID string
- {
- cmd := &cobra.Command{Use: "safe-transfer", Short: "safeTransferFrom(sender,to,tokenId)", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if stTo==""||stID=="" { log.Fatal("--to --token-id required") }
- id, ok := new(big.Int).SetString(stID, 10); if !ok { log.Fatal("invalid token-id") }
- ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- sender := crypto.PubkeyToAddress(mustPrivKey().PublicKey)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- tx, err := con.Transact(auth, "safeTransferFrom", sender, common.HexToAddress(stTo), id); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- }}
- cmd.Flags().StringVar(&stTo, "to", "", "Recipient address")
- cmd.Flags().StringVar(&stID, "token-id", "", "Token ID")
- tokCmd.AddCommand(cmd)
- }
- // approvals
- var apTo string; var apID2 string
- {
- cmd := &cobra.Command{Use: "approve", Short: "Approve address for tokenId", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if apTo==""||apID2=="" { log.Fatal("--to --token-id required") }
- id, ok := new(big.Int).SetString(apID2, 10); if !ok { log.Fatal("invalid token-id") }
- ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- tx, err := con.Transact(auth, "approve", common.HexToAddress(apTo), id); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- }}
- cmd.Flags().StringVar(&apTo, "to", "", "Approved address")
- cmd.Flags().StringVar(&apID2, "token-id", "", "Token ID")
- tokCmd.AddCommand(cmd)
- }
- var saoOp string; var saoApproved bool
- {
- cmd := &cobra.Command{Use: "set-approval-for-all", Short: "Set operator approval", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if saoOp=="" { log.Fatal("--operator required") }
- ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- tx, err := con.Transact(auth, "setApprovalForAll", common.HexToAddress(saoOp), saoApproved); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- }}
- cmd.Flags().StringVar(&saoOp, "operator", "", "Operator address")
- cmd.Flags().BoolVar(&saoApproved, "approved", false, "Approved status")
- tokCmd.AddCommand(cmd)
- }
- // getters for approvals
- var gaID string
- {
- cmd := &cobra.Command{Use: "get-approved", Short: "Get approved for tokenId", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if gaID=="" { log.Fatal("--token-id required") }
- id, ok := new(big.Int).SetString(gaID, 10); if !ok { log.Fatal("invalid token-id") }
- ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second); defer cancel()
- c, _ := mustClient(ctx)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- a, err := callAddress(ctx, con, "getApproved", id); if err != nil { log.Fatal(err) }
- fmt.Println(a.Hex())
- }}
- cmd.Flags().StringVar(&gaID, "token-id", "", "Token ID")
- tokCmd.AddCommand(cmd)
- }
- var iaOwner, iaOp string
- {
- cmd := &cobra.Command{Use: "is-approved-for-all", Short: "Is operator approved for owner", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if iaOwner==""||iaOp=="" { log.Fatal("--owner --operator required") }
- ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second); defer cancel()
- c, _ := mustClient(ctx)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- v, err := callBool(ctx, con, "isApprovedForAll", common.HexToAddress(iaOwner), common.HexToAddress(iaOp)); if err != nil { log.Fatal(err) }
- fmt.Println(v)
- }}
- cmd.Flags().StringVar(&iaOwner, "owner", "", "Owner address")
- cmd.Flags().StringVar(&iaOp, "operator", "", "Operator address")
- tokCmd.AddCommand(cmd)
- }
- // pause/unpause/paused
- tokCmd.AddCommand(&cobra.Command{Use: "paused", Short: "Is paused?", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second); defer cancel()
- c, _ := mustClient(ctx)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- p, err := callBool(ctx, con, "paused"); if err != nil { log.Fatal(err) }
- fmt.Println(p)
- }})
- tokCmd.AddCommand(&cobra.Command{Use: "pause", Short: "Pause transfers", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- tx, err := con.Transact(auth, "pause"); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- }})
- tokCmd.AddCommand(&cobra.Command{Use: "unpause", Short: "Unpause transfers", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- tx, err := con.Transact(auth, "unpause"); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- }})
- // blacklist
- var tblAcc string; var tblStatus bool
- {
- cmd := &cobra.Command{Use: "set-blacklist", Short: "Set blacklist status", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if tblAcc=="" { log.Fatal("--account required") }
- ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- tx, err := con.Transact(auth, "setBlacklist", common.HexToAddress(tblAcc), tblStatus); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- }}
- cmd.Flags().StringVar(&tblAcc, "account", "", "Account")
- cmd.Flags().BoolVar(&tblStatus, "status", false, "Blacklist status")
- tokCmd.AddCommand(cmd)
- }
- var tqblAcc string
- {
- cmd := &cobra.Command{Use: "is-blacklisted", Short: "Check blacklist", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if tqblAcc=="" { log.Fatal("--account required") }
- ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second); defer cancel()
- c, _ := mustClient(ctx)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- v, err := callBool(ctx, con, "isBlacklisted", common.HexToAddress(tqblAcc)); if err != nil { log.Fatal(err) }
- fmt.Println(v)
- }}
- cmd.Flags().StringVar(&tqblAcc, "account", "", "Account")
- tokCmd.AddCommand(cmd)
- }
- // roles
- var trRole, trAcc string
- {
- cmd := &cobra.Command{Use: "grant-role", Short: "Grant role", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if trRole==""||trAcc=="" { log.Fatal("--role --account required") }
- ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- role := roleID(trRole)
- tx, err := con.Transact(auth, "grantRole", role, common.HexToAddress(trAcc)); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- }}
- cmd.Flags().StringVar(&trRole, "role", "", "Role name (DEFAULT_ADMIN_ROLE, PAUSER_ROLE, MINTER_ROLE, METADATA_ROLE, APPRAISER_ROLE, COMPLIANCE_ROLE)")
- cmd.Flags().StringVar(&trAcc, "account", "", "Account address")
- tokCmd.AddCommand(cmd)
- }
- trRole, trAcc = "", ""
- {
- cmd := &cobra.Command{Use: "revoke-role", Short: "Revoke role", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if trRole==""||trAcc=="" { log.Fatal("--role --account required") }
- ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- role := roleID(trRole)
- tx, err := con.Transact(auth, "revokeRole", role, common.HexToAddress(trAcc)); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- }}
- cmd.Flags().StringVar(&trRole, "role", "", "Role name")
- cmd.Flags().StringVar(&trAcc, "account", "", "Account address")
- tokCmd.AddCommand(cmd)
- }
- trRole, trAcc = "", ""
- {
- cmd := &cobra.Command{Use: "has-role", Short: "Has role?", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if trRole==""||trAcc=="" { log.Fatal("--role --account required") }
- ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second); defer cancel()
- c, _ := mustClient(ctx)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- role := roleID(trRole)
- v, err := callBool(ctx, con, "hasRole", role, common.HexToAddress(trAcc)); if err != nil { log.Fatal(err) }
- fmt.Println(v)
- }}
- cmd.Flags().StringVar(&trRole, "role", "", "Role name")
- cmd.Flags().StringVar(&trAcc, "account", "", "Account address")
- tokCmd.AddCommand(cmd)
- }
- var tgcAcc string
- {
- cmd := &cobra.Command{Use: "grant-compliance-role", Short: "Grant COMPLIANCE_ROLE via helper", Run: func(cmd *cobra.Command, args []string) {
- loadEnv(); if tgcAcc=="" { log.Fatal("--account required") }
- ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second); defer cancel()
- c, chain := mustClient(ctx); auth := txOpts(ctx, c, chain)
- addr := mustAddress(tokenAddr, "EASY_TOKEN_ADDR")
- con := boundContract(addr, easyTokenDocumentABI, c)
- tx, err := con.Transact(auth, "grantComplianceRole", common.HexToAddress(tgcAcc)); if err != nil { log.Fatal(err) }
- fmt.Println(tx.Hash().Hex())
- }}
- cmd.Flags().StringVar(&tgcAcc, "account", "", "Account address")
- tokCmd.AddCommand(cmd)
- }
- return tokCmd
- }
- func cmdPolygon() *cobra.Command {
- pg := &cobra.Command{Use: "polygon", Short: "Polygon utilities"}
- pg.AddCommand(&cobra.Command{Use: "create-new-address", Short: "Generate a new wallet", Run: func(cmd *cobra.Command, args []string) {
- pk, err := crypto.GenerateKey(); if err != nil { log.Fatal(err) }
- pkHex := "0x" + common.Bytes2Hex(crypto.FromECDSA(pk))
- pubHex := "0x" + common.Bytes2Hex(crypto.FromECDSAPub(&pk.PublicKey))
- addr := crypto.PubkeyToAddress(pk.PublicKey).Hex()
- fmt.Printf("privateKey=%s\npublicKey=%s\naddress=%s\n", pkHex, pubHex, addr)
- }})
- return pg
- }
- func main() {
- root := &cobra.Command{Use: "sdk", Short: "CLI for EasyBRL (coin) and EasyToken (token)"}
- root.PersistentFlags().StringVar(&rpcURL, "rpc", "", "RPC URL (overrides .env)")
- root.PersistentFlags().StringVar(&pkHex, "pk", "", "Private key hex (overrides .env)")
- root.PersistentFlags().StringVar(&coinAddr, "coin-addr", coinAddr, "ERC20 contract address (overrides .env)")
- root.PersistentFlags().StringVar(&tokenAddr, "token-addr", tokenAddr, "ERC721 contract address (overrides .env)")
- root.AddCommand(cmdCoin())
- root.AddCommand(cmdToken())
- root.AddCommand(cmdPolygon())
- if err := root.Execute(); err != nil {
- os.Exit(1)
- }
- }
|