Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
8 changes: 4 additions & 4 deletions deployment/changesets/cs_add_ccip_package_id.go
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we also update and test the block function & block version changesets/ops?

Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,10 @@ func executeAddPackageId(e cldf.Environment, config AddCCIPPackageIdConfig, chai
switch target {
case AddPackageIdTargetCCIP:
r, err := operations.ExecuteOperation(e.OperationsBundle, ccipops.AddPackageIdStateObjectOp, deps, ccipops.AddPackageIdStateObjectInput{
CCIPPackageId: config.CCIPPackageId,
PackageId: config.CCIPPackageId,
CCIPObjectRefObjectId: chainState.CCIPObjectRef,
OwnerCapObjectId: chainState.CCIPOwnerCapObjectId,
PackageId: config.PackageId,
NewPackageId: config.PackageId,
})
if err != nil {
return operations.Report[any, any]{}, fmt.Errorf("failed to add package ID to CCIP state object for Sui chain %d: %w", config.SuiChainSelector, err)
Expand All @@ -130,10 +130,10 @@ func executeAddPackageId(e cldf.Environment, config AddCCIPPackageIdConfig, chai

case AddPackageIdTargetOffRamp:
r, err := operations.ExecuteOperation(e.OperationsBundle, offrampops.AddPackageIdOffRampOp, deps, offrampops.AddPackageIdOffRampInput{
OffRampPackageId: config.OffRampPackageId,
PackageId: config.OffRampPackageId,
StateObjectId: chainState.OffRampStateObjectId,
OwnerCapObjectId: chainState.OffRampOwnerCapId,
PackageId: config.PackageId,
NewPackageId: config.PackageId,
})
if err != nil {
return operations.Report[any, any]{}, fmt.Errorf("failed to add package ID to OffRamp for Sui chain %d: %w", config.SuiChainSelector, err)
Expand Down
4 changes: 2 additions & 2 deletions deployment/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ require (
github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260311190822-5cbfc939dd16
github.com/smartcontractkit/chainlink-common v0.11.2-0.20260406055916-9aa6b6c0ae81
github.com/smartcontractkit/chainlink-deployments-framework v0.75.0
github.com/smartcontractkit/chainlink-sui v0.0.0-20260205175622-33e65031f9a9
github.com/smartcontractkit/mcms v0.40.1
github.com/smartcontractkit/chainlink-sui v0.0.0-20260408222042-6c7b4c27a8b2
github.com/smartcontractkit/mcms v0.40.5-0.20260409113859-92ddf0d61451 // Replace with official release before merging
github.com/stretchr/testify v1.11.1
golang.org/x/sync v0.19.0
)
Expand Down
4 changes: 2 additions & 2 deletions deployment/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 21 additions & 8 deletions deployment/ops/ccip/op_state_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,35 +15,48 @@ import (
// =================== Add Package ID Operations =================== //

type AddPackageIdStateObjectInput struct {
CCIPPackageId string
PackageId string // original package ID (MCMS registry identity; used as binary when LatestPackageId is "")
LatestPackageId string // optional: upgraded package ID (PTB execution target when set)
CCIPObjectRefObjectId string
OwnerCapObjectId string
PackageId string
NewPackageId string // the package ID to register in the CCIP StateObject
}

type AddPackageIdStateObjectObjects struct {
// No specific objects are returned from add_package_id
}

var addPackageIdStateObjectHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input AddPackageIdStateObjectInput) (output sui_ops.OpTxResult[AddPackageIdStateObjectObjects], err error) {
contract, err := module_state_object.NewStateObject(input.CCIPPackageId, deps.Client)
// When the package has been upgraded, PTB must target the latest bytecode for execution.
binaryPkgId := input.PackageId
if input.LatestPackageId != "" {
binaryPkgId = input.LatestPackageId
}
contract, err := module_state_object.NewStateObject(binaryPkgId, deps.Client)
if err != nil {
return sui_ops.OpTxResult[AddPackageIdStateObjectObjects]{}, fmt.Errorf("failed to create StateObject contract: %w", err)
}

encodedCall, err := contract.Encoder().AddPackageId(bind.Object{Id: input.CCIPObjectRefObjectId}, bind.Object{Id: input.OwnerCapObjectId}, input.PackageId)
encodedCall, err := contract.Encoder().AddPackageId(bind.Object{Id: input.CCIPObjectRefObjectId}, bind.Object{Id: input.OwnerCapObjectId}, input.NewPackageId)
if err != nil {
return sui_ops.OpTxResult[AddPackageIdStateObjectObjects]{}, fmt.Errorf("failed to encode AddPackageId call: %w", err)
}
call, err := sui_ops.ToTransactionCall(encodedCall, input.CCIPObjectRefObjectId)
if err != nil {
return sui_ops.OpTxResult[AddPackageIdStateObjectObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err)
}
// When the package has been upgraded, the on-chain MCMS registry still holds the original package's
// proof type, so tx.To must be the original package ID. The PTB MoveCall must target the latest package
// so upgraded bytecode runs. Use LatestPackageId so the proposal generator can separate the two.
if input.LatestPackageId != "" {
call.LatestPackageID = call.PackageID // current PackageID is the latest (from binaryPkgId)
call.PackageID = input.PackageId // replace with original for on-chain identity
}
if deps.Signer == nil {
b.Logger.Infow("Skipping execution of AddPackageId on StateObject as per no Signer provided", "packageId", input.PackageId)
b.Logger.Infow("Skipping execution of AddPackageId on StateObject as per no Signer provided", "newPackageId", input.NewPackageId)
return sui_ops.OpTxResult[AddPackageIdStateObjectObjects]{
Digest: "",
PackageId: input.CCIPPackageId,
PackageId: input.PackageId,
Objects: AddPackageIdStateObjectObjects{},
Call: call,
}, nil
Expand All @@ -60,11 +73,11 @@ var addPackageIdStateObjectHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDep
return sui_ops.OpTxResult[AddPackageIdStateObjectObjects]{}, fmt.Errorf("failed to execute AddPackageId on StateObject: %w", err)
}

b.Logger.Infow("Package ID added to CCIP StateObject", "packageId", input.PackageId)
b.Logger.Infow("Package ID added to CCIP StateObject", "newPackageId", input.NewPackageId)

return sui_ops.OpTxResult[AddPackageIdStateObjectObjects]{
Digest: tx.Digest,
PackageId: input.CCIPPackageId,
PackageId: input.PackageId,
Objects: AddPackageIdStateObjectObjects{},
Call: call,
}, nil
Expand Down
8 changes: 4 additions & 4 deletions deployment/ops/ccip/op_state_object_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,10 @@ func TestStateObjectOperations(t *testing.T) {
t.Run("Test Add Package ID", func(t *testing.T) {
newPackageId := "0x123456789abcdef" // Example package ID
addReport, err := cld_ops.ExecuteOperation(bundle, AddPackageIdStateObjectOp, deps, AddPackageIdStateObjectInput{
CCIPPackageId: ccipReport.Output.PackageId,
PackageId: ccipReport.Output.PackageId,
CCIPObjectRefObjectId: ccipReport.Output.Objects.CCIPObjectRefObjectId,
OwnerCapObjectId: ccipReport.Output.Objects.OwnerCapObjectId,
PackageId: newPackageId,
NewPackageId: newPackageId,
})
require.NoError(t, err, "failed to add package ID")
require.NotEmpty(t, addReport.Output.Digest, "add package ID transaction should have a digest")
Expand All @@ -101,10 +101,10 @@ func TestStateObjectOperations(t *testing.T) {
// First add a package ID to remove
newPackageId := "0xabcdef1234567890abcdef1234567890abcdef12"
_, err := cld_ops.ExecuteOperation(bundle, AddPackageIdStateObjectOp, deps, AddPackageIdStateObjectInput{
CCIPPackageId: ccipReport.Output.PackageId,
PackageId: ccipReport.Output.PackageId,
CCIPObjectRefObjectId: ccipReport.Output.Objects.CCIPObjectRefObjectId,
OwnerCapObjectId: ccipReport.Output.Objects.OwnerCapObjectId,
PackageId: newPackageId,
NewPackageId: newPackageId,
})
// Now remove the package ID
removeReport, err := cld_ops.ExecuteOperation(bundle, RemovePackageIdStateObjectOp, deps, RemovePackageIdStateObjectInput{
Expand Down
48 changes: 39 additions & 9 deletions deployment/ops/ccip_offramp/op_deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,41 +241,71 @@ var applySourceChainConfigUpdateHandler = func(b cld_ops.Bundle, deps sui_ops.Op
}

type AddPackageIdOffRampInput struct {
OffRampPackageId string
PackageId string // original package ID (MCMS registry identity; used as binary when LatestPackageId is "")
LatestPackageId string // optional: upgraded package ID (PTB execution target when set)
StateObjectId string
OwnerCapObjectId string
PackageId string
NewPackageId string // the package ID to register in the OffRamp state
}

type AddPackageIdOffRampObjects struct {
// No specific objects are returned from add_package_id
}

var addPackageIdOffRampHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, input AddPackageIdOffRampInput) (output sui_ops.OpTxResult[AddPackageIdOffRampObjects], err error) {
offRampPackage, err := module_offramp.NewOfframp(input.OffRampPackageId, deps.Client)
// When the package has been upgraded, PTB must target the latest bytecode for execution.
binaryPkgId := input.PackageId
if input.LatestPackageId != "" {
binaryPkgId = input.LatestPackageId
}
offRampPackage, err := module_offramp.NewOfframp(binaryPkgId, deps.Client)
if err != nil {
return sui_ops.OpTxResult[AddPackageIdOffRampObjects]{}, err
}

encodedCall, err := offRampPackage.Encoder().AddPackageId(bind.Object{Id: input.StateObjectId}, bind.Object{Id: input.OwnerCapObjectId}, input.NewPackageId)
if err != nil {
return sui_ops.OpTxResult[AddPackageIdOffRampObjects]{}, fmt.Errorf("failed to encode AddPackageId call: %w", err)
}
call, err := sui_ops.ToTransactionCall(encodedCall, input.StateObjectId)
if err != nil {
return sui_ops.OpTxResult[AddPackageIdOffRampObjects]{}, fmt.Errorf("failed to convert encoded call to TransactionCall: %w", err)
}
// When the package has been upgraded, the on-chain MCMS registry still holds the original package's
// proof type, so tx.To must be the original package ID. Use LatestPackageId so the proposal
// generator routes the PTB MoveCall to the upgraded bytecode.
if input.LatestPackageId != "" {
call.LatestPackageID = call.PackageID // current PackageID is the latest (from binaryPkgId)
call.PackageID = input.PackageId // replace with original for on-chain identity
}
if deps.Signer == nil {
b.Logger.Infow("Skipping execution of AddPackageId on OffRamp as per no Signer provided", "newPackageId", input.NewPackageId)
return sui_ops.OpTxResult[AddPackageIdOffRampObjects]{
Digest: "",
PackageId: input.PackageId,
Objects: AddPackageIdOffRampObjects{},
Call: call,
}, nil
}

opts := deps.GetCallOpts()
opts.Signer = deps.Signer
tx, err := offRampPackage.AddPackageId(
tx, err := offRampPackage.Bound().ExecuteTransaction(
b.GetContext(),
opts,
bind.Object{Id: input.StateObjectId},
bind.Object{Id: input.OwnerCapObjectId},
input.PackageId,
encodedCall,
)
if err != nil {
return sui_ops.OpTxResult[AddPackageIdOffRampObjects]{}, fmt.Errorf("failed to execute AddPackageId on offRamp: %w", err)
}

b.Logger.Infow("Package ID added to OffRamp", "packageId", input.PackageId)
b.Logger.Infow("Package ID added to OffRamp", "newPackageId", input.NewPackageId)

return sui_ops.OpTxResult[AddPackageIdOffRampObjects]{
Digest: tx.Digest,
PackageId: input.OffRampPackageId,
PackageId: input.PackageId,
Objects: AddPackageIdOffRampObjects{},
Call: call,
}, nil
}

Expand Down
7 changes: 7 additions & 0 deletions deployment/ops/mcms/op_proposal_generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ var generateProposalHandler = func(b cld_ops.Bundle, deps sui_ops.OpTxDeps, inpu
if err != nil {
return mcms.TimelockProposal{}, fmt.Errorf("failed to create transaction for operation %s: %w", def.ID, err)
}
// If the op signalled an upgraded package, record it so the timelock converter
// propagates it as InternalLatestPackageIDs in the outer batch operation.
if call.LatestPackageID != "" {
if setErr := suisdk.SetLatestPackageID(&tx, call.LatestPackageID); setErr != nil {
return mcms.TimelockProposal{}, fmt.Errorf("failed to set latest package ID for operation %s: %w", def.ID, setErr)
}
}
mcmsTxs[i] = tx
}

Expand Down
12 changes: 6 additions & 6 deletions deployment/ops/mcms/op_proposal_generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,10 @@ func TestMCMSDynamicProposalGenerateSeq(t *testing.T) {

inputs := []any{
ccipops.AddPackageIdStateObjectInput{
CCIPPackageId: testCCIPPackageId,
PackageId: testCCIPPackageId,
CCIPObjectRefObjectId: testObjectRefId,
OwnerCapObjectId: testOwnerCapId,
PackageId: testPackageId,
NewPackageId: testPackageId,
},
ccipops.TransferOwnershipStateObjectInput{
CCIPPackageId: testCCIPPackageId,
Expand Down Expand Up @@ -228,10 +228,10 @@ func TestMCMSDynamicProposalGenerateSeq(t *testing.T) {
inputs := []any{

ccipops.AddPackageIdStateObjectInput{
CCIPPackageId: testCCIPPackageId,
PackageId: testCCIPPackageId,
CCIPObjectRefObjectId: testObjectRefId,
OwnerCapObjectId: testOwnerCapId,
PackageId: testPackageId,
NewPackageId: testPackageId,
},
}

Expand Down Expand Up @@ -270,10 +270,10 @@ func TestMCMSDynamicProposalGenerateSeq(t *testing.T) {
inputs := []any{

ccipops.AddPackageIdStateObjectInput{
CCIPPackageId: testCCIPPackageId,
PackageId: testCCIPPackageId,
CCIPObjectRefObjectId: testObjectRefId,
OwnerCapObjectId: testOwnerCapId,
PackageId: testPackageId,
NewPackageId: testPackageId,
},

// Missing second input
Expand Down
13 changes: 7 additions & 6 deletions deployment/ops/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ type OpTxResult[O any] struct {
}

type TransactionCall struct {
PackageID string
Module string
Function string
Data []byte
StateObjID string
TypeArgs []string
PackageID string
LatestPackageID string // optional: when set, the PTB MoveCall targets this (upgraded) package while PackageID remains the on-chain MCMS identity
Module string
Function string
Data []byte
StateObjID string
TypeArgs []string
}

type OpTxDeps struct {
Expand Down
4 changes: 2 additions & 2 deletions integration-tests/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ require (
github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260311190822-5cbfc939dd16
github.com/smartcontractkit/chainlink-common v0.11.2-0.20260406055916-9aa6b6c0ae81
github.com/smartcontractkit/chainlink-deployments-framework v0.75.0
github.com/smartcontractkit/chainlink-sui v0.0.0-20260205175622-33e65031f9a9
github.com/smartcontractkit/chainlink-sui v0.0.0-20260408222042-6c7b4c27a8b2
github.com/smartcontractkit/chainlink-sui/deployment v0.0.0-20250903045200-c3d973201e55
github.com/smartcontractkit/mcms v0.40.1
github.com/smartcontractkit/mcms v0.40.5-0.20260409113859-92ddf0d61451 // Replace with official release before merging
github.com/stretchr/testify v1.11.1
)

Expand Down
4 changes: 2 additions & 2 deletions integration-tests/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading