Skip to content

Commit

Permalink
[DPA-1494]: fix(solana): use new seed for timelock bypasser to addres…
Browse files Browse the repository at this point in the history
…s latest breaking change (#271)

Dependent on [this
PR](#270) updating the rest
of the [API breaking
change](smartcontractkit/chainlink-ccip#474).

- Uses the new seed `timelock_bypasser_operation` for bypass operation
for timelock converter.
- Preload instructions for timelock bypasser from initialise to finalize
- Updated e2e

JIRA: https://smartcontract-it.atlassian.net/browse/DPA-1494
  • Loading branch information
graham-chainlink authored Jan 29, 2025
1 parent e38816f commit 671cf97
Show file tree
Hide file tree
Showing 5 changed files with 266 additions and 9 deletions.
118 changes: 114 additions & 4 deletions e2e/tests/solana/timelock_converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ func (s *SolanaTestSuite) Test_TimelockConverter() {
operation2PDA, err := solanasdk.FindTimelockOperationPDA(s.TimelockProgramID, testPDASeedTimelockConverter, operation2ID)
s.Require().NoError(err)

operation1BypasserPDA, err := solanasdk.FindTimelockBypasserOperationPDA(s.TimelockProgramID, testPDASeedTimelockConverter, operation1ID)
s.Require().NoError(err)
operation2BypasserPDA, err := solanasdk.FindTimelockBypasserOperationPDA(s.TimelockProgramID, testPDASeedTimelockConverter, operation2ID)
s.Require().NoError(err)

// build base timelock proposal
timelockProposalBuilder := func() *mcms.TimelockProposalBuilder {
return mcms.NewTimelockProposalBuilder().
Expand Down Expand Up @@ -331,24 +336,129 @@ func (s *SolanaTestSuite) Test_TimelockConverter() {
timelockProposal, err := timelockProposalBuilder().SetAction(types.TimelockActionBypass).Build()
s.Require().NoError(err)

bypasserAC := s.Roles[timelock.Bypasser_Role].AccessController.PublicKey()

// build expected output Proposal
wantProposal, err := mcms.NewProposalBuilder().
SetValidUntil(uint32(validUntil)).
SetDescription("proposal to test the timelock proposal converter").
SetOverridePreviousRoot(true).
SetVersion("v1").
AddChainMetadata(s.ChainSelector, types.ChainMetadata{MCMAddress: mcmAddress}).
AddOperation(types.Operation{ChainSelector: s.ChainSelector, Transaction: types.Transaction{
// op1: initialize operation instruction
To: s.TimelockProgramID.String(),
Data: base64Decode(s.T(), "OhswzBPFPxp0ZXN0LXRpbWVsb2NrY29udmVydGVyAAAAAAAAAAAAAFF3oPhB0oSxY3h5BmiszWNGktjysKAxcPliXCS0aGa3ekMrgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAA"),
OperationMetadata: types.OperationMetadata{ContractType: "RBACTimelock", Tags: op1Tags},
AdditionalFields: marshalAdditionalFields(s.T(), solanasdk.AdditionalFields{
Accounts: []*solana.AccountMeta{
{PublicKey: operation1BypasserPDA, IsWritable: true},
{PublicKey: configPDA},
{PublicKey: bypasserAC},
{PublicKey: mcmSignerPDA, IsWritable: true},
{PublicKey: solana.SystemProgramID},
},
}),
}}).
AddOperation(types.Operation{ChainSelector: s.ChainSelector, Transaction: types.Transaction{
// op1: append 1st timelock instruction ("empty" call)
To: s.TimelockProgramID.String(),
Data: base64Decode(s.T(), "f0QI0mrVGdd0ZXN0LXRpbWVsb2NrY29udmVydGVyAAAAAAAAAAAAAFF3oPhB0oSxY3h5BmiszWNGktjysKAxcPliXCS0aGa3AQAAADDXIVGUZuenxgaR919Jc0lUvuAv22cA3X8CoZ3pcszbCAAAANYsBPcMKdluAAAAAA=="),
OperationMetadata: types.OperationMetadata{ContractType: "RBACTimelock", Tags: op1Tags},
AdditionalFields: marshalAdditionalFields(s.T(), solanasdk.AdditionalFields{
Accounts: []*solana.AccountMeta{
{PublicKey: operation1BypasserPDA, IsWritable: true},
{PublicKey: configPDA},
{PublicKey: bypasserAC},
{PublicKey: mcmSignerPDA, IsWritable: true},
{PublicKey: solana.SystemProgramID},
},
}),
}}).
AddOperation(types.Operation{ChainSelector: s.ChainSelector, Transaction: types.Transaction{
// op1: append 2nd timelock instruction ("u8_value" call)
To: s.TimelockProgramID.String(),
Data: base64Decode(s.T(), "f0QI0mrVGdd0ZXN0LXRpbWVsb2NrY29udmVydGVyAAAAAAAAAAAAAFF3oPhB0oSxY3h5BmiszWNGktjysKAxcPliXCS0aGa3AQAAADDXIVGUZuenxgaR919Jc0lUvuAv22cA3X8CoZ3pcszbCQAAABGvnP1brRrkewAAAAA="),
OperationMetadata: types.OperationMetadata{ContractType: "RBACTimelock", Tags: op1Tags},
AdditionalFields: marshalAdditionalFields(s.T(), solanasdk.AdditionalFields{
Accounts: []*solana.AccountMeta{
{PublicKey: operation1BypasserPDA, IsWritable: true},
{PublicKey: configPDA},
{PublicKey: bypasserAC},
{PublicKey: mcmSignerPDA, IsWritable: true},
{PublicKey: solana.SystemProgramID},
},
}),
}}).
AddOperation(types.Operation{ChainSelector: s.ChainSelector, Transaction: types.Transaction{
// op1: finalize timelock operation instruction
To: s.TimelockProgramID.String(),
Data: base64Decode(s.T(), "LTfGM3wYqfp0ZXN0LXRpbWVsb2NrY29udmVydGVyAAAAAAAAAAAAAFF3oPhB0oSxY3h5BmiszWNGktjysKAxcPliXCS0aGa3"),
OperationMetadata: types.OperationMetadata{ContractType: "RBACTimelock", Tags: op1Tags},
AdditionalFields: marshalAdditionalFields(s.T(), solanasdk.AdditionalFields{
Accounts: []*solana.AccountMeta{
{PublicKey: operation1BypasserPDA, IsWritable: true},
{PublicKey: configPDA},
{PublicKey: bypasserAC},
{PublicKey: mcmSignerPDA, IsWritable: true},
},
}),
}}).
AddOperation(types.Operation{ChainSelector: s.ChainSelector, Transaction: types.Transaction{
// op1: bypass operation instruction
To: s.TimelockProgramID.String(),
Data: base64Decode(s.T(), "Wj5CBuOuHsJ0ZXN0LXRpbWVsb2NrY29udmVydGVyAAAAAAAAAAAAAFF3oPhB0oSxY3h5BmiszWNGktjysKAxcPliXCS0aGa3"),
OperationMetadata: types.OperationMetadata{ContractType: "RBACTimelock", Tags: op1Tags},
AdditionalFields: marshalAdditionalFields(s.T(), solanasdk.AdditionalFields{
Accounts: []*solana.AccountMeta{
{PublicKey: operation1PDA, IsWritable: true},
{PublicKey: operation1BypasserPDA, IsWritable: true},
{PublicKey: configPDA},
{PublicKey: timelockSignerPDA},
{PublicKey: s.Roles[timelock.Bypasser_Role].AccessController.PublicKey()},
{PublicKey: bypasserAC},
{PublicKey: mcmSignerPDA, IsWritable: true},
},
}),
}}).
AddOperation(types.Operation{ChainSelector: s.ChainSelector, Transaction: types.Transaction{
// op2: initialize operation instruction
To: s.TimelockProgramID.String(),
Data: base64Decode(s.T(), "OhswzBPFPxp0ZXN0LXRpbWVsb2NrY29udmVydGVyAAAAAAAAAAAAAPO0prTM++8wUEx0AL0HXcJXgMEiCBuEpqYz3RUsVyR2ekMrgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAA"),
OperationMetadata: types.OperationMetadata{ContractType: "RBACTimelock", Tags: op2Tags},
AdditionalFields: marshalAdditionalFields(s.T(), solanasdk.AdditionalFields{
Accounts: []*solana.AccountMeta{
{PublicKey: operation2BypasserPDA, IsWritable: true},
{PublicKey: configPDA},
{PublicKey: bypasserAC},
{PublicKey: mcmSignerPDA, IsWritable: true},
{PublicKey: solana.SystemProgramID},
},
}),
}}).
AddOperation(types.Operation{ChainSelector: s.ChainSelector, Transaction: types.Transaction{
// op2: append 1st timelock instruction ("account_mut" call)
To: s.TimelockProgramID.String(),
Data: base64Decode(s.T(), "f0QI0mrVGdd0ZXN0LXRpbWVsb2NrY29udmVydGVyAAAAAAAAAAAAAPO0prTM++8wUEx0AL0HXcJXgMEiCBuEpqYz3RUsVyR2AQAAADDXIVGUZuenxgaR919Jc0lUvuAv22cA3X8CoZ3pcszbCAAAAAwCiRMW65BGAwAAAG+BM3O9T0AnAD/J5GCl4se4KfoU9I+VFCQqLlubQc6KAAHEha3I7pMr6u9/2xPWDvyhZY1i0Q2PkRqRzJODZIak+gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="),
OperationMetadata: types.OperationMetadata{ContractType: "RBACTimelock", Tags: op2Tags},
AdditionalFields: marshalAdditionalFields(s.T(), solanasdk.AdditionalFields{
Accounts: []*solana.AccountMeta{
{PublicKey: operation2BypasserPDA, IsWritable: true},
{PublicKey: configPDA},
{PublicKey: bypasserAC},
{PublicKey: mcmSignerPDA, IsWritable: true},
{PublicKey: solana.SystemProgramID},
},
}),
}}).
AddOperation(types.Operation{ChainSelector: s.ChainSelector, Transaction: types.Transaction{
// op2: finalize timelock operation instruction
To: s.TimelockProgramID.String(),
Data: base64Decode(s.T(), "LTfGM3wYqfp0ZXN0LXRpbWVsb2NrY29udmVydGVyAAAAAAAAAAAAAPO0prTM++8wUEx0AL0HXcJXgMEiCBuEpqYz3RUsVyR2"),
OperationMetadata: types.OperationMetadata{ContractType: "RBACTimelock", Tags: op2Tags},
AdditionalFields: marshalAdditionalFields(s.T(), solanasdk.AdditionalFields{
Accounts: []*solana.AccountMeta{
{PublicKey: operation2BypasserPDA, IsWritable: true},
{PublicKey: configPDA},
{PublicKey: bypasserAC},
{PublicKey: mcmSignerPDA, IsWritable: true},
},
}),
Expand All @@ -360,10 +470,10 @@ func (s *SolanaTestSuite) Test_TimelockConverter() {
OperationMetadata: types.OperationMetadata{ContractType: "RBACTimelock", Tags: op2Tags},
AdditionalFields: marshalAdditionalFields(s.T(), solanasdk.AdditionalFields{
Accounts: []*solana.AccountMeta{
{PublicKey: operation2PDA, IsWritable: true},
{PublicKey: operation2BypasserPDA, IsWritable: true},
{PublicKey: configPDA},
{PublicKey: timelockSignerPDA},
{PublicKey: s.Roles[timelock.Bypasser_Role].AccessController.PublicKey()},
{PublicKey: bypasserAC},
{PublicKey: mcmSignerPDA, IsWritable: true},
},
}),
Expand Down
6 changes: 6 additions & 0 deletions sdk/solana/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ func FindTimelockOperationPDA(
return findPDA(programID, seeds)
}

func FindTimelockBypasserOperationPDA(
programID solana.PublicKey, timelockID PDASeed, opID [32]byte) (solana.PublicKey, error) {
seeds := [][]byte{[]byte("timelock_bypasser_operation"), timelockID[:], opID[:]}
return findPDA(programID, seeds)
}

func FindTimelockSignerPDA(
programID solana.PublicKey, timelockID PDASeed) (solana.PublicKey, error) {
seeds := [][]byte{[]byte("timelock_signer"), timelockID[:]}
Expand Down
7 changes: 7 additions & 0 deletions sdk/solana/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ func Test_FindTimelockOperationPDA(t *testing.T) {
require.Empty(t, cmp.Diff(pda, solana.MustPublicKeyFromBase58("9kmDgWeckKVoW44YEp4MByUJXxxwjjxK52o1HyqSPTru")))
}

func Test_FindTimelockBypasserOperationPDA(t *testing.T) {
t.Parallel()
pda, err := FindTimelockBypasserOperationPDA(testTimelockProgramID, testPDASeed, testOpID)
require.NoError(t, err)
require.Empty(t, cmp.Diff(pda, solana.MustPublicKeyFromBase58("5mDicsfmjcDDUuaMkrBvWVf9fgDGmA9ahUdebSAM1Aid")))
}

func Test_FindTimelockSignerPDA(t *testing.T) {
t.Parallel()
pda, err := FindTimelockSignerPDA(testTimelockProgramID, testPDASeed)
Expand Down
58 changes: 56 additions & 2 deletions sdk/solana/timelock_converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ func (t *TimelockConverter) ConvertBatchToChainOperations(
if err != nil {
return []types.Operation{}, common.Hash{}, fmt.Errorf("unable to find timelock operation pda: %w", err)
}
operationBypasserPDA, err := FindTimelockBypasserOperationPDA(timelockProgramID, timelockPDASeed, operationID)
if err != nil {
return []types.Operation{}, common.Hash{}, fmt.Errorf("unable to find timelock bypasser operation pda: %w", err)
}
configPDA, err := FindTimelockConfigPDA(timelockProgramID, timelockPDASeed)
if err != nil {
return []types.Operation{}, common.Hash{}, fmt.Errorf("unable to find timelock config pda: %w", err)
Expand Down Expand Up @@ -94,7 +98,7 @@ func (t *TimelockConverter) ConvertBatchToChainOperations(
operationPDA, configPDA, mcmSignerPDA)
case types.TimelockActionBypass:
instructions, err = bypassInstructions(timelockPDASeed, operationID, config.BypasserRoleAccessController,
operationPDA, configPDA, signerPDA, mcmSignerPDA)
operationBypasserPDA, configPDA, signerPDA, mcmSignerPDA, salt, uint32(len(batchOp.Transactions)), instructionsData) //nolint:gosec
default:
err = fmt.Errorf("invalid timelock operation: %s", string(action))
}
Expand Down Expand Up @@ -309,14 +313,64 @@ func cancelInstructions(
func bypassInstructions(
pdaSeed PDASeed, operationID [32]byte, bypassAccessController, operationPDA, configPDA, signerPDA,
mcmSignerPDA solana.PublicKey,
salt [32]byte,
numInstructions uint32, instructionsData []bindings.InstructionData,
) ([]solana.Instruction, error) {
instructions := make([]solana.Instruction, 0, numInstructions)
initOpIx, ioErr := bindings.NewInitializeBypasserOperationInstruction(
pdaSeed,
operationID,
salt,
numInstructions,
operationPDA,
configPDA,
bypassAccessController,
mcmSignerPDA,
solana.SystemProgramID,
).ValidateAndBuild()
if ioErr != nil {
return nil, fmt.Errorf("failed to build initialize bypasser operation instruction: %w", ioErr)
}
instructions = append(instructions, initOpIx)

for _, instruction := range instructionsData {
appendIxsIx, apErr := bindings.NewAppendBypasserInstructionsInstruction(
pdaSeed,
operationID,
[]bindings.InstructionData{instruction}, // this should be a slice of instruction within 1232 bytes
operationPDA,
configPDA,
bypassAccessController,
mcmSignerPDA,
solana.SystemProgramID, // for reallocation
).ValidateAndBuild()
if apErr != nil {
return nil, fmt.Errorf("failed to build append bypasser instructions instruction: %w", apErr)
}
instructions = append(instructions, appendIxsIx)
}

finOpIx, foErr := bindings.NewFinalizeBypasserOperationInstruction(
pdaSeed,
operationID,
operationPDA,
configPDA,
bypassAccessController,
mcmSignerPDA,
).ValidateAndBuild()
if foErr != nil {
return nil, fmt.Errorf("failed to build finalize bypasser operation instruction: %w", foErr)
}
instructions = append(instructions, finOpIx)

instruction, err := bindings.NewBypasserExecuteBatchInstruction(pdaSeed, operationID, operationPDA,
configPDA, signerPDA, bypassAccessController, mcmSignerPDA).ValidateAndBuild()
if err != nil {
return []solana.Instruction{}, fmt.Errorf("unable to build BypasserExecuteBatch instruction: %w", err)
}
instructions = append(instructions, instruction)

return []solana.Instruction{instruction}, nil
return instructions, nil
}

// https://dev.to/chigbeef_77/bool-int-but-stupid-in-go-3jb3
Expand Down
86 changes: 83 additions & 3 deletions sdk/solana/timelock_converter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ func Test_TimelockConverter_ConvertBatchToChainOperations(t *testing.T) {
proposerAC, err := solana.NewRandomPrivateKey()
require.NoError(t, err)

bypasserAC, err := solana.NewRandomPrivateKey()
require.NoError(t, err)

tests := []struct {
name string
batchOp types.BatchOperation
Expand Down Expand Up @@ -253,17 +256,92 @@ func Test_TimelockConverter_ConvertBatchToChainOperations(t *testing.T) {
predecessor: common.Hash{},
salt: defaultSalt,
wantOperations: []types.Operation{
{
// initialize
ChainSelector: chaintest.Chain4Selector,
Transaction: types.Transaction{
To: testTimelockProgramID.String(),
Data: base64Decode(t, "OhswzBPFPxp0ZXN0LW1jbQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOzNziC5jaIAHmroyBw0o6rhzkqnV4l5BvFaLyVxMtx/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAECAAAA"),
AdditionalFields: toJSON(t, AdditionalFields{Accounts: []*solana.AccountMeta{
{PublicKey: solana.MPK("5kA68ZDhLguQqxoEraVvdSYzR43JddUZXEm8SCdCEQfh"), IsWritable: true},
{PublicKey: solana.MPK("GYWcPzXkdzY9DJLcbFs67phqyYzmJxeEKSTtqEoo8oKz")},
{PublicKey: solana.MPK(bypasserAC.PublicKey().String())},
{PublicKey: solana.MPK("62gDM6BRLf2w1yXfmpePUTsuvbeBbu4QqdjV32wcc4UG"), IsWritable: true},
{PublicKey: solana.MPK("11111111111111111111111111111111")},
}}),
OperationMetadata: types.OperationMetadata{
ContractType: "RBACTimelock",
Tags: []string{"tag1.1", "tag1.2", "tag2.1", "tag2.2"},
},
},
},
{
// append first operation
ChainSelector: chaintest.Chain4Selector,
Transaction: types.Transaction{
To: testTimelockProgramID.String(),
Data: base64Decode(t, "f0QI0mrVGdd0ZXN0LW1jbQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOzNziC5jaIAHmroyBw0o6rhzkqnV4l5BvFaLyVxMtx/AQAAAOy/SwEm9OHsR3Iyhg37tMCACi9OJO1mbYf2EdbL8BdlBgAAADB4MTIzNAIAAABzrkiHQ+JGjN94Ifr0hyI7xbfT2AUTMNwqcY6ldOvyZQEBkKcZjjIczPUeb2jNRtBAfOQA/tDFWu7x9HDKmqHFfGAAAQ=="),
AdditionalFields: toJSON(t, AdditionalFields{Accounts: []*solana.AccountMeta{
{PublicKey: solana.MPK("5kA68ZDhLguQqxoEraVvdSYzR43JddUZXEm8SCdCEQfh"), IsWritable: true},
{PublicKey: solana.MPK("GYWcPzXkdzY9DJLcbFs67phqyYzmJxeEKSTtqEoo8oKz")},
{PublicKey: solana.MPK(bypasserAC.PublicKey().String())},
{PublicKey: solana.MPK("62gDM6BRLf2w1yXfmpePUTsuvbeBbu4QqdjV32wcc4UG"), IsWritable: true},
{PublicKey: solana.MPK("11111111111111111111111111111111")},
}}),
OperationMetadata: types.OperationMetadata{
ContractType: "RBACTimelock",
Tags: []string{"tag1.1", "tag1.2", "tag2.1", "tag2.2"},
},
},
},
{
// append second operation
ChainSelector: chaintest.Chain4Selector,
Transaction: types.Transaction{
To: testTimelockProgramID.String(),
Data: base64Decode(t, "f0QI0mrVGdd0ZXN0LW1jbQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOzNziC5jaIAHmroyBw0o6rhzkqnV4l5BvFaLyVxMtx/AQAAAA0THF/kMtia7NQl9/Z+bKF0Ggj7DNa/3WxLGpQ1QAaIBgAAADB4NTY3OAAAAAA="),
AdditionalFields: toJSON(t, AdditionalFields{Accounts: []*solana.AccountMeta{
{PublicKey: solana.MPK("5kA68ZDhLguQqxoEraVvdSYzR43JddUZXEm8SCdCEQfh"), IsWritable: true},
{PublicKey: solana.MPK("GYWcPzXkdzY9DJLcbFs67phqyYzmJxeEKSTtqEoo8oKz")},
{PublicKey: solana.MPK(bypasserAC.PublicKey().String())},
{PublicKey: solana.MPK("62gDM6BRLf2w1yXfmpePUTsuvbeBbu4QqdjV32wcc4UG"), IsWritable: true},
{PublicKey: solana.MPK("11111111111111111111111111111111")},
}}),
OperationMetadata: types.OperationMetadata{
ContractType: "RBACTimelock",
Tags: []string{"tag1.1", "tag1.2", "tag2.1", "tag2.2"},
},
},
},
{
// finalize
ChainSelector: chaintest.Chain4Selector,
Transaction: types.Transaction{
To: testTimelockProgramID.String(),
Data: base64Decode(t, "LTfGM3wYqfp0ZXN0LW1jbQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOzNziC5jaIAHmroyBw0o6rhzkqnV4l5BvFaLyVxMtx/"),
AdditionalFields: toJSON(t, AdditionalFields{Accounts: []*solana.AccountMeta{
{PublicKey: solana.MPK("5kA68ZDhLguQqxoEraVvdSYzR43JddUZXEm8SCdCEQfh"), IsWritable: true},
{PublicKey: solana.MPK("GYWcPzXkdzY9DJLcbFs67phqyYzmJxeEKSTtqEoo8oKz")},
{PublicKey: solana.MPK(bypasserAC.PublicKey().String())},
{PublicKey: solana.MPK("62gDM6BRLf2w1yXfmpePUTsuvbeBbu4QqdjV32wcc4UG"), IsWritable: true},
}}),
OperationMetadata: types.OperationMetadata{
ContractType: "RBACTimelock",
Tags: []string{"tag1.1", "tag1.2", "tag2.1", "tag2.2"},
},
},
},
{
// schedule batch
ChainSelector: chaintest.Chain4Selector,
Transaction: types.Transaction{
To: testTimelockProgramID.String(),
Data: base64Decode(t, "Wj5CBuOuHsJ0ZXN0LW1jbQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOzNziC5jaIAHmroyBw0o6rhzkqnV4l5BvFaLyVxMtx/"),
AdditionalFields: toJSON(t, AdditionalFields{Accounts: []*solana.AccountMeta{
{PublicKey: solana.MPK("3x12f1G4bt9j7rsBfLE7rZQ5hXoHuHdjtUr2UKW8gjQp"), IsWritable: true},
{PublicKey: solana.MPK("5kA68ZDhLguQqxoEraVvdSYzR43JddUZXEm8SCdCEQfh"), IsWritable: true},
{PublicKey: solana.MPK("GYWcPzXkdzY9DJLcbFs67phqyYzmJxeEKSTtqEoo8oKz")},
{PublicKey: solana.MPK("2g4vS5Y9g5FKoBakfNTEQcoyuPxuqgiXhribGxE1Vrsb")},
{PublicKey: solana.MPK("11111111111111111111111111111111")},
{PublicKey: solana.MPK(bypasserAC.PublicKey().String())},
{PublicKey: solana.MPK("62gDM6BRLf2w1yXfmpePUTsuvbeBbu4QqdjV32wcc4UG"), IsWritable: true},
}}),
OperationMetadata: types.OperationMetadata{
Expand All @@ -276,7 +354,9 @@ func Test_TimelockConverter_ConvertBatchToChainOperations(t *testing.T) {
wantPredecessor: common.HexToHash("0xeccdce20b98da2001e6ae8c81c34a3aae1ce4aa757897906f15a2f257132dc7f"),
setup: func(t *testing.T, mockJSONRPCClient *mocks.JSONRPCClient) {
t.Helper()
config := &bindings.Config{}
config := &bindings.Config{
BypasserRoleAccessController: bypasserAC.PublicKey(),
}
mockGetAccountInfo(t, mockJSONRPCClient, configPDA, config, nil)
},
},
Expand Down

0 comments on commit 671cf97

Please sign in to comment.