Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c00f3e3
Migrate TON to test adapters
archseer Jan 27, 2026
7845557
Remove unnecessary generics
archseer Jan 27, 2026
665139c
Fix extraArgs
archseer Jan 27, 2026
a88fbe1
Merge branch 'main' into devenv-testadapter
jadepark-dev Jan 28, 2026
688ea7c
Fix build
archseer Jan 29, 2026
9deec4b
Implement CCIPReceiver
archseer Jan 29, 2026
0ed350c
TEMP: switch smoke test TARGET_BRANCH to PR
archseer Jan 30, 2026
25d6907
Fix integration-tests build
archseer Jan 30, 2026
c1a6668
go mod tidy
archseer Jan 30, 2026
28be98b
.core_version update
pavel-raykov Jan 30, 2026
f4d6a45
run gomods tidy
pavel-raykov Jan 30, 2026
f5bde3f
run ./modgraph > go.md
pavel-raykov Jan 30, 2026
2a520bc
Clear this file so my PR is actually tested?
archseer Jan 30, 2026
23a5aa7
Merge branch 'main' into devenv-testadapter
jadepark-dev Feb 3, 2026
46ef3ef
chore: tidy
jadepark-dev Feb 3, 2026
00821c0
fix: use native token when it's empty
jadepark-dev Feb 4, 2026
80db61e
chore: bump
jadepark-dev Feb 4, 2026
ca7787f
chore(deps): bump ctf
jadepark-dev Feb 4, 2026
54b78d6
Merge branch 'main' into devenv-testadapter
jadepark-dev Feb 4, 2026
5619fc5
chore: tidy
jadepark-dev Feb 4, 2026
3861e29
fix: use current head
jadepark-dev Feb 4, 2026
c2f3f1c
fix: deps
jadepark-dev Feb 4, 2026
27ac3c7
fix: e2e
jadepark-dev Feb 4, 2026
2245bdb
Merge branch 'main' into devenv-testadapter
jadepark-dev Feb 4, 2026
c91f1f4
chore: trigger ci
jadepark-dev Feb 4, 2026
880a928
Merge branch 'main' into devenv-testadapter
jadepark-dev Feb 5, 2026
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
2 changes: 1 addition & 1 deletion .github/workflows/test-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ jobs:
# Deployment configuration
WORKFLOW_FILE: .github/workflows/test_smoke.yml
TARGET_REPO: smartcontractkit/chainlink-ccip
TARGET_BRANCH: main
TARGET_BRANCH: ton-testadapter
TON_REF: ${{steps.set-version-chainlink-ton.outputs.chainlink-ton_version}}
CHAINLINK_VERSION: ${{steps.set-version-chainlink.outputs.chainlink_version}}
# relative to chainlink-ccip/devenv. Assumes chainlink-ton is checked out to top level
Expand Down
179 changes: 6 additions & 173 deletions deployment/ccip/cs_test_helpers.go
Original file line number Diff line number Diff line change
@@ -1,36 +1,27 @@
package ops

import (
"context"
"crypto/rand"
"encoding/binary"
"errors"
"fmt"
"math/big"
"testing"

"github.com/Masterminds/semver/v3"

"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"

chainsel "github.com/smartcontractkit/chain-selectors"

"github.com/smartcontractkit/chainlink-ccip/deployment/lanes"
"github.com/smartcontractkit/chainlink-ccip/deployment/testadapters"

cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment"

"github.com/smartcontractkit/chainlink-ton/pkg/ccip/bindings/onramp"
"github.com/smartcontractkit/chainlink-ton/pkg/ccip/bindings/router"
"github.com/smartcontractkit/chainlink-ton/pkg/ton/codec/debug"
sequenceDiagram "github.com/smartcontractkit/chainlink-ton/pkg/ton/codec/debug/visualizations/sequence"
"github.com/smartcontractkit/chainlink-ton/pkg/ton/tracetracking"
"github.com/smartcontractkit/chainlink-ton/pkg/ton/tvm"

"github.com/smartcontractkit/chainlink-ton/deployment/ccip/config"
"github.com/smartcontractkit/chainlink-ton/deployment/state"
"github.com/smartcontractkit/chainlink-ton/deployment/testadapter"
"github.com/smartcontractkit/chainlink-ton/deployment/utils/sequence"
)

Expand All @@ -42,6 +33,7 @@ const (
CalldataGasPerByteThreshold = 3000
)

// Deprecated: Use tvm.TonTokenAddr instead.
var TonTokenAddr = address.MustParseRawAddr("0:0000000000000000000000000000000000000000000000000000000000000001")

var (
Expand Down Expand Up @@ -277,174 +269,15 @@ func AddLaneTONConfig(env *cldf.Environment, onRamp []byte, from, to uint64, fro
}
}

// TODO Consider move chainlink core AnyMsgSentEvent and CCIPSendReqConfig to CLDF?
// SendCCIPMessage sends a CCIP request from a TON chain using the standard router.CCIPSend message.
// TODO: add TokenAmounts support for TON token transfers
// Deprecated: Use testadapters instead
func SendCCIPMessage(
e cldf.Environment,
state state.CCIPChainState,
sourceChain uint64,
msg router.CCIPSend) (uint64, any, error) {
chain := e.BlockChains.TonChains()[sourceChain]
senderWallet := chain.Wallet
senderAddr := chain.WalletAddress
clientConn := chain.Client

routerAddr := state.Router

ccipSend := msg

ccipSendCell, err := tlb.ToCell(ccipSend)
if err != nil {
return 0, nil, fmt.Errorf("failed to convert to cell: %w", err)
}

e.Logger.Infof("Getting Fee to send CCIP request from chain selector %d to chain selector %d",
sourceChain, msg.DestChainSelector)

ctx := context.Background()
block, err := clientConn.CurrentMasterchainInfo(ctx)
if err != nil {
return 0, nil, fmt.Errorf("failed to get current masterchain info: %w", err)
}
getResult, err := clientConn.RunGetMethod(ctx, block, &state.FeeQuoter, "validatedFeeCell", ccipSendCell)
if err != nil {
return 0, nil, fmt.Errorf("failed to get validatedFee: %w", err)
}

fee, err := getResult.Int(0)
if err != nil {
return 0, nil, fmt.Errorf("failed to get fee: %w", err)
}
e.Logger.Infof("Fee to send CCIP request: %s nano TON", fee.String())

e.Logger.Infof("(Ton) Sending CCIP request from chain selector %d to chain selector %d using sender %s",
sourceChain, msg.DestChainSelector, senderAddr.String())

value := big.NewInt(0).Add(fee, tlb.MustFromTON("0.5").Nano() /* To cover for gas */)

// Check sender balance before sending
senderAccount, err := clientConn.GetAccount(ctx, block, senderAddr)
if err != nil {
return 0, nil, fmt.Errorf("failed to get sender account: %w", err)
}
senderBalance := senderAccount.State.Balance.Nano()
e.Logger.Infof("Sender balance: %s nano TON, required value: %s nano TON", senderBalance.String(), value.String())
if senderBalance.Cmp(value) < 0 {
return 0, nil, fmt.Errorf("insufficient balance: sender has %s nano TON but needs %s nano TON", senderBalance.String(), value.String())
}
walletMsg := &wallet.Message{
Mode: wallet.PayGasSeparately | wallet.IgnoreErrors,
InternalMessage: &tlb.InternalMessage{
IHRDisabled: true,
Bounce: false,
DstAddr: &routerAddr,
Amount: tlb.MustFromNano(value, 9),
Body: ccipSendCell,
},
}

ttConn := tracetracking.NewSignedAPIClient(clientConn, *senderWallet)
receivedMsg, blockID, err := ttConn.SendWaitTransaction(e.GetContext(), routerAddr, walletMsg)
if err != nil {
return 0, nil, fmt.Errorf("failed to send transaction: %w", err)
}

if receivedMsg.ExitCode != 0 {
return 0, nil, fmt.Errorf("transaction failed: with exitcode %d: %s", receivedMsg.ExitCode, receivedMsg.ExitCode.Describe())
}

e.Logger.Infow("transaction sent", "blockID", blockID, "receivedMsg", receivedMsg)
err = receivedMsg.WaitForTrace(e.GetContext(), clientConn)
if err != nil {
return 0, nil, fmt.Errorf("failed to wait for trace: %w", err)
}

// TODO: This is temporary debugging code to be removed later
zeroVersion := *semver.MustParse("0.0.0")
knownAddresses := map[string]debug.TypeAndVersion{
senderAddr.String(): {Type: "SenderWallet", Version: zeroVersion},
state.LinkTokenAddress.String(): {Type: "LinkTokenAddress", Version: zeroVersion},
state.OffRamp.String(): {Type: "OffRamp", Version: zeroVersion},
state.Router.String(): {Type: "Router", Version: zeroVersion},
state.OnRamp.String(): {Type: "OnRamp", Version: zeroVersion},
state.FeeQuoter.String(): {Type: "FeeQuoter", Version: zeroVersion},
state.ReceiverAddress.String(): {Type: "ReceiverAddress", Version: zeroVersion},
}
e.Logger.Infof("Msg tree trace:\n%s\n", debug.NewDebuggerTreeTrace(knownAddresses).DumpReceived(receivedMsg))
e.Logger.Infof("Msg sequence diagram:\n%s\n", debug.NewDebuggerSequenceTrace(knownAddresses, sequenceDiagram.OutputFmtURL).DumpReceived(receivedMsg))

event, err := waitForReceivedMsgFlatten(e, clientConn, receivedMsg)
if err != nil {
return 0, nil, fmt.Errorf("failed to get CCIPMessageSent from flattening received messages: %w", err)
}
return event.Message.Header.SequenceNumber, event, nil
}

func waitForReceivedMsgFlatten(e cldf.Environment, clientConn ton.APIClientWrapped, msg *tracetracking.ReceivedMessage) (onramp.CCIPMessageSent, error) {
if msg == nil {
return onramp.CCIPMessageSent{}, errors.New("received message is nil")
}

// Collect all messages to process in a queue
var messagesToProcess []*tracetracking.ReceivedMessage
messagesToProcess = append(messagesToProcess, msg)

var commitMessage *tracetracking.ReceivedMessage

// Process messages iteratively
for len(messagesToProcess) > 0 {
// Get the first message from the queue
currentMsg := messagesToProcess[0]
messagesToProcess = messagesToProcess[1:]

if len(currentMsg.OutgoingInternalReceivedMessages) == 0 {
continue
}

e.Logger.Infof("Flattening %d outgoing internal messages", len(currentMsg.OutgoingInternalReceivedMessages))

for i, outMsg := range currentMsg.OutgoingInternalReceivedMessages {
e.Logger.Infof("Outgoing message %d: exit code %v, success: %v, bounced: %v, status: %v",
i, outMsg.ExitCode, outMsg.Success, outMsg.EmittedBouncedMessage, outMsg.Status())

if outMsg.ExitCode != 0 {
e.Logger.Errorf("Outgoing message %d failed with exit code %v", i, outMsg.ExitCode)
}
if !outMsg.Success {
e.Logger.Errorf("Outgoing message %d was not successful", i)
}
if outMsg.EmittedBouncedMessage {
e.Logger.Errorf("Outgoing message %d was bounced", i)
}

err := outMsg.WaitForTrace(e.GetContext(), clientConn)
if err != nil {
e.Logger.Errorf("failed to wait for trace: %v", err)
continue
}

// Add this message to the queue for further processing
messagesToProcess = append(messagesToProcess, outMsg)
opcode, err := outMsg.InternalMsg.Body.BeginParse().LoadUInt(32)
if err == nil && opcode == onramp.OpcodeOnRampExecutorFinishedSuccessfully {
commitMessage = outMsg
}
}
}

if commitMessage == nil || len(commitMessage.OutgoingExternalMessages) == 0 {
return onramp.CCIPMessageSent{}, errors.New("no received messages were processed")
}

var event onramp.CCIPMessageSent
err := tlb.LoadFromCell(&event, commitMessage.OutgoingExternalMessages[0].Body.BeginParse())
if err != nil {
e.Logger.Errorf("failed to parse CCIPMessageSent from cell: %v", err)
return onramp.CCIPMessageSent{}, err
}

return event, nil
stateProvider := &testadapters.DataStoreStateProvider{Selector: sourceChain, DS: e.DataStore}
return testadapter.SendCCIPMessage(e.GetContext(), chain, stateProvider, sourceChain, msg)
}

func RandomUint32() (uint32, error) {
Expand Down
Loading
Loading