Skip to content

Commit e31c0ae

Browse files
[Chore] Sui gRPC client migration (#1028)
This PR includes the following changes: * Updates the Sui SDK references to correspond to the gRPC migration changes in chainlink-sui. This primarily includes dropping the `ISuiAPI` reference (old version of the Sui SDK) in favor of using a client interface exported by `chainlink-sui/relayer/client`. * Update the mocked interface for Sui in this repo. * General lint and deps version bumps (e.g., MCMS dep). --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent 0aed0b2 commit e31c0ae

16 files changed

Lines changed: 3274 additions & 3895 deletions

.mockery.yml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,23 @@ packages:
140140
interfaces:
141141
AptosRpcClient:
142142
TransactionSigner:
143-
github.com/block-vision/sui-go-sdk/sui:
143+
github.com/smartcontractkit/chainlink-sui/relayer/client:
144144
config:
145145
all: false
146146
pkgname: "mocks"
147147
dir: "chain/sui/mocks"
148148
filename: "{{.InterfaceName | snakecase}}.go"
149149
interfaces:
150-
ISuiAPI:
150+
BindingsClient:
151+
SuiPTBClient:
152+
github.com/smartcontractkit/chainlink-sui/bindings/utils:
153+
config:
154+
all: false
155+
pkgname: "mocks"
156+
dir: "chain/sui/mocks"
157+
filename: "{{.InterfaceName | snakecase}}.go"
158+
interfaces:
159+
SuiSigner:
151160
github.com/xssnick/tonutils-go/ton:
152161
config:
153162
all: false

chain/mcms/adapters/chain_access.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package adapters
22

33
import (
44
aptoslib "github.com/aptos-labs/aptos-go-sdk"
5-
"github.com/block-vision/sui-go-sdk/sui"
65
"github.com/ethereum/go-ethereum/accounts/abi/bind"
76
sol "github.com/gagliardetto/solana-go"
87
solrpc "github.com/gagliardetto/solana-go/rpc"
@@ -13,6 +12,8 @@ import (
1312
"github.com/xssnick/tonutils-go/ton"
1413
tonwallet "github.com/xssnick/tonutils-go/ton/wallet"
1514

15+
cslclient "github.com/smartcontractkit/chainlink-sui/relayer/client"
16+
1617
"github.com/smartcontractkit/chainlink-deployments-framework/chain"
1718
cldfaptos "github.com/smartcontractkit/chainlink-deployments-framework/chain/aptos"
1819
cldfcanton "github.com/smartcontractkit/chainlink-deployments-framework/chain/canton"
@@ -101,7 +102,7 @@ func (a *ChainAccessAdapter) AptosSigner(selector uint64) (aptoslib.TransactionS
101102
}
102103

103104
// SuiClient returns the Sui API client for the given selector.
104-
func (a *ChainAccessAdapter) SuiClient(selector uint64) (sui.ISuiAPI, bool) {
105+
func (a *ChainAccessAdapter) SuiClient(selector uint64) (cslclient.BindingsClient, bool) {
105106
ch, ok := a.inner.SuiChains()[selector]
106107
if !ok {
107108
return nil, false

chain/mcms/adapters/chain_access_test.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,6 @@ func TestChainAccess_UnknownSelector(t *testing.T) {
5858
require.False(t, ok)
5959
require.Nil(t, suiClient)
6060

61-
suiSigner, ok := a.SuiSigner(999)
62-
require.False(t, ok)
63-
require.Nil(t, suiSigner)
64-
6561
tonClient, ok := a.TonClient(999)
6662
require.False(t, ok)
6763
require.Nil(t, tonClient)
@@ -94,8 +90,8 @@ func TestChainAccess_SelectorsAndLookups(t *testing.T) {
9490
aptosSigner := aptosmocks.NewMockTransactionSigner(t)
9591
solClient := solrpc.New("http://example.invalid")
9692
solSigner := &sol.PrivateKey{1, 2, 3}
97-
suiClient := suimocks.NewMockISuiAPI(t)
98-
suiSigner, _ := chainsui.NewSignerFromSeed(make([]byte, 32))
93+
suiClient := suimocks.NewMockSuiPTBClient(t)
94+
suiSigner := suimocks.NewMockSuiSigner(t)
9995
tonClient := tonmocks.NewMockAPIClientWrapped(t)
10096
tonSigner := &tonwallet.Wallet{}
10197

chain/sui/client.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package sui
2+
3+
import (
4+
"fmt"
5+
"net/url"
6+
"strings"
7+
"time"
8+
9+
"github.com/smartcontractkit/chainlink-common/pkg/logger"
10+
11+
cslclient "github.com/smartcontractkit/chainlink-sui/relayer/client"
12+
)
13+
14+
const defaultGrpcToken = "test"
15+
16+
// NewPTBClientFromNodeURL creates a gRPC-backed Sui PTB client from an HTTP RPC URL.
17+
func NewPTBClientFromNodeURL(log logger.Logger, nodeURL string, grpcToken string) (cslclient.SuiPTBClient, error) {
18+
grpcTarget, err := grpcTargetFromNodeURL(nodeURL)
19+
if err != nil {
20+
return nil, err
21+
}
22+
if grpcToken == "" {
23+
grpcToken = defaultGrpcToken
24+
}
25+
26+
return cslclient.NewPTBClient(log, cslclient.PTBClientConfig{
27+
GrpcTarget: grpcTarget,
28+
GrpcToken: grpcToken,
29+
TransactionTimeout: 30 * time.Second,
30+
MaxConcurrentRequests: 50,
31+
DefaultRequestType: cslclient.WaitForEffectsCert,
32+
})
33+
}
34+
35+
func grpcTargetFromNodeURL(nodeURL string) (string, error) {
36+
u, err := url.Parse(nodeURL)
37+
if err != nil {
38+
return "", fmt.Errorf("parse node URL %q: %w", nodeURL, err)
39+
}
40+
host := u.Hostname()
41+
port := u.Port()
42+
if host == "" {
43+
return "", fmt.Errorf("node URL %q has no host", nodeURL)
44+
}
45+
if port == "" {
46+
switch u.Scheme {
47+
case "https":
48+
port = "443"
49+
default:
50+
port = "9000"
51+
}
52+
}
53+
if strings.Contains(host, ":") && !strings.HasPrefix(host, "[") {
54+
return fmt.Sprintf("[%s]:%s", host, port), nil
55+
}
56+
57+
return fmt.Sprintf("%s:%s", host, port), nil
58+
}

chain/sui/client_test.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package sui
2+
3+
import (
4+
"testing"
5+
6+
"github.com/smartcontractkit/chainlink-common/pkg/logger"
7+
"github.com/stretchr/testify/assert"
8+
"github.com/stretchr/testify/require"
9+
)
10+
11+
func TestGrpcTargetFromNodeURL(t *testing.T) {
12+
t.Parallel()
13+
14+
tests := []struct {
15+
name string
16+
nodeURL string
17+
want string
18+
wantErr string
19+
}{
20+
{
21+
name: "host with explicit port",
22+
nodeURL: "http://127.0.0.1:9000",
23+
want: "127.0.0.1:9000",
24+
},
25+
{
26+
name: "http scheme defaults to port 9000",
27+
nodeURL: "http://example.com",
28+
want: "example.com:9000",
29+
},
30+
{
31+
name: "https scheme defaults to port 443",
32+
nodeURL: "https://example.com",
33+
want: "example.com:443",
34+
},
35+
{
36+
name: "ipv6 host with port gets bracketed",
37+
nodeURL: "http://[::1]:9000",
38+
want: "[::1]:9000",
39+
},
40+
{
41+
name: "ipv6 host without port gets bracketed and defaulted",
42+
nodeURL: "http://[::1]",
43+
want: "[::1]:9000",
44+
},
45+
{
46+
name: "invalid URL returns error",
47+
nodeURL: "http://\x7f",
48+
wantErr: "parse node URL",
49+
},
50+
{
51+
name: "missing host returns error",
52+
nodeURL: "http:///path",
53+
wantErr: "has no host",
54+
},
55+
}
56+
57+
for _, tt := range tests {
58+
t.Run(tt.name, func(t *testing.T) {
59+
t.Parallel()
60+
61+
got, err := grpcTargetFromNodeURL(tt.nodeURL)
62+
if tt.wantErr != "" {
63+
require.Error(t, err)
64+
assert.Contains(t, err.Error(), tt.wantErr)
65+
66+
return
67+
}
68+
require.NoError(t, err)
69+
assert.Equal(t, tt.want, got)
70+
})
71+
}
72+
}
73+
74+
func TestNewPTBClientFromNodeURL(t *testing.T) {
75+
t.Parallel()
76+
77+
log, err := logger.New()
78+
require.NoError(t, err)
79+
80+
t.Run("valid URL with empty token uses default", func(t *testing.T) {
81+
t.Parallel()
82+
83+
client, err := NewPTBClientFromNodeURL(log, "http://127.0.0.1:9000", "")
84+
require.NoError(t, err)
85+
require.NotNil(t, client)
86+
})
87+
88+
t.Run("valid URL with explicit token", func(t *testing.T) {
89+
t.Parallel()
90+
91+
client, err := NewPTBClientFromNodeURL(log, "http://127.0.0.1:9000", "my-token")
92+
require.NoError(t, err)
93+
require.NotNil(t, client)
94+
})
95+
96+
t.Run("invalid URL returns error", func(t *testing.T) {
97+
t.Parallel()
98+
99+
client, err := NewPTBClientFromNodeURL(log, "http://\x7f", "")
100+
require.Error(t, err)
101+
require.Nil(t, client)
102+
})
103+
}

0 commit comments

Comments
 (0)