-
Notifications
You must be signed in to change notification settings - Fork 2
Extend cldf timelock converter logic for TON #628
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
3261478
ce292f9
76f7941
6b03e06
bb6622b
564f880
fa6aa6c
580e5c7
d139579
e0493eb
8c9b9ff
b703c08
a68db89
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,7 +13,6 @@ import ( | |
| "github.com/avast/retry-go/v4" | ||
| "github.com/testcontainers/testcontainers-go" | ||
|
|
||
| "github.com/xssnick/tonutils-go/address" | ||
| "github.com/xssnick/tonutils-go/tlb" | ||
| "github.com/xssnick/tonutils-go/ton" | ||
| "github.com/xssnick/tonutils-go/ton/wallet" | ||
|
|
@@ -34,6 +33,9 @@ const ( | |
|
|
||
| // supportedTONImageRepository is the only supported Docker image repository for TON localnet. | ||
| supportedTONImageRepository = "ghcr.io/neodix42/mylocalton-docker" | ||
|
|
||
| // defaultTxTONAmount is the default amount of TON to use for transactions. | ||
| defaultTxTONAmount = "0.1" | ||
| ) | ||
|
|
||
| // CTFChainProviderConfig holds the configuration to initialize the CTFChainProvider. | ||
|
|
@@ -122,18 +124,15 @@ func (p *CTFChainProvider) Initialize(ctx context.Context) (chain.BlockChain, er | |
| return nil, fmt.Errorf("failed to create wallet: %w", err) | ||
| } | ||
|
|
||
| // airdrop the deployer wallet | ||
| ferr := fundTonWallets(ctx, nodeClient, []*address.Address{tonWallet.Address()}, []tlb.Coins{tlb.MustFromTON("1000")}) | ||
| if ferr != nil { | ||
| return nil, fmt.Errorf("failed to fund wallet: %w", ferr) | ||
| } | ||
|
|
||
| p.chain = &cldf_ton.Chain{ | ||
| ChainMetadata: cldf_ton.ChainMetadata{Selector: p.selector}, | ||
| Client: nodeClient, | ||
| Wallet: tonWallet, | ||
| WalletAddress: tonWallet.Address(), | ||
| WalletAddress: tonWallet.WalletAddress(), | ||
|
||
| URL: url, | ||
| TxOps: cldf_ton.TxOps{ | ||
| Wallet: tonWallet, | ||
| Amount: tlb.MustFromTON(defaultTxTONAmount), // default amount for transactions | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good for now, too simple to scale - we need to track this item. We will need to be able to load gas configuration (from somewhere) which will need to tell us how much on average something costs to do (per contract call), and something a CLD user should be able to easily override. cc @patricios-space @vicentevieytes re: per call gas configuration |
||
| }, | ||
jadepark-dev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| return *p.chain, nil | ||
|
|
@@ -220,54 +219,6 @@ func createTonWallet(client ton.APIClientWrapped, versionConfig wallet.VersionCo | |
| return pw, nil | ||
| } | ||
|
|
||
| func fundTonWallets(ctx context.Context, client ton.APIClientWrapped, recipients []*address.Address, amounts []tlb.Coins) error { | ||
| if len(amounts) != len(recipients) { | ||
| return errors.New("recipients and amounts must have the same length") | ||
| } | ||
|
|
||
| // initialize the prefunded wallet(Highload-V2), for other wallets, see https://github.com/neodix42/mylocalton-docker#pre-installed-wallets | ||
| version := wallet.HighloadV2Verified //nolint:staticcheck // SA1019: only available option in mylocalton-docker | ||
| rawHlWallet, err := wallet.FromSeed(client, strings.Fields(blockchain.DefaultTonHlWalletMnemonic), version) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to create wallet from seed: %w", err) | ||
| } | ||
|
|
||
| mcFunderWallet, err := wallet.FromPrivateKeyWithOptions(client, rawHlWallet.PrivateKey(), version, wallet.WithWorkchain(-1)) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to create wallet from private key: %w", err) | ||
| } | ||
|
|
||
| funder, err := mcFunderWallet.GetSubwallet(uint32(42)) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to get subwallet: %w", err) | ||
| } | ||
|
|
||
| // double check funder address | ||
| if funder.Address().StringRaw() != blockchain.DefaultTonHlWalletAddress { | ||
| return fmt.Errorf("funder address mismatch: %s != %s", funder.Address().StringRaw(), blockchain.DefaultTonHlWalletAddress) | ||
| } | ||
|
|
||
| // create transfer messages for each recipient | ||
| messages := make([]*wallet.Message, len(recipients)) | ||
| for i, addr := range recipients { | ||
| transfer, terr := funder.BuildTransfer(addr, amounts[i], false, "") | ||
| if terr != nil { | ||
| return fmt.Errorf("failed to build transfer: %w", terr) | ||
| } | ||
| messages[i] = transfer | ||
| } | ||
|
|
||
| // we don't wait for the transaction to be confirmed here, as it may take some time | ||
| // the name SendManyWaitTransaction is misleading, it doesn't wait for the transaction to be confirmed, | ||
| // it just sends the transactions(TON has asynchronous transactions) | ||
| _, _, txerr := funder.SendManyWaitTransaction(ctx, messages) | ||
| if txerr != nil { | ||
| return fmt.Errorf("failed to send many wait transaction: %w", txerr) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func getMasterchainBlockID(ctx context.Context, client ton.APIClientWrapped) (*ton.BlockIDExt, error) { | ||
| var masterchainBlockID *ton.BlockIDExt | ||
| // check connection, CTFv2 handles the readiness | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -7,6 +7,7 @@ import ( | |||||||||||||||||||||||||||||||
| "strings" | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| "github.com/xssnick/tonutils-go/liteclient" | ||||||||||||||||||||||||||||||||
| "github.com/xssnick/tonutils-go/tlb" | ||||||||||||||||||||||||||||||||
| tonlib "github.com/xssnick/tonutils-go/ton" | ||||||||||||||||||||||||||||||||
| "github.com/xssnick/tonutils-go/ton/wallet" | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
@@ -22,6 +23,8 @@ const ( | |||||||||||||||||||||||||||||||
| WalletVersionV4R2 WalletVersion = "V4R2" | ||||||||||||||||||||||||||||||||
| WalletVersionV5R1 WalletVersion = "V5R1" | ||||||||||||||||||||||||||||||||
| WalletVersionDefault WalletVersion = "" | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| defaultAmountTonString = "0.1" // Default amount in TON for transactions | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
| defaultAmountTonString = "0.1" // Default amount in TON for transactions | |
| // defaultAmountTonString defines the default amount (in TON) used when a caller | |
| // does not explicitly specify a transaction amount. | |
| // | |
| // The value 0.1 TON is intentionally conservative: it is typically sufficient to | |
| // cover standard transaction fees on mainnet and testnet while remaining small | |
| // enough to avoid unintentionally transferring a large balance. | |
| // | |
| // Consumers should override this default if: | |
| // - their workflow requires sending a larger or smaller value per transaction; | |
| // - network fee dynamics change so that 0.1 TON is no longer adequate to cover | |
| // gas and other on-chain costs; or | |
| // - they operate in an environment (e.g., private/test networks) with different | |
| // economic assumptions. | |
| defaultAmountTonString = "0.1" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,6 +32,7 @@ import ( | |
| "github.com/smartcontractkit/mcms/sdk/evm/bindings" | ||
| "github.com/smartcontractkit/mcms/sdk/solana" | ||
| "github.com/smartcontractkit/mcms/sdk/sui" | ||
| "github.com/smartcontractkit/mcms/sdk/ton" | ||
| "github.com/smartcontractkit/mcms/types" | ||
| "github.com/spf13/cobra" | ||
| "github.com/spf13/pflag" | ||
|
|
@@ -1198,6 +1199,8 @@ func newCfgv2(lggr logger.Logger, cmd *cobra.Command, domain cldf_domain.Domain, | |
| if err != nil { | ||
| return nil, fmt.Errorf("error creating Sui timelock converter: %w", err) | ||
| } | ||
| case chainsel.FamilyTon: | ||
| converter = ton.NewTimelockConverter(ton.DefaultSendAmount) | ||
|
||
| default: | ||
| return nil, fmt.Errorf("unsupported chain family %s", fam) | ||
| } | ||
|
|
@@ -1504,18 +1507,18 @@ func getExecutorWithChainOverride(cfg *cfgv2, chainSelector types.ChainSelector) | |
| if !ok { | ||
| return nil, fmt.Errorf("invalid encoder type: %T", encoder) | ||
| } | ||
| chain := cfg.blockchains.EVMChains()[uint64(chainSelector)] | ||
| c := cfg.blockchains.EVMChains()[uint64(chainSelector)] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what's wrong with the word
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's a nit thing, go variables with limited scope should have shorter names |
||
|
|
||
| return evm.NewExecutor(evmEncoder, chain.Client, chain.DeployerKey), nil | ||
| return evm.NewExecutor(evmEncoder, c.Client, c.DeployerKey), nil | ||
|
|
||
| case chainsel.FamilySolana: | ||
| solanaEncoder, ok := encoder.(*solana.Encoder) | ||
| if !ok { | ||
| return nil, fmt.Errorf("invalid encoder type: %T", encoder) | ||
| } | ||
| chain := cfg.blockchains.SolanaChains()[uint64(chainSelector)] | ||
| c := cfg.blockchains.SolanaChains()[uint64(chainSelector)] | ||
|
|
||
| return solana.NewExecutor(solanaEncoder, chain.Client, *chain.DeployerKey), nil | ||
| return solana.NewExecutor(solanaEncoder, c.Client, *c.DeployerKey), nil | ||
|
|
||
| case chainsel.FamilyAptos: | ||
| encoder, ok := encoder.(*aptos.Encoder) | ||
|
|
@@ -1526,9 +1529,9 @@ func getExecutorWithChainOverride(cfg *cfgv2, chainSelector types.ChainSelector) | |
| if err != nil { | ||
| return nil, fmt.Errorf("error getting aptos role from proposal: %w", err) | ||
| } | ||
| chain := cfg.blockchains.AptosChains()[uint64(chainSelector)] | ||
| c := cfg.blockchains.AptosChains()[uint64(chainSelector)] | ||
|
|
||
| return aptos.NewExecutor(chain.Client, chain.DeployerSigner, encoder, *role), nil | ||
| return aptos.NewExecutor(c.Client, c.DeployerSigner, encoder, *role), nil | ||
|
|
||
| case chainsel.FamilySui: | ||
| encoder, ok := encoder.(*sui.Encoder) | ||
|
|
@@ -1539,10 +1542,18 @@ func getExecutorWithChainOverride(cfg *cfgv2, chainSelector types.ChainSelector) | |
| if err != nil { | ||
| return nil, fmt.Errorf("error getting sui metadata from proposal: %w", err) | ||
| } | ||
| chain := cfg.blockchains.SuiChains()[uint64(chainSelector)] | ||
| c := cfg.blockchains.SuiChains()[uint64(chainSelector)] | ||
| entrypointEncoder := suibindings.NewCCIPEntrypointArgEncoder(metadata.RegistryObj, metadata.DeployerStateObj) | ||
|
|
||
| return sui.NewExecutor(chain.Client, chain.Signer, encoder, entrypointEncoder, metadata.McmsPackageID, metadata.Role, cfg.timelockProposal.ChainMetadata[chainSelector].MCMAddress, metadata.AccountObj, metadata.RegistryObj, metadata.TimelockObj) | ||
| return sui.NewExecutor(c.Client, c.Signer, encoder, entrypointEncoder, metadata.McmsPackageID, metadata.Role, cfg.timelockProposal.ChainMetadata[chainSelector].MCMAddress, metadata.AccountObj, metadata.RegistryObj, metadata.TimelockObj) | ||
| case chainsel.FamilyTon: | ||
| encoder, ok := encoder.(*ton.Encoder) | ||
| if !ok { | ||
| return nil, fmt.Errorf("error getting encoder for chain %d", cfg.chainSelector) | ||
huangzhen1997 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| c := cfg.blockchains.TonChains()[uint64(chainSelector)] | ||
|
|
||
| return ton.NewExecutor(encoder, c.Client, c.TxOps.Wallet, c.TxOps.Amount) | ||
|
||
| default: | ||
| return nil, fmt.Errorf("unsupported chain family %s", family) | ||
| } | ||
|
|
@@ -1572,26 +1583,29 @@ func getTimelockExecutorWithChainOverride(cfg *cfgv2, chainSelector types.ChainS | |
| var executor sdk.TimelockExecutor | ||
| switch family { | ||
| case chainsel.FamilyEVM: | ||
| chain := cfg.blockchains.EVMChains()[uint64(chainSelector)] | ||
| c := cfg.blockchains.EVMChains()[uint64(chainSelector)] | ||
|
|
||
| executor = evm.NewTimelockExecutor(chain.Client, chain.DeployerKey) | ||
| executor = evm.NewTimelockExecutor(c.Client, c.DeployerKey) | ||
| case chainsel.FamilySolana: | ||
| chain := cfg.blockchains.SolanaChains()[uint64(chainSelector)] | ||
| executor = solana.NewTimelockExecutor(chain.Client, *chain.DeployerKey) | ||
| c := cfg.blockchains.SolanaChains()[uint64(chainSelector)] | ||
| executor = solana.NewTimelockExecutor(c.Client, *c.DeployerKey) | ||
| case chainsel.FamilyAptos: | ||
| chain := cfg.blockchains.AptosChains()[uint64(chainSelector)] | ||
| executor = aptos.NewTimelockExecutor(chain.Client, chain.DeployerSigner) | ||
| c := cfg.blockchains.AptosChains()[uint64(chainSelector)] | ||
| executor = aptos.NewTimelockExecutor(c.Client, c.DeployerSigner) | ||
| case chainsel.FamilySui: | ||
| chain := cfg.blockchains.SuiChains()[uint64(chainSelector)] | ||
| c := cfg.blockchains.SuiChains()[uint64(chainSelector)] | ||
| metadata, err := suiMetadataFromProposal(chainSelector, cfg.timelockProposal) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("error getting sui metadata from proposal: %w", err) | ||
| } | ||
| entrypointEncoder := suibindings.NewCCIPEntrypointArgEncoder(metadata.AccountObj, metadata.DeployerStateObj) | ||
| executor, err = sui.NewTimelockExecutor(chain.Client, chain.Signer, entrypointEncoder, metadata.McmsPackageID, metadata.RegistryObj, metadata.AccountObj) | ||
| executor, err = sui.NewTimelockExecutor(c.Client, c.Signer, entrypointEncoder, metadata.McmsPackageID, metadata.RegistryObj, metadata.AccountObj) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("error creating sui timelock executor: %w", err) | ||
| } | ||
| case chainsel.FamilyTon: | ||
| c := cfg.blockchains.TonChains()[uint64(chainSelector)] | ||
| return ton.NewTimelockExecutor(c.Client, c.TxOps.Wallet, c.TxOps.Amount) | ||
|
||
| default: | ||
| return nil, fmt.Errorf("unsupported chain family %s", family) | ||
| } | ||
|
|
@@ -1646,6 +1660,9 @@ var getInspectorFromChainSelector = func(cfg cfgv2) (sdk.Inspector, error) { | |
| if err != nil { | ||
| return nil, fmt.Errorf("error creating sui inspector: %w", err) | ||
| } | ||
| case chainsel.FamilyTon: | ||
| chain := cfg.blockchains.TonChains()[cfg.chainSelector] | ||
| inspector = ton.NewInspector(chain.Client) | ||
|
Comment on lines
+1664
to
+1665
|
||
| default: | ||
| return nil, fmt.Errorf("unsupported chain family %s", fam) | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Omitting fund logic from network setup makes sense to me(if I am reading it right), but just a reminder that integration tests in core and chainlink-ton are relying on the deployer wallet to fund transmitters: