Skip to content

Commit aa4c5e6

Browse files
authored
feat: adds aptos chain providers (#123)
1 parent 641ec43 commit aa4c5e6

File tree

14 files changed

+1210
-22
lines changed

14 files changed

+1210
-22
lines changed

.changeset/four-pandas-rush.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+
Adds Aptos Chain providers for RPC and CTF backed chains

chain/aptos/aptos_chain.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package aptos
22

33
import (
4-
"github.com/aptos-labs/aptos-go-sdk"
4+
aptoslib "github.com/aptos-labs/aptos-go-sdk"
55

66
chain_common "github.com/smartcontractkit/chainlink-deployments-framework/chain/internal/common"
77
)
@@ -10,8 +10,8 @@ import (
1010
type Chain struct {
1111
Selector uint64
1212

13-
Client aptos.AptosRpcClient
14-
DeployerSigner aptos.TransactionSigner
13+
Client aptoslib.AptosRpcClient
14+
DeployerSigner aptoslib.TransactionSigner
1515
URL string
1616

1717
Confirm func(txHash string, opts ...any) error
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package provider
2+
3+
import (
4+
"crypto/ed25519"
5+
"encoding/hex"
6+
"fmt"
7+
"strings"
8+
9+
aptoslib "github.com/aptos-labs/aptos-go-sdk"
10+
"github.com/aptos-labs/aptos-go-sdk/crypto"
11+
"github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain"
12+
)
13+
14+
// AccountGenerator is an interface for generating Aptos accounts.
15+
type AccountGenerator interface {
16+
Generate() (*aptoslib.Account, error)
17+
}
18+
19+
var (
20+
_ AccountGenerator = (*accountGenCTFDefault)(nil)
21+
_ AccountGenerator = (*accountGenNewSingleSender)(nil)
22+
_ AccountGenerator = (*accountGenPrivateKey)(nil)
23+
)
24+
25+
// accountGenCTFDefault is a default account generator for CTF (Chainlink Testing Framework).
26+
type accountGenCTFDefault struct {
27+
// The account address string to use for generating the account.
28+
accountStr string
29+
// privateKeyStr is the private key string to use for generating the account.
30+
privateKeyStr string
31+
}
32+
33+
// AccountGenCTFDefault creates a new instance of accountGenCTFDefault. It uses the default
34+
// Aptos account and private key from the blockchain package.
35+
func AccountGenCTFDefault() *accountGenCTFDefault {
36+
return &accountGenCTFDefault{
37+
accountStr: blockchain.DefaultAptosAccount,
38+
privateKeyStr: blockchain.DefaultAptosPrivateKey,
39+
}
40+
}
41+
42+
// Generate generates an Aptos account using the default address and private key from the
43+
// blockchain package. It returns an error if the address or private key is invalid.
44+
func (g *accountGenCTFDefault) Generate() (*aptoslib.Account, error) {
45+
var address aptoslib.AccountAddress
46+
47+
if err := address.ParseStringRelaxed(g.accountStr); err != nil {
48+
return nil, fmt.Errorf("failed to parse account address %s: %w", g.accountStr, err)
49+
}
50+
51+
privateKeyBytes, err := hex.DecodeString(strings.TrimPrefix(g.privateKeyStr, "0x"))
52+
if err != nil {
53+
return nil, fmt.Errorf("failed to decode private key: %w", err)
54+
}
55+
privateKey := ed25519.NewKeyFromSeed(privateKeyBytes)
56+
57+
return aptoslib.NewAccountFromSigner(&crypto.Ed25519PrivateKey{Inner: privateKey}, address)
58+
}
59+
60+
// accountGenNewSingleSender is an account generator that creates a new single sender account.
61+
type accountGenNewSingleSender struct{}
62+
63+
// AccountGenNewSingleSender creates a new instance of accountGenNewSingleSender.
64+
func AccountGenNewSingleSender() *accountGenNewSingleSender {
65+
return &accountGenNewSingleSender{}
66+
}
67+
68+
// Generate generates a new Aptos account using the aptos library's single sender account creation
69+
// method.
70+
func (g *accountGenNewSingleSender) Generate() (*aptoslib.Account, error) {
71+
return aptoslib.NewEd25519SingleSenderAccount()
72+
}
73+
74+
// accountGenPrivateKey is an account generator that creates an account from the private key.
75+
type accountGenPrivateKey struct {
76+
// PrivateKey is the hex formatted private key used to generate the Aptos account.
77+
PrivateKey string
78+
}
79+
80+
// AccountGenPrivateKey creates a new instance of accountGenPrivateKey with the provided private key.
81+
func AccountGenPrivateKey(privateKey string) *accountGenPrivateKey {
82+
return &accountGenPrivateKey{
83+
PrivateKey: privateKey,
84+
}
85+
}
86+
87+
// Generate generates an Aptos account from the provided private key. It returns an error if the
88+
// private key string cannot be parsed.
89+
func (g *accountGenPrivateKey) Generate() (*aptoslib.Account, error) {
90+
privateKey := &crypto.Ed25519PrivateKey{}
91+
if err := privateKey.FromHex(g.PrivateKey); err != nil {
92+
return nil, fmt.Errorf("failed to parse private key: %w", err)
93+
}
94+
95+
return aptoslib.NewAccountFromSigner(privateKey)
96+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package provider
2+
3+
import (
4+
"testing"
5+
6+
"github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain"
7+
"github.com/stretchr/testify/assert"
8+
"github.com/stretchr/testify/require"
9+
)
10+
11+
func Test_AccountGenCtfDefault(t *testing.T) {
12+
t.Parallel()
13+
14+
tests := []struct {
15+
name string
16+
giveAccountAddr string
17+
givePrivateKey string
18+
wantErr string
19+
}{
20+
{
21+
name: "valid default account and private key",
22+
},
23+
{
24+
name: "invalid account address",
25+
giveAccountAddr: "invalid_address",
26+
givePrivateKey: blockchain.DefaultAptosPrivateKey,
27+
wantErr: "failed to parse account address",
28+
},
29+
{
30+
name: "invalid private key",
31+
giveAccountAddr: blockchain.DefaultAptosAccount,
32+
givePrivateKey: "invalid_private_key",
33+
wantErr: "failed to decode private key",
34+
},
35+
}
36+
37+
for _, tt := range tests {
38+
t.Run(tt.name, func(t *testing.T) {
39+
t.Parallel()
40+
41+
var gen *accountGenCTFDefault
42+
if tt.giveAccountAddr == "" && tt.givePrivateKey == "" {
43+
gen = AccountGenCTFDefault() // Use the constructor with default values if we don't need to override
44+
} else {
45+
gen = &accountGenCTFDefault{
46+
accountStr: tt.giveAccountAddr,
47+
privateKeyStr: tt.givePrivateKey,
48+
}
49+
}
50+
51+
got, err := gen.Generate()
52+
if tt.wantErr != "" {
53+
require.Error(t, err)
54+
require.ErrorContains(t, err, tt.wantErr)
55+
} else {
56+
require.NoError(t, err)
57+
assert.Equal(t, blockchain.DefaultAptosAccount, got.Address.String())
58+
}
59+
})
60+
}
61+
}
62+
63+
func Test_AccountGenNewSingleSender(t *testing.T) {
64+
t.Parallel()
65+
66+
gen := AccountGenNewSingleSender()
67+
got, err := gen.Generate()
68+
require.NoError(t, err)
69+
assert.NotNil(t, got)
70+
}
71+
72+
func Test_AccountGenPrivateKey(t *testing.T) {
73+
t.Parallel()
74+
75+
tests := []struct {
76+
name string
77+
givePrivateKey string
78+
wantAddr string
79+
wantErr string
80+
}{
81+
{
82+
name: "valid private key",
83+
givePrivateKey: testPrivateKey,
84+
wantAddr: testAccountAddr,
85+
},
86+
{
87+
name: "invalid private key",
88+
givePrivateKey: "invalid_private_key",
89+
wantErr: "failed to parse private key",
90+
},
91+
}
92+
93+
for _, tt := range tests {
94+
t.Run(tt.name, func(t *testing.T) {
95+
t.Parallel()
96+
97+
gen := AccountGenPrivateKey(tt.givePrivateKey)
98+
account, err := gen.Generate()
99+
if tt.wantErr != "" {
100+
require.Error(t, err)
101+
require.ErrorContains(t, err, tt.wantErr)
102+
} else {
103+
require.NoError(t, err)
104+
assert.NotNil(t, account)
105+
assert.Equal(t, tt.wantAddr, account.Address.String())
106+
}
107+
})
108+
}
109+
}

chain/aptos/provider/const_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package provider
2+
3+
const (
4+
// A valid Aptos private key in hex format
5+
testPrivateKey = "0xE4FD0E90D32CB98DC6AD64516A421E8C2731870217CDBA64203CEB158A866304"
6+
7+
// The expected account address for above private key
8+
testAccountAddr = "0x9b7a7333d1abd0e9c2a27d00a8a7a131d30d3b09908739d52693fe513e205c38"
9+
)

0 commit comments

Comments
 (0)