diff --git a/solana/indexer/program/claimable_tokens_test.go b/solana/indexer/program/claimable_tokens_test.go new file mode 100644 index 00000000..4ed33d62 --- /dev/null +++ b/solana/indexer/program/claimable_tokens_test.go @@ -0,0 +1,47 @@ +package program + +import ( + "testing" + + "api.audius.co/solana/spl/programs/claimable_tokens" + "github.com/gagliardetto/solana-go" + "github.com/test-go/testify/require" + "go.uber.org/zap" +) + +func TestProcessClaimableTokensSetAuthority(t *testing.T) { + accountKeys := solana.PublicKeySlice{ + solana.MustPublicKeyFromBase58("8teuqGNB7RhwC2JoDT961J3jStBfXeu4nRxyubu36Kpe"), + solana.MustPublicKeyFromBase58("5ZiE3vAkrdXBgyFL7KqG3RoEGBws4CjRcXVbABDLZTgx"), + solana.SysVarInstructionsPubkey, + solana.SysVarRecentBlockHashesPubkey, + solana.TokenProgramID, + claimable_tokens.ProgramID, + } + instruction := solana.CompiledInstruction{ + ProgramIDIndex: 5, + Accounts: []uint16{0, 1, 2, 3, 4}, + Data: solana.Base58{claimable_tokens.Instruction_SetAuthority}, + } + tx := &solana.Transaction{ + Message: solana.Message{ + AccountKeys: accountKeys, + Header: solana.MessageHeader{ + NumReadonlyUnsignedAccounts: 5, + }, + Instructions: []solana.CompiledInstruction{{}, instruction}, + }, + } + + err := processClaimableTokensInstruction( + t.Context(), + nil, + 449737686, + tx, + 1, + instruction, + "2RuRg4MCAJHF5dQifhGzkZ6qD7XQGbGop4Z48fxgweHawi5FNKiwiTVYwfQ7hzgU1MgJkjaKV7SWumr8ztGa98cf", + zap.NewNop(), + ) + require.NoError(t, err) +} diff --git a/solana/spl/programs/claimable_tokens/SetAuthority.go b/solana/spl/programs/claimable_tokens/SetAuthority.go new file mode 100644 index 00000000..b9409165 --- /dev/null +++ b/solana/spl/programs/claimable_tokens/SetAuthority.go @@ -0,0 +1,15 @@ +package claimable_tokens + +import "github.com/gagliardetto/solana-go" + +// SetAuthority has no instruction data beyond its variant discriminator. +// The signed SPL Token set-authority payload is carried by the preceding +// secp256k1 instruction. +type SetAuthority struct { + solana.AccountMetaSlice `bin:"-" borsh_skip:"true"` +} + +var ( + _ solana.AccountsGettable = (*SetAuthority)(nil) + _ solana.AccountsSettable = (*SetAuthority)(nil) +) diff --git a/solana/spl/programs/claimable_tokens/instruction.go b/solana/spl/programs/claimable_tokens/instruction.go index a1101274..13fcc26e 100644 --- a/solana/spl/programs/claimable_tokens/instruction.go +++ b/solana/spl/programs/claimable_tokens/instruction.go @@ -118,6 +118,12 @@ var InstructionImplDef = bin.NewVariantDefinition( { Name: "Transfer", Type: (*Transfer)(nil), }, + { + Name: "SetAuthority", Type: (*SetAuthority)(nil), + }, + { + Name: "Close", Type: (*Close)(nil), + }, }, ) diff --git a/solana/spl/programs/claimable_tokens/instruction_test.go b/solana/spl/programs/claimable_tokens/instruction_test.go index a06a8506..d1d56749 100644 --- a/solana/spl/programs/claimable_tokens/instruction_test.go +++ b/solana/spl/programs/claimable_tokens/instruction_test.go @@ -4,6 +4,7 @@ import ( "testing" "api.audius.co/solana/spl/programs/claimable_tokens" + "github.com/ethereum/go-ethereum/common" "github.com/gagliardetto/solana-go" "github.com/test-go/testify/assert" "github.com/test-go/testify/require" @@ -31,3 +32,40 @@ func TestDecodeInstruction(t *testing.T) { claimable_tokens.SetProgramID(originalProgramId) } + +func TestDecodeSetAuthorityInstruction(t *testing.T) { + // Real tx: 2RuRg4MCAJHF5dQifhGzkZ6qD7XQGbGop4Z48fxgweHawi5FNKiwiTVYwfQ7hzgU1MgJkjaKV7SWumr8ztGa98cf + accounts := []*solana.AccountMeta{ + solana.Meta(solana.MustPublicKeyFromBase58("8teuqGNB7RhwC2JoDT961J3jStBfXeu4nRxyubu36Kpe")).WRITE(), + solana.Meta(solana.MustPublicKeyFromBase58("5ZiE3vAkrdXBgyFL7KqG3RoEGBws4CjRcXVbABDLZTgx")), + solana.Meta(solana.SysVarInstructionsPubkey), + solana.Meta(solana.SysVarRecentBlockHashesPubkey), + solana.Meta(solana.TokenProgramID), + } + + decoded, err := claimable_tokens.DecodeInstruction( + accounts, + []byte{claimable_tokens.Instruction_SetAuthority}, + ) + require.NoError(t, err) + require.IsType(t, &claimable_tokens.SetAuthority{}, decoded.Impl) + assert.Equal(t, accounts, decoded.Accounts()) +} + +func TestDecodeCloseInstruction(t *testing.T) { + ethAddress := common.HexToAddress("0x65b2681094e762CAD2349e6C1e2FbC8d54b9c046") + accounts := []*solana.AccountMeta{ + solana.Meta(solana.NewWallet().PublicKey()).WRITE(), + solana.Meta(solana.NewWallet().PublicKey()), + solana.Meta(solana.NewWallet().PublicKey()).WRITE(), + solana.Meta(solana.TokenProgramID), + } + data := append([]byte{claimable_tokens.Instruction_Close}, ethAddress.Bytes()...) + + decoded, err := claimable_tokens.DecodeInstruction(accounts, data) + require.NoError(t, err) + closeInstruction, ok := decoded.Impl.(*claimable_tokens.Close) + require.True(t, ok) + assert.Equal(t, ethAddress, closeInstruction.EthAddress) + assert.Equal(t, accounts, decoded.Accounts()) +}