Skip to content

Commit

Permalink
Add tron integration
Browse files Browse the repository at this point in the history
  • Loading branch information
cfal committed Dec 13, 2024
1 parent dde1751 commit 009507a
Show file tree
Hide file tree
Showing 67 changed files with 2,048 additions and 5 deletions.
3 changes: 3 additions & 0 deletions core/cmd/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ func NewApp(s *Shell) *cli.App {
keysCommand("Solana", NewSolanaKeysClient(s)),
keysCommand("StarkNet", NewStarkNetKeysClient(s)),
keysCommand("Aptos", NewAptosKeysClient(s)),
keysCommand("Tron", NewTronKeysClient(s)),

initVRFKeysSubCmd(s),
},
Expand Down Expand Up @@ -298,6 +299,7 @@ func NewApp(s *Shell) *cli.App {
chainCommand("Solana", SolanaChainClient(s),
cli.StringFlag{Name: "id", Usage: "chain ID, options: [mainnet, testnet, devnet, localnet]"}),
chainCommand("StarkNet", StarkNetChainClient(s), cli.StringFlag{Name: "id", Usage: "chain ID"}),
chainCommand("Tron", TronChainClient(s), cli.StringFlag{Name: "id", Usage: "chain ID"}),
},
},
{
Expand All @@ -308,6 +310,7 @@ func NewApp(s *Shell) *cli.App {
initCosmosNodeSubCmd(s),
initSolanaNodeSubCmd(s),
initStarkNetNodeSubCmd(s),
initTronNodeSubCmd(s),
},
},
{
Expand Down
4 changes: 4 additions & 0 deletions core/cmd/nodes_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ func initSolanaNodeSubCmd(s *Shell) cli.Command {
return nodeCommand("Solana", NewSolanaNodeClient(s))
}

func initTronNodeSubCmd(s *Shell) cli.Command {
return nodeCommand("Tron", NewTronNodeClient(s))
}

// nodeCommand returns a cli.Command with subcommands for the given NodeClient.
// A string cli.Flag for "name" is automatically included.
func nodeCommand(typ string, client NodeClient) cli.Command {
Expand Down
7 changes: 7 additions & 0 deletions core/cmd/shell.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,13 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G
}
initOps = append(initOps, chainlink.InitAptos(ctx, relayerFactory, aptosCfg))
}
if cfg.TronEnabled() {
tronCfg := chainlink.TronFactoryConfig{
Keystore: keyStore.Tron(),
TOMLConfigs: cfg.TronConfigs(),
}
initOps = append(initOps, chainlink.InitTron(ctx, relayerFactory, tronCfg))
}

relayChainInterops, err := chainlink.NewCoreRelayerChainInteroperators(initOps...)
if err != nil {
Expand Down
9 changes: 9 additions & 0 deletions core/cmd/shell_local.go
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,9 @@ func (s *Shell) runNode(c *cli.Context) error {
if s.Config.AptosEnabled() {
enabledChains = append(enabledChains, chaintype.Aptos)
}
if s.Config.TronEnabled() {
enabledChains = append(enabledChains, chaintype.Tron)
}
err2 := app.GetKeyStore().OCR2().EnsureKeys(rootCtx, enabledChains...)
if err2 != nil {
return errors.Wrap(err2, "failed to ensure ocr key")
Expand Down Expand Up @@ -468,6 +471,12 @@ func (s *Shell) runNode(c *cli.Context) error {
return errors.Wrap(err2, "failed to ensure aptos key")
}
}
if s.Config.TronEnabled() {
err2 := app.GetKeyStore().Tron().EnsureKey(rootCtx)
if err2 != nil {
return errors.Wrap(err2, "failed to ensure tron key")
}
}

err2 := app.GetKeyStore().Workflow().EnsureKey(rootCtx)
if err2 != nil {
Expand Down
48 changes: 48 additions & 0 deletions core/cmd/tron_chains_commands.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package cmd

import (
"strconv"

"github.com/smartcontractkit/chainlink/v2/core/web/presenters"
)

// TronChainPresenter implements TableRenderer for a TronChainResource
type TronChainPresenter struct {
presenters.TronChainResource
}

// ToRow presents the TronChainResource as a slice of strings.
func (p *TronChainPresenter) ToRow() []string {
return []string{p.GetID(), strconv.FormatBool(p.Enabled), p.Config}
}

// RenderTable implements TableRenderer
// Just renders a single row
func (p TronChainPresenter) RenderTable(rt RendererTable) error {
rows := [][]string{}
rows = append(rows, p.ToRow())

renderList(chainHeaders, rows, rt.Writer)

return nil
}

// TronChainPresenters implements TableRenderer for a slice of TronChainPresenters.
type TronChainPresenters []TronChainPresenter

// RenderTable implements TableRenderer
func (ps TronChainPresenters) RenderTable(rt RendererTable) error {
rows := [][]string{}

for _, p := range ps {
rows = append(rows, p.ToRow())
}

renderList(chainHeaders, rows, rt.Writer)

return nil
}

func TronChainClient(s *Shell) ChainClient {
return newChainClient[TronChainPresenters](s, "tron")
}
57 changes: 57 additions & 0 deletions core/cmd/tron_keys_commands.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package cmd

import (
"github.com/smartcontractkit/chainlink-common/pkg/utils"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/tronkey"
"github.com/smartcontractkit/chainlink/v2/core/web/presenters"
)

type TronKeyPresenter struct {
JAID
presenters.TronKeyResource
}

// RenderTable implements TableRenderer
func (p TronKeyPresenter) RenderTable(rt RendererTable) error {
headers := []string{"ID", "Public key"}
rows := [][]string{p.ToRow()}

if _, err := rt.Write([]byte("🔑 Tron Keys\n")); err != nil {
return err
}
renderList(headers, rows, rt.Writer)

return utils.JustError(rt.Write([]byte("\n")))
}

func (p *TronKeyPresenter) ToRow() []string {
row := []string{
p.ID,
p.PubKey,
}

return row
}

type TronKeyPresenters []TronKeyPresenter

// RenderTable implements TableRenderer
func (ps TronKeyPresenters) RenderTable(rt RendererTable) error {
headers := []string{"ID", "Public key"}
rows := [][]string{}

for _, p := range ps {
rows = append(rows, p.ToRow())
}

if _, err := rt.Write([]byte("🔑 Tron Keys\n")); err != nil {
return err
}
renderList(headers, rows, rt.Writer)

return utils.JustError(rt.Write([]byte("\n")))
}

func NewTronKeysClient(s *Shell) KeysClient {
return newKeysClient[tronkey.Key, TronKeyPresenter, TronKeyPresenters]("Tron", s)
}
174 changes: 174 additions & 0 deletions core/cmd/tron_keys_commands_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package cmd_test

import (
"bytes"
"context"
"flag"
"os"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/urfave/cli"

"github.com/smartcontractkit/chainlink-common/pkg/utils"
"github.com/smartcontractkit/chainlink/v2/core/cmd"
"github.com/smartcontractkit/chainlink/v2/core/internal/cltest"
"github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
"github.com/smartcontractkit/chainlink/v2/core/services/chainlink"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/tronkey"
"github.com/smartcontractkit/chainlink/v2/core/web/presenters"
)

func TestTronKeyPresenter_RenderTable(t *testing.T) {
t.Parallel()

var (
id = "1"
pubKey = "somepubkey"
buffer = bytes.NewBufferString("")
r = cmd.RendererTable{Writer: buffer}
)

p := cmd.TronKeyPresenter{
JAID: cmd.JAID{ID: id},
TronKeyResource: presenters.TronKeyResource{
JAID: presenters.NewJAID(id),
PubKey: pubKey,
},
}

// Render a single resource
require.NoError(t, p.RenderTable(r))

output := buffer.String()
assert.Contains(t, output, id)
assert.Contains(t, output, pubKey)

// Render many resources
buffer.Reset()
ps := cmd.TronKeyPresenters{p}
require.NoError(t, ps.RenderTable(r))

output = buffer.String()
assert.Contains(t, output, id)
assert.Contains(t, output, pubKey)
}

func TestShell_TronKeys(t *testing.T) {
app := startNewApplicationV2(t, nil)
ks := app.GetKeyStore().Tron()
cleanup := func() {
ctx := context.Background()
keys, err := ks.GetAll()
require.NoError(t, err)
for _, key := range keys {
require.NoError(t, utils.JustError(ks.Delete(ctx, key.ID())))
}
requireTronKeyCount(t, app, 0)
}

t.Run("ListTronKeys", func(tt *testing.T) {
defer cleanup()
ctx := testutils.Context(t)
client, r := app.NewShellAndRenderer()
key, err := app.GetKeyStore().Tron().Create(ctx)
require.NoError(t, err)
requireTronKeyCount(t, app, 1)
require.NoError(t, cmd.NewTronKeysClient(client).ListKeys(cltest.EmptyCLIContext()))
require.Len(t, r.Renders, 1)
keys := *r.Renders[0].(*cmd.TronKeyPresenters)
assert.Equal(t, key.PublicKeyStr(), keys[0].PubKey)
})

t.Run("CreateTronKey", func(tt *testing.T) {
defer cleanup()
client, _ := app.NewShellAndRenderer()
require.NoError(t, cmd.NewTronKeysClient(client).CreateKey(nilContext))
keys, err := app.GetKeyStore().Tron().GetAll()
require.NoError(t, err)
require.Len(t, keys, 1)
})

t.Run("DeleteTronKey", func(tt *testing.T) {
defer cleanup()
ctx := testutils.Context(t)
client, _ := app.NewShellAndRenderer()
key, err := app.GetKeyStore().Tron().Create(ctx)
require.NoError(t, err)
requireTronKeyCount(t, app, 1)
set := flag.NewFlagSet("test", 0)
flagSetApplyFromAction(cmd.NewTronKeysClient(client).DeleteKey, set, "tron")

require.NoError(tt, set.Set("yes", "true"))

strID := key.ID()
err = set.Parse([]string{strID})
require.NoError(t, err)
c := cli.NewContext(nil, set, nil)
err = cmd.NewTronKeysClient(client).DeleteKey(c)
require.NoError(t, err)
requireTronKeyCount(t, app, 0)
})

t.Run("ImportExportTronKey", func(tt *testing.T) {
defer cleanup()
defer deleteKeyExportFile(t)
ctx := testutils.Context(t)
client, _ := app.NewShellAndRenderer()

_, err := app.GetKeyStore().Tron().Create(ctx)
require.NoError(t, err)

keys := requireTronKeyCount(t, app, 1)
key := keys[0]
keyName := keyNameForTest(t)

// Export test invalid id
set := flag.NewFlagSet("test Tron export", 0)
flagSetApplyFromAction(cmd.NewTronKeysClient(client).ExportKey, set, "tron")

require.NoError(tt, set.Parse([]string{"0"}))
require.NoError(tt, set.Set("new-password", "../internal/fixtures/incorrect_password.txt"))
require.NoError(tt, set.Set("output", keyName))

c := cli.NewContext(nil, set, nil)
err = cmd.NewTronKeysClient(client).ExportKey(c)
require.Error(t, err, "Error exporting")
require.Error(t, utils.JustError(os.Stat(keyName)))

// Export test
set = flag.NewFlagSet("test Tron export", 0)
flagSetApplyFromAction(cmd.NewTronKeysClient(client).ExportKey, set, "tron")

require.NoError(tt, set.Parse([]string{key.ID()}))
require.NoError(tt, set.Set("new-password", "../internal/fixtures/incorrect_password.txt"))
require.NoError(tt, set.Set("output", keyName))

c = cli.NewContext(nil, set, nil)

require.NoError(t, cmd.NewTronKeysClient(client).ExportKey(c))
require.NoError(t, utils.JustError(os.Stat(keyName)))

require.NoError(t, utils.JustError(app.GetKeyStore().Tron().Delete(ctx, key.ID())))
requireTronKeyCount(t, app, 0)

set = flag.NewFlagSet("test Tron import", 0)
flagSetApplyFromAction(cmd.NewTronKeysClient(client).ImportKey, set, "tron")

require.NoError(tt, set.Parse([]string{keyName}))
require.NoError(tt, set.Set("old-password", "../internal/fixtures/incorrect_password.txt"))
c = cli.NewContext(nil, set, nil)
require.NoError(t, cmd.NewTronKeysClient(client).ImportKey(c))

requireTronKeyCount(t, app, 1)
})
}

func requireTronKeyCount(t *testing.T, app chainlink.Application, length int) []tronkey.Key {
t.Helper()
keys, err := app.GetKeyStore().Tron().GetAll()
require.NoError(t, err)
require.Len(t, keys, length)
return keys
}
42 changes: 42 additions & 0 deletions core/cmd/tron_node_commands.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package cmd

import (
"github.com/smartcontractkit/chainlink/v2/core/web/presenters"
)

// TronNodePresenter implements TableRenderer for a TronNodeResource.
type TronNodePresenter struct {
presenters.TronNodeResource
}

// ToRow presents the TronNodeResource as a slice of strings.
func (p *TronNodePresenter) ToRow() []string {
return []string{p.Name, p.ChainID, p.State, p.Config}
}

// RenderTable implements TableRenderer
func (p TronNodePresenter) RenderTable(rt RendererTable) error {
rows := [][]string{p.ToRow()}
renderList(nodeHeaders, rows, rt.Writer)

return nil
}

// TronNodePresenters implements TableRenderer for a slice of TronNodePresenter.
type TronNodePresenters []TronNodePresenter

// RenderTable implements TableRenderer
func (ps TronNodePresenters) RenderTable(rt RendererTable) error {
rows := [][]string{}
for _, p := range ps {
rows = append(rows, p.ToRow())
}

renderList(nodeHeaders, rows, rt.Writer)

return nil
}

func NewTronNodeClient(s *Shell) NodeClient {
return newNodeClient[TronNodePresenters](s, "tron")
}
Loading

0 comments on commit 009507a

Please sign in to comment.