Skip to content
Draft
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
16 changes: 14 additions & 2 deletions chainwrappers/chainaccessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,28 @@ package chainwrappers
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"
cldfcanton "github.com/smartcontractkit/chainlink-deployments-framework/chain/canton"
"github.com/xssnick/tonutils-go/ton"
tonwallet "github.com/xssnick/tonutils-go/ton/wallet"

evmsdk "github.com/smartcontractkit/mcms/sdk/evm"
suisuisdk "github.com/smartcontractkit/mcms/sdk/sui"
suisdk "github.com/smartcontractkit/mcms/sdk/sui"
)

type ChainAccessor interface {
Selectors() []uint64
EVMClient(selector uint64) (evmsdk.ContractDeployBackend, bool)
EVMSigner(selector uint64) (*bind.TransactOpts, bool)
SolanaClient(selector uint64) (*solrpc.Client, bool)
SolanaSigner(selector uint64) (*sol.PrivateKey, bool)
AptosClient(selector uint64) (aptoslib.AptosRpcClient, bool)
SuiClient(selector uint64) (sui.ISuiAPI, suisuisdk.SuiSigner, bool)
AptosSigner(selector uint64) (aptoslib.TransactionSigner, bool)
SuiClient(selector uint64) (sui.ISuiAPI, bool)
SuiSigner(selector uint64) (suisdk.SuiSigner, bool)
TonClient(selector uint64) (ton.APIClientWrapped, bool)
TonSigner(selector uint64) (*tonwallet.Wallet, bool)
CantonChain(selector uint64) (cldfcanton.Chain, bool)
}
3 changes: 3 additions & 0 deletions chainwrappers/converters.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/smartcontractkit/mcms/sdk"
"github.com/smartcontractkit/mcms/sdk/aptos"
"github.com/smartcontractkit/mcms/sdk/canton"
"github.com/smartcontractkit/mcms/sdk/evm"
"github.com/smartcontractkit/mcms/sdk/solana"
"github.com/smartcontractkit/mcms/types"
Expand All @@ -29,6 +30,8 @@ func BuildConverters(chainMetadata map[types.ChainSelector]types.ChainMetadata)
converter = solana.NewTimelockConverter()
case chainsel.FamilyAptos:
converter = aptos.NewTimelockConverter()
case chainsel.FamilyCanton:
converter = canton.NewTimelockConverter()
default:
return nil, fmt.Errorf("unsupported chain family %s", fam)
}
Expand Down
150 changes: 150 additions & 0 deletions chainwrappers/executors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package chainwrappers

import (
"fmt"

chainsel "github.com/smartcontractkit/chain-selectors"
mcmsencoder "github.com/smartcontractkit/chainlink-sui/bindings"

"github.com/smartcontractkit/mcms/sdk"
aptossdk "github.com/smartcontractkit/mcms/sdk/aptos"
cantonsdk "github.com/smartcontractkit/mcms/sdk/canton"
evmsdk "github.com/smartcontractkit/mcms/sdk/evm"
solanasdk "github.com/smartcontractkit/mcms/sdk/solana"
suisdk "github.com/smartcontractkit/mcms/sdk/sui"
tonsdk "github.com/smartcontractkit/mcms/sdk/ton"
"github.com/smartcontractkit/mcms/types"
)

func BuildExecutors(
chains ChainAccessor,
chainMetadata map[types.ChainSelector]types.ChainMetadata,
encoders map[types.ChainSelector]sdk.Encoder,
action types.TimelockAction,
) (map[types.ChainSelector]sdk.Executor, error) {
executors := map[types.ChainSelector]sdk.Executor{}
for chainSelector, metadata := range chainMetadata {
encoder, ok := encoders[chainSelector]
if !ok {
return nil, fmt.Errorf("missing encoder for chain selector %d", chainSelector)
}
executor, err := BuildExecutor(chains, chainSelector, encoder, action, metadata)
if err != nil {
return nil, err
}
executors[chainSelector] = executor
}
return executors, nil
}

func BuildExecutor(
chains ChainAccessor,
selector types.ChainSelector,
encoder sdk.Encoder,
action types.TimelockAction,
metadata types.ChainMetadata,
) (sdk.Executor, error) {
if chains == nil {
return nil, fmt.Errorf("chain access is required")
}
family, err := types.GetChainSelectorFamily(selector)
if err != nil {
return nil, fmt.Errorf("error getting chain family: %w", err)
}
rawSelector := uint64(selector)
switch family {
case chainsel.FamilyCanton:
cantonEncoder, ok := encoder.(*cantonsdk.Encoder)
if !ok {
return nil, fmt.Errorf("invalid canton encoder type for selector %d: %T", selector, encoder)
}
ch, ok := chains.CantonChain(rawSelector)
if !ok || len(ch.Participants) == 0 {
return nil, fmt.Errorf("missing Canton chain participant for selector %d", rawSelector)
}
participant := ch.Participants[0]
inspector := cantonsdk.NewInspector(participant.LedgerServices.State, participant.PartyID, cantonRole(action))
return cantonsdk.NewExecutor(cantonEncoder, inspector, participant.LedgerServices.Command, participant.UserID, participant.PartyID, cantonRole(action))
case chainsel.FamilyEVM:
evmEncoder, ok := encoder.(*evmsdk.Encoder)
if !ok {
return nil, fmt.Errorf("invalid EVM encoder type for selector %d: %T", selector, encoder)
}
client, ok := chains.EVMClient(rawSelector)
if !ok {
return nil, fmt.Errorf("missing EVM chain client for selector %d", rawSelector)
}
auth, ok := chains.EVMSigner(rawSelector)
if !ok {
return nil, fmt.Errorf("missing EVM signer for selector %d", rawSelector)
}
return evmsdk.NewExecutor(evmEncoder, client, auth), nil
case chainsel.FamilySolana:
solanaEncoder, ok := encoder.(*solanasdk.Encoder)
if !ok {
return nil, fmt.Errorf("invalid Solana encoder type for selector %d: %T", selector, encoder)
}
client, ok := chains.SolanaClient(rawSelector)
if !ok {
return nil, fmt.Errorf("missing Solana chain client for selector %d", rawSelector)
}
signer, ok := chains.SolanaSigner(rawSelector)
if !ok {
return nil, fmt.Errorf("missing Solana signer for selector %d", rawSelector)
}
return solanasdk.NewExecutor(solanaEncoder, client, *signer), nil
case chainsel.FamilyAptos:
aptosEncoder, ok := encoder.(*aptossdk.Encoder)
if !ok {
return nil, fmt.Errorf("invalid Aptos encoder type for selector %d: %T", selector, encoder)
}
client, ok := chains.AptosClient(rawSelector)
if !ok {
return nil, fmt.Errorf("missing Aptos chain client for selector %d", rawSelector)
}
signer, ok := chains.AptosSigner(rawSelector)
if !ok {
return nil, fmt.Errorf("missing Aptos signer for selector %d", rawSelector)
}
role, err := aptossdk.AptosRoleFromAction(action)
if err != nil {
return nil, fmt.Errorf("error determining aptos role: %w", err)
}
return aptossdk.NewExecutor(client, signer, aptosEncoder, role), nil
case chainsel.FamilySui:
suiEncoder, ok := encoder.(*suisdk.Encoder)
if !ok {
return nil, fmt.Errorf("invalid Sui encoder type for selector %d: %T", selector, encoder)
}
client, ok := chains.SuiClient(rawSelector)
if !ok {
return nil, fmt.Errorf("missing Sui chain client for selector %d", rawSelector)
}
signer, ok := chains.SuiSigner(rawSelector)
if !ok {
return nil, fmt.Errorf("missing Sui signer for selector %d", rawSelector)
}
suiMetadata, err := suisdk.SuiMetadata(metadata)
if err != nil {
return nil, fmt.Errorf("error parsing sui metadata: %w", err)
}
entrypointEncoder := mcmsencoder.NewCCIPEntrypointArgEncoder(suiMetadata.RegistryObj, suiMetadata.DeployerStateObj)
return suisdk.NewExecutor(client, signer, suiEncoder, entrypointEncoder, suiMetadata.McmsPackageID, suiMetadata.Role, metadata.MCMAddress, suiMetadata.AccountObj, suiMetadata.RegistryObj, suiMetadata.TimelockObj)
case chainsel.FamilyTon:
tonEncoder, ok := encoder.(*tonsdk.Encoder)
if !ok {
return nil, fmt.Errorf("invalid TON encoder type for selector %d: %T", selector, encoder)
}
client, ok := chains.TonClient(rawSelector)
if !ok {
return nil, fmt.Errorf("missing TON chain client for selector %d", rawSelector)
}
wallet, ok := chains.TonSigner(rawSelector)
if !ok {
return nil, fmt.Errorf("missing TON signer for selector %d", rawSelector)
}
return tonsdk.NewExecutor(tonsdk.ExecutorOpts{Encoder: tonEncoder, Client: client, Wallet: wallet, Amount: tonsdk.DefaultSendAmount})
default:
return nil, fmt.Errorf("unsupported chain family %s", family)
}
}
25 changes: 24 additions & 1 deletion chainwrappers/inspectors.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/smartcontractkit/mcms/sdk"
"github.com/smartcontractkit/mcms/sdk/aptos"
cantonsdk "github.com/smartcontractkit/mcms/sdk/canton"
"github.com/smartcontractkit/mcms/sdk/evm"
"github.com/smartcontractkit/mcms/sdk/solana"
sdkSui "github.com/smartcontractkit/mcms/sdk/sui"
Expand Down Expand Up @@ -48,6 +49,13 @@ func BuildInspector(

rawSelector := uint64(selector)
switch family {
case chainsel.FamilyCanton:
ch, ok := chains.CantonChain(rawSelector)
if !ok || len(ch.Participants) == 0 {
return nil, fmt.Errorf("missing Canton chain participant for selector %d", rawSelector)
}
participant := ch.Participants[0]
return cantonsdk.NewInspector(participant.LedgerServices.State, participant.PartyID, cantonRole(action)), nil
case chainsel.FamilyEVM:
client, ok := chains.EVMClient(rawSelector)
if !ok {
Expand All @@ -74,10 +82,14 @@ func BuildInspector(

return aptos.NewInspector(client, role), nil
case chainsel.FamilySui:
client, signer, ok := chains.SuiClient(rawSelector)
client, ok := chains.SuiClient(rawSelector)
if !ok {
return nil, fmt.Errorf("missing Sui chain client for selector %d", rawSelector)
}
signer, ok := chains.SuiSigner(rawSelector)
if !ok {
return nil, fmt.Errorf("missing Sui signer for selector %d", rawSelector)
}
suiMetadata, err := sdkSui.SuiMetadata(metadata)
if err != nil {
return nil, fmt.Errorf("error parsing sui metadata: %w", err)
Expand All @@ -88,3 +100,14 @@ func BuildInspector(
return nil, fmt.Errorf("unsupported chain family %s", family)
}
}

func cantonRole(action types.TimelockAction) cantonsdk.TimelockRole {
switch action {
case types.TimelockActionBypass:
return cantonsdk.TimelockRoleBypasser
case types.TimelockActionCancel:
return cantonsdk.TimelockRoleCanceller
default:
return cantonsdk.TimelockRoleProposer
}
}
116 changes: 116 additions & 0 deletions chainwrappers/timelock_executors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package chainwrappers

import (
"fmt"

chainsel "github.com/smartcontractkit/chain-selectors"
mcmsencoder "github.com/smartcontractkit/chainlink-sui/bindings"

"github.com/smartcontractkit/mcms/sdk"
aptossdk "github.com/smartcontractkit/mcms/sdk/aptos"
cantonsdk "github.com/smartcontractkit/mcms/sdk/canton"
evmsdk "github.com/smartcontractkit/mcms/sdk/evm"
solanasdk "github.com/smartcontractkit/mcms/sdk/solana"
suisdk "github.com/smartcontractkit/mcms/sdk/sui"
tonsdk "github.com/smartcontractkit/mcms/sdk/ton"
"github.com/smartcontractkit/mcms/types"
)

func BuildTimelockExecutors(
chains ChainAccessor,
chainMetadata map[types.ChainSelector]types.ChainMetadata,
action types.TimelockAction,
) (map[types.ChainSelector]sdk.TimelockExecutor, error) {
executors := map[types.ChainSelector]sdk.TimelockExecutor{}
for chainSelector, metadata := range chainMetadata {
executor, err := BuildTimelockExecutor(chains, chainSelector, action, metadata)
if err != nil {
return nil, err
}
executors[chainSelector] = executor
}
return executors, nil
}

func BuildTimelockExecutor(
chains ChainAccessor,
selector types.ChainSelector,
action types.TimelockAction,
metadata types.ChainMetadata,
) (sdk.TimelockExecutor, error) {
if chains == nil {
return nil, fmt.Errorf("chain access is required")
}
_ = action
family, err := types.GetChainSelectorFamily(selector)
if err != nil {
return nil, fmt.Errorf("error getting chain family: %w", err)
}
rawSelector := uint64(selector)
switch family {
case chainsel.FamilyCanton:
ch, ok := chains.CantonChain(rawSelector)
if !ok || len(ch.Participants) == 0 {
return nil, fmt.Errorf("missing Canton chain participant for selector %d", rawSelector)
}
participant := ch.Participants[0]
return cantonsdk.NewTimelockExecutor(participant.LedgerServices.Command, participant.LedgerServices.State, participant.PartyID), nil
case chainsel.FamilyEVM:
client, ok := chains.EVMClient(rawSelector)
if !ok {
return nil, fmt.Errorf("missing EVM chain client for selector %d", rawSelector)
}
auth, ok := chains.EVMSigner(rawSelector)
if !ok {
return nil, fmt.Errorf("missing EVM signer for selector %d", rawSelector)
}
return evmsdk.NewTimelockExecutor(client, auth), nil
case chainsel.FamilySolana:
client, ok := chains.SolanaClient(rawSelector)
if !ok {
return nil, fmt.Errorf("missing Solana chain client for selector %d", rawSelector)
}
signer, ok := chains.SolanaSigner(rawSelector)
if !ok {
return nil, fmt.Errorf("missing Solana signer for selector %d", rawSelector)
}
return solanasdk.NewTimelockExecutor(client, *signer), nil
case chainsel.FamilyAptos:
client, ok := chains.AptosClient(rawSelector)
if !ok {
return nil, fmt.Errorf("missing Aptos chain client for selector %d", rawSelector)
}
signer, ok := chains.AptosSigner(rawSelector)
if !ok {
return nil, fmt.Errorf("missing Aptos signer for selector %d", rawSelector)
}
return aptossdk.NewTimelockExecutor(client, signer), nil
case chainsel.FamilySui:
client, ok := chains.SuiClient(rawSelector)
if !ok {
return nil, fmt.Errorf("missing Sui chain client for selector %d", rawSelector)
}
signer, ok := chains.SuiSigner(rawSelector)
if !ok {
return nil, fmt.Errorf("missing Sui signer for selector %d", rawSelector)
}
suiMetadata, err := suisdk.SuiMetadata(metadata)
if err != nil {
return nil, fmt.Errorf("error parsing sui metadata: %w", err)
}
entrypointEncoder := mcmsencoder.NewCCIPEntrypointArgEncoder(suiMetadata.RegistryObj, suiMetadata.DeployerStateObj)
return suisdk.NewTimelockExecutor(client, signer, entrypointEncoder, suiMetadata.McmsPackageID, suiMetadata.RegistryObj, suiMetadata.AccountObj)
case chainsel.FamilyTon:
client, ok := chains.TonClient(rawSelector)
if !ok {
return nil, fmt.Errorf("missing TON chain client for selector %d", rawSelector)
}
wallet, ok := chains.TonSigner(rawSelector)
if !ok {
return nil, fmt.Errorf("missing TON signer for selector %d", rawSelector)
}
return tonsdk.NewTimelockExecutor(tonsdk.TimelockExecutorOpts{Client: client, Wallet: wallet, Amount: tonsdk.DefaultSendAmount})
default:
return nil, fmt.Errorf("unsupported chain family %s", family)
}
}
10 changes: 10 additions & 0 deletions e2e/config.canton.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[settings]
private_keys = [
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
"0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d",
"0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a"
]

[canton_config]
type = "canton"
number_of_canton_validators = 1
Loading
Loading