From 94dd62e14c2eddfc2bf44c10352dced24a43a50c Mon Sep 17 00:00:00 2001 From: jeffyanta Date: Fri, 15 May 2026 12:00:32 -0400 Subject: [PATCH] Use memo v2 program for VM deposits --- ocp/worker/geyser/external_deposit.go | 6 ++-- solana/memov2/program.go | 41 +++++++++++++++++++++++++++ solana/memov2/program_test.go | 38 +++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 solana/memov2/program.go create mode 100644 solana/memov2/program_test.go diff --git a/ocp/worker/geyser/external_deposit.go b/ocp/worker/geyser/external_deposit.go index fff10f0..ad14bbf 100644 --- a/ocp/worker/geyser/external_deposit.go +++ b/ocp/worker/geyser/external_deposit.go @@ -31,7 +31,7 @@ import ( "github.com/code-payments/ocp-server/solana" compute_budget "github.com/code-payments/ocp-server/solana/computebudget" "github.com/code-payments/ocp-server/solana/currencycreator" - "github.com/code-payments/ocp-server/solana/memo" + "github.com/code-payments/ocp-server/solana/memov2" "github.com/code-payments/ocp-server/solana/vm" ) @@ -117,9 +117,9 @@ func initiateExternalDepositIntoVm(ctx context.Context, data ocp_data.Provider, // Do not close the VM deposit ATA, since the real-time handler won't pick it up txn := solana.NewLegacyTransaction( vmConfig.Authority.PublicKey().ToBytes(), - memo.Instruction(codeVmDepositMemoValue), + memov2.Instruction(codeVmDepositMemoValue), compute_budget.SetComputeUnitPrice(10_000), - compute_budget.SetComputeUnitLimit(40_000), + compute_budget.SetComputeUnitLimit(45_000), vm.NewDepositFromPdaInstruction( &vm.DepositFromPdaInstructionAccounts{ VmAuthority: vmConfig.Authority.PublicKey().ToBytes(), diff --git a/solana/memov2/program.go b/solana/memov2/program.go new file mode 100644 index 0000000..662b7d2 --- /dev/null +++ b/solana/memov2/program.go @@ -0,0 +1,41 @@ +package memov2 + +import ( + "bytes" + "crypto/ed25519" + + "github.com/pkg/errors" + + "github.com/code-payments/ocp-server/solana" +) + +// ProgramKey is the address of the v2 memo program. +// +// Current key: MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr +var ProgramKey = ed25519.PublicKey{5, 74, 83, 90, 153, 41, 33, 6, 77, 36, 232, 113, 96, 218, 56, 124, 124, 53, 181, 221, 188, 146, 187, 129, 228, 31, 168, 64, 65, 5, 68, 141} + +// Reference: https://github.com/solana-program/memo +func Instruction(data string) solana.Instruction { + return solana.NewInstruction( + ProgramKey, + []byte(data), + ) +} + +type DecompiledMemo struct { + Data []byte +} + +func DecompileMemo(m solana.Message, index int) (*DecompiledMemo, error) { + if index >= len(m.Instructions) { + return nil, errors.Errorf("instruction doesn't exist at %d", index) + } + + i := m.Instructions[index] + + if !bytes.Equal(m.Accounts[i.ProgramIndex], ProgramKey) { + return nil, solana.ErrIncorrectProgram + } + + return &DecompiledMemo{Data: i.Data}, nil +} diff --git a/solana/memov2/program_test.go b/solana/memov2/program_test.go new file mode 100644 index 0000000..fd037c2 --- /dev/null +++ b/solana/memov2/program_test.go @@ -0,0 +1,38 @@ +package memov2 + +import ( + "crypto/ed25519" + "testing" + + "github.com/code-payments/ocp-server/solana" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestInstruction(t *testing.T) { + i := Instruction("hello, world!") + assert.Equal(t, ProgramKey, i.Program) + assert.Empty(t, i.Accounts) + assert.Equal(t, "hello, world!", string(i.Data)) +} + +func TestDecompile(t *testing.T) { + tx := solana.NewLegacyTransaction( + make([]byte, 32), + Instruction("hello, world"), + ) + + i, err := DecompileMemo(tx.Message, 0) + assert.NoError(t, err) + assert.Equal(t, "hello, world", string(i.Data)) + + _, err = DecompileMemo(tx.Message, 1) + assert.Error(t, err) + assert.Contains(t, err.Error(), "instruction doesn't exist") + + tx.Message.Accounts[1], _, err = ed25519.GenerateKey(nil) + require.NoError(t, err) + _, err = DecompileMemo(tx.Message, 0) + assert.Error(t, err) + assert.Equal(t, solana.ErrIncorrectProgram, err) +}