Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions .mockery.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,23 @@ packages:
interfaces:
AptosRpcClient:
TransactionSigner:
github.com/block-vision/sui-go-sdk/sui:
github.com/smartcontractkit/chainlink-sui/relayer/client:
config:
all: false
pkgname: "mocks"
dir: "chain/sui/mocks"
filename: "{{.InterfaceName | snakecase}}.go"
interfaces:
ISuiAPI:
BindingsClient:
SuiPTBClient:
github.com/smartcontractkit/chainlink-sui/bindings/utils:
config:
all: false
pkgname: "mocks"
dir: "chain/sui/mocks"
filename: "{{.InterfaceName | snakecase}}.go"
interfaces:
SuiSigner:
github.com/xssnick/tonutils-go/ton:
config:
all: false
Expand Down
5 changes: 3 additions & 2 deletions chain/mcms/adapters/chain_access.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package adapters

import (
aptoslib "github.com/aptos-labs/aptos-go-sdk"
"github.com/block-vision/sui-go-sdk/sui"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
sol "github.com/gagliardetto/solana-go"
solrpc "github.com/gagliardetto/solana-go/rpc"
Expand All @@ -13,6 +12,8 @@ import (
"github.com/xssnick/tonutils-go/ton"
tonwallet "github.com/xssnick/tonutils-go/ton/wallet"

cslclient "github.com/smartcontractkit/chainlink-sui/relayer/client"

"github.com/smartcontractkit/chainlink-deployments-framework/chain"
cldfaptos "github.com/smartcontractkit/chainlink-deployments-framework/chain/aptos"
cldfcanton "github.com/smartcontractkit/chainlink-deployments-framework/chain/canton"
Expand Down Expand Up @@ -101,7 +102,7 @@ func (a *ChainAccessAdapter) AptosSigner(selector uint64) (aptoslib.TransactionS
}

// SuiClient returns the Sui API client for the given selector.
func (a *ChainAccessAdapter) SuiClient(selector uint64) (sui.ISuiAPI, bool) {
func (a *ChainAccessAdapter) SuiClient(selector uint64) (cslclient.BindingsClient, bool) {
ch, ok := a.inner.SuiChains()[selector]
if !ok {
return nil, false
Expand Down
8 changes: 2 additions & 6 deletions chain/mcms/adapters/chain_access_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,6 @@ func TestChainAccess_UnknownSelector(t *testing.T) {
require.False(t, ok)
require.Nil(t, suiClient)

suiSigner, ok := a.SuiSigner(999)
require.False(t, ok)
require.Nil(t, suiSigner)

tonClient, ok := a.TonClient(999)
require.False(t, ok)
require.Nil(t, tonClient)
Expand Down Expand Up @@ -94,8 +90,8 @@ func TestChainAccess_SelectorsAndLookups(t *testing.T) {
aptosSigner := aptosmocks.NewMockTransactionSigner(t)
solClient := solrpc.New("http://example.invalid")
solSigner := &sol.PrivateKey{1, 2, 3}
suiClient := suimocks.NewMockISuiAPI(t)
suiSigner, _ := chainsui.NewSignerFromSeed(make([]byte, 32))
suiClient := suimocks.NewMockSuiPTBClient(t)
suiSigner := suimocks.NewMockSuiSigner(t)
tonClient := tonmocks.NewMockAPIClientWrapped(t)
tonSigner := &tonwallet.Wallet{}

Expand Down
58 changes: 58 additions & 0 deletions chain/sui/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package sui

import (
"fmt"
"net/url"
"strings"
"time"

"github.com/smartcontractkit/chainlink-common/pkg/logger"

cslclient "github.com/smartcontractkit/chainlink-sui/relayer/client"
)

const defaultGrpcToken = "test"

// NewPTBClientFromNodeURL creates a gRPC-backed Sui PTB client from an HTTP RPC URL.
func NewPTBClientFromNodeURL(log logger.Logger, nodeURL string, grpcToken string) (cslclient.SuiPTBClient, error) {
grpcTarget, err := grpcTargetFromNodeURL(nodeURL)
if err != nil {
return nil, err
}
if grpcToken == "" {
grpcToken = defaultGrpcToken
}
Comment thread
faisal-chainlink marked this conversation as resolved.
Comment thread
faisal-chainlink marked this conversation as resolved.

return cslclient.NewPTBClient(log, cslclient.PTBClientConfig{
GrpcTarget: grpcTarget,
GrpcToken: grpcToken,
TransactionTimeout: 30 * time.Second,
MaxConcurrentRequests: 50,
DefaultRequestType: cslclient.WaitForEffectsCert,
})
}

func grpcTargetFromNodeURL(nodeURL string) (string, error) {
u, err := url.Parse(nodeURL)
if err != nil {
return "", fmt.Errorf("parse node URL %q: %w", nodeURL, err)
}
host := u.Hostname()
port := u.Port()
if host == "" {
return "", fmt.Errorf("node URL %q has no host", nodeURL)
}
if port == "" {
switch u.Scheme {
case "https":
port = "443"
default:
port = "9000"
}
}
if strings.Contains(host, ":") && !strings.HasPrefix(host, "[") {
return fmt.Sprintf("[%s]:%s", host, port), nil
}

return fmt.Sprintf("%s:%s", host, port), nil
}
Comment thread
faisal-chainlink marked this conversation as resolved.
103 changes: 103 additions & 0 deletions chain/sui/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package sui

import (
"testing"

"github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

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

tests := []struct {
name string
nodeURL string
want string
wantErr string
}{
{
name: "host with explicit port",
nodeURL: "http://127.0.0.1:9000",
want: "127.0.0.1:9000",
},
{
name: "http scheme defaults to port 9000",
nodeURL: "http://example.com",
want: "example.com:9000",
},
{
name: "https scheme defaults to port 443",
nodeURL: "https://example.com",
want: "example.com:443",
},
{
name: "ipv6 host with port gets bracketed",
nodeURL: "http://[::1]:9000",
want: "[::1]:9000",
},
{
name: "ipv6 host without port gets bracketed and defaulted",
nodeURL: "http://[::1]",
want: "[::1]:9000",
},
{
name: "invalid URL returns error",
nodeURL: "http://\x7f",
wantErr: "parse node URL",
},
{
name: "missing host returns error",
nodeURL: "http:///path",
wantErr: "has no host",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()

got, err := grpcTargetFromNodeURL(tt.nodeURL)
if tt.wantErr != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tt.wantErr)

return
}
require.NoError(t, err)
assert.Equal(t, tt.want, got)
})
}
}

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

log, err := logger.New()
require.NoError(t, err)

t.Run("valid URL with empty token uses default", func(t *testing.T) {
t.Parallel()

client, err := NewPTBClientFromNodeURL(log, "http://127.0.0.1:9000", "")
require.NoError(t, err)
require.NotNil(t, client)
})

t.Run("valid URL with explicit token", func(t *testing.T) {
t.Parallel()

client, err := NewPTBClientFromNodeURL(log, "http://127.0.0.1:9000", "my-token")
require.NoError(t, err)
require.NotNil(t, client)
})

t.Run("invalid URL returns error", func(t *testing.T) {
t.Parallel()

client, err := NewPTBClientFromNodeURL(log, "http://\x7f", "")
require.Error(t, err)
require.Nil(t, client)
})
}
Loading
Loading