Skip to content

Commit 42dc440

Browse files
Fixes: Sui chain & ctf provider fixes (#292)
Co-authored-by: Graham Goh <[email protected]>
1 parent ed98d76 commit 42dc440

File tree

5 files changed

+94
-36
lines changed

5 files changed

+94
-36
lines changed

.changeset/calm-crews-unite.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"chainlink-deployments-framework": patch
3+
---
4+
5+
fixes for sui provider

chain/sui/provider/ctf_provider.go

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ import (
1010
"testing"
1111
"time"
1212

13+
"github.com/go-resty/resty/v2"
14+
1315
"github.com/avast/retry-go/v4"
16+
"github.com/block-vision/sui-go-sdk/models"
1417
sui_sdk "github.com/block-vision/sui-go-sdk/sui"
1518
chainsel "github.com/smartcontractkit/chain-selectors"
1619
"github.com/smartcontractkit/chainlink-testing-framework/framework"
@@ -108,16 +111,17 @@ func (p *CTFChainProvider) Initialize(_ context.Context) (chain.BlockChain, erro
108111
}
109112

110113
// Start the CTF Container
111-
url, client := p.startContainer(chainID, deployerSigner)
114+
url, faucetUrl, client := p.startContainer(chainID, deployerSigner)
112115

113116
// Construct the chain
114117
p.chain = &sui.Chain{
115118
ChainMetadata: sui.ChainMetadata{
116119
Selector: p.selector,
117120
},
118-
Client: client,
119-
Signer: deployerSigner,
120-
URL: url,
121+
Client: client,
122+
Signer: deployerSigner,
123+
URL: url,
124+
FaucetURL: faucetUrl,
121125
// TODO: Implement ConfirmTransaction when available
122126
}
123127

@@ -144,11 +148,11 @@ func (p *CTFChainProvider) BlockChain() chain.BlockChain {
144148
// It returns the URL of the Sui node and the client to interact with it.
145149
func (p *CTFChainProvider) startContainer(
146150
chainID string, account sui.SuiSigner,
147-
) (string, sui_sdk.ISuiAPI) {
151+
) (string, string, sui_sdk.ISuiAPI) {
148152
var (
149-
attempts = uint(10)
150-
url string
151-
containerName string
153+
attempts = uint(10)
154+
url string
155+
fauceturl string
152156
)
153157

154158
// initialize the docker network used by CTF
@@ -161,6 +165,7 @@ func (p *CTFChainProvider) startContainer(
161165

162166
type containerResult struct {
163167
url string
168+
faucetPort string
164169
containerName string
165170
}
166171

@@ -204,13 +209,15 @@ func (p *CTFChainProvider) startContainer(
204209
if rerr != nil {
205210
// Return the ports to freeport to avoid leaking them during retries
206211
freeport.Return([]int{port, faucetPort})
212+
207213
return containerResult{}, rerr
208214
}
209215

210216
testcontainers.CleanupContainer(p.t, output.Container)
211217

212218
return containerResult{
213-
url: output.Nodes[0].ExternalHTTPUrl + "/v1",
219+
url: output.Nodes[0].ExternalHTTPUrl,
220+
faucetPort: input.FaucetPort,
214221
containerName: output.ContainerName,
215222
}, nil
216223
},
@@ -225,7 +232,7 @@ func (p *CTFChainProvider) startContainer(
225232
require.NoError(p.t, err, "Failed to start CTF Sui container after %d attempts", attempts)
226233

227234
url = result.url
228-
containerName = result.containerName
235+
fauceturl = fmt.Sprintf("http://%s:%s", "127.0.0.1", result.faucetPort)
229236

230237
client := sui_sdk.NewSuiClient(url)
231238

@@ -240,14 +247,24 @@ func (p *CTFChainProvider) startContainer(
240247
}
241248
require.True(p.t, ready, "Sui network not ready")
242249

243-
dc, err := framework.NewDockerClient()
250+
err = fundAccount(fauceturl, address)
244251
require.NoError(p.t, err)
245252

246-
_, err = dc.ExecContainer(containerName, []string{
247-
"sui", "client", "faucet",
248-
"--address", address,
249-
})
250-
require.NoError(p.t, err)
253+
return url, fauceturl, client
254+
}
251255

252-
return url, client
256+
func fundAccount(url string, address string) error {
257+
r := resty.New().SetBaseURL(url)
258+
b := &models.FaucetRequest{
259+
FixedAmountRequest: &models.FaucetFixedAmountRequest{
260+
Recipient: address,
261+
},
262+
}
263+
resp, err := r.R().SetBody(b).SetHeader("Content-Type", "application/json").Post("/gas")
264+
if err != nil {
265+
return err
266+
}
267+
framework.L.Info().Any("Resp", resp).Msg("Address is funded!")
268+
269+
return nil
253270
}

chain/sui/signer.go

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
package sui
22

33
import (
4+
"crypto/ed25519"
45
"encoding/base64"
56
"encoding/hex"
6-
"errors"
77
"fmt"
88

9-
"github.com/block-vision/sui-go-sdk/constant"
109
"github.com/block-vision/sui-go-sdk/signer"
10+
"golang.org/x/crypto/blake2b"
1111
)
1212

1313
// TODO: Everything in this file should come from chainlink-sui when available
@@ -46,24 +46,58 @@ func NewSignerFromHexPrivateKey(hexPrivateKey string) (SuiSigner, error) {
4646
}
4747

4848
func (s *suiSigner) Sign(message []byte) ([]string, error) {
49-
if s.signer == nil {
50-
return nil, errors.New("signer is nil")
51-
}
49+
// Add intent scope for transaction data (0x00, 0x00, 0x00)
50+
intentMessage := append([]byte{0x00, 0x00, 0x00}, message...)
5251

53-
// Sign the message as a transaction message
54-
b64Message := base64.StdEncoding.EncodeToString(message)
55-
signedMsg, err := s.signer.SignMessage(b64Message, constant.TransactionDataIntentScope)
56-
if err != nil {
57-
return nil, fmt.Errorf("failed to sign message: %w", err)
58-
}
52+
// Hash the message with blake2b
53+
hash := blake2b.Sum256(intentMessage)
54+
55+
// Sign the hash
56+
signature := ed25519.Sign(s.signer.PriKey, hash[:])
57+
58+
// Get public key
59+
publicKey := s.signer.PriKey.Public().(ed25519.PublicKey)
60+
61+
// Create serialized signature: flag + signature + pubkey
62+
serializedSig := make([]byte, 1+len(signature)+len(publicKey))
63+
serializedSig[0] = 0x00 // Ed25519 flag
64+
copy(serializedSig[1:], signature)
65+
copy(serializedSig[1+len(signature):], publicKey)
66+
67+
// Encode to base64
68+
encoded := base64.StdEncoding.EncodeToString(serializedSig)
5969

60-
return []string{signedMsg.Signature}, nil
70+
return []string{encoded}, nil
6171
}
6272

6373
func (s *suiSigner) GetAddress() (string, error) {
64-
if s.signer == nil {
65-
return "", errors.New("signer is nil")
74+
publicKey := s.signer.PriKey.Public().(ed25519.PublicKey)
75+
76+
// For Ed25519, the signature scheme is 0x00
77+
const signatureScheme = 0x00
78+
79+
// Create the data to hash: signature scheme byte || public key
80+
data := append([]byte{signatureScheme}, publicKey...)
81+
82+
// Hash using Blake2b-256
83+
hash := blake2b.Sum256(data)
84+
85+
// The Sui address is the hex representation of the hash
86+
return "0x" + hex.EncodeToString(hash[:]), nil
87+
}
88+
89+
// PublicKeyBytes extracts the raw 32-byte ed25519 public key from a SuiSigner.
90+
func PublicKeyBytes(s SuiSigner) ([]byte, error) {
91+
impl, ok := s.(*suiSigner)
92+
if !ok {
93+
return nil, fmt.Errorf("unsupported signer type %T", s)
94+
}
95+
priv := []byte(impl.signer.PriKey)
96+
if len(priv) != ed25519.PrivateKeySize {
97+
return nil, fmt.Errorf("unexpected ed25519 key length: %d", len(priv))
6698
}
99+
pub := make([]byte, ed25519.PublicKeySize)
100+
copy(pub, priv[32:]) // last 32 bytes are the pubkey
67101

68-
return s.signer.Address, nil
102+
return pub, nil
69103
}

chain/sui/sui_chain.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ type ChainMetadata = common.ChainMetadata
1111
// Chain represents an Sui chain.
1212
type Chain struct {
1313
ChainMetadata
14-
Client sui.ISuiAPI
15-
Signer SuiSigner
16-
URL string
14+
Client sui.ISuiAPI
15+
Signer SuiSigner
16+
URL string
17+
FaucetURL string
18+
1719
// TODO: Implement ConfirmTransaction. Current tooling relies on node local execution
1820
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ require (
5151
github.com/xssnick/tonutils-go v1.13.0
5252
github.com/zksync-sdk/zksync2-go v1.1.1-0.20250620124214-2c742ee399c6
5353
go.uber.org/zap v1.27.0
54+
golang.org/x/crypto v0.40.0
5455
golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc
5556
golang.org/x/oauth2 v0.30.0
5657
google.golang.org/grpc v1.74.2
@@ -280,7 +281,6 @@ require (
280281
go.uber.org/atomic v1.11.0 // indirect
281282
go.uber.org/multierr v1.11.0 // indirect
282283
go.uber.org/ratelimit v0.3.1 // indirect
283-
golang.org/x/crypto v0.40.0 // indirect
284284
golang.org/x/net v0.42.0 // indirect
285285
golang.org/x/sync v0.16.0 // indirect
286286
golang.org/x/sys v0.34.0 // indirect

0 commit comments

Comments
 (0)