From 8aac401d807465438a28e62acf6c2ea8bd10290d Mon Sep 17 00:00:00 2001 From: Marcus Pasell <3690498+rickyrombo@users.noreply.github.com> Date: Tue, 22 Apr 2025 14:15:31 -0700 Subject: [PATCH 1/3] Add tests, fixed unmarshal --- .../secp256k1/Secp256k1Instruction.go | 2 +- .../secp256k1/Secp256k1Instruction_test.go | 79 +++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 api/solana/programs/secp256k1/Secp256k1Instruction_test.go diff --git a/api/solana/programs/secp256k1/Secp256k1Instruction.go b/api/solana/programs/secp256k1/Secp256k1Instruction.go index d178f495..64a54ad8 100644 --- a/api/solana/programs/secp256k1/Secp256k1Instruction.go +++ b/api/solana/programs/secp256k1/Secp256k1Instruction.go @@ -128,7 +128,7 @@ func (obj *Secp256k1Instruction) UnmarshalWithDecoder(decoder *ag_binary.Decoder if err != nil { return err } - signature, err := decoder.ReadBytes(int(offsets.MessageDataOffset) - int(offsets.SignatureOffset) - 1) + signature, err := decoder.ReadBytes(int(offsets.MessageDataOffset) - int(offsets.SignatureOffset)) if err != nil { return err } diff --git a/api/solana/programs/secp256k1/Secp256k1Instruction_test.go b/api/solana/programs/secp256k1/Secp256k1Instruction_test.go new file mode 100644 index 00000000..b71f812f --- /dev/null +++ b/api/solana/programs/secp256k1/Secp256k1Instruction_test.go @@ -0,0 +1,79 @@ +package secp256k1_test + +import ( + "encoding/hex" + "testing" + + "bridgerton.audius.co/api/solana/programs/secp256k1" + "github.com/ethereum/go-ethereum/crypto" + bin "github.com/gagliardetto/binary" + "github.com/gagliardetto/solana-go" + "github.com/stretchr/testify/require" +) + +func TestSecp256k1Instruction(t *testing.T) { + // Expected results + ethAddress, err := hex.DecodeString("8fcfa10bd3808570987dbb5b1ef4ab74400fbfda") + require.NoError(t, err) + message, err := hex.DecodeString("68d5397bb16195ea47091010f3abb8fc6b5cdfa65f00e1f505000000005f623a33383639383d3e3530373431303135335f00b6462e955da5841b6d9e1e2529b830f00f31bf") + require.NoError(t, err) + signature, err := hex.DecodeString("f89b2e6f97f95f1306b468b10b1a18df9569b07d9d7b81b241d6fc99d9ec782e4e449f5c3c63836ed52c9344d3de5c3133fead711e421af545822f09bd78cb3900") + require.NoError(t, err) + + // Test data (taken from Secp256k1Program.test.ts) + expectedData, _ := hex.DecodeString("012000000c000061004500008fcfa10bd3808570987dbb5b1ef4ab74400fbfdaf89b2e6f97f95f1306b468b10b1a18df9569b07d9d7b81b241d6fc99d9ec782e4e449f5c3c63836ed52c9344d3de5c3133fead711e421af545822f09bd78cb390068d5397bb16195ea47091010f3abb8fc6b5cdfa65f00e1f505000000005f623a33383639383d3e3530373431303135335f00b6462e955da5841b6d9e1e2529b830f00f31bf") + + ix := secp256k1.NewSecp256k1Instruction(ethAddress, message, signature, 0).Build() + data, err := ix.Data() + + require.Equal(t, solana.Secp256k1ProgramID, ix.ProgramID()) + require.Len(t, ix.Accounts(), 0) + require.NoError(t, err) + require.Equal(t, expectedData, data) +} + +func TestUnmarshal(t *testing.T) { + // Expected results + ethAddress, err := hex.DecodeString("00b6462e955da5841b6d9e1e2529b830f00f31bf") + require.NoError(t, err) + message, err := hex.DecodeString("00ab2f814a75e9bb778ccbb998a028bb9b8a1ce1bc5f0065cd1d000000005f623a39636537613a3261633834376538") + require.NoError(t, err) + signature, err := hex.DecodeString("559ec22babe96e7d9ed0b40fd908a8da7049209cce80da05c46b4ed4b2ac996a16962d4d9b910f0bc536ee4bfe254a52cda3612f4e505ebacf8b0ea8869f6d4400") + require.NoError(t, err) + instrIndex := uint8(0) + + // Test data + data, err := hex.DecodeString("012000000c000061002f000000b6462e955da5841b6d9e1e2529b830f00f31bf559ec22babe96e7d9ed0b40fd908a8da7049209cce80da05c46b4ed4b2ac996a16962d4d9b910f0bc536ee4bfe254a52cda3612f4e505ebacf8b0ea8869f6d440000ab2f814a75e9bb778ccbb998a028bb9b8a1ce1bc5f0065cd1d000000005f623a39636537613a3261633834376538") + require.NoError(t, err) + + ix := secp256k1.NewSecp256k1InstructionBuilder() + decoder := bin.NewBorshDecoder(data) + ix.UnmarshalWithDecoder(decoder) + + require.Len(t, ix.SignatureDatas, 1) + require.Equal(t, ethAddress, ix.SignatureDatas[0].EthAddress) + require.Equal(t, message, ix.SignatureDatas[0].Message) + require.Equal(t, signature, ix.SignatureDatas[0].Signature) + require.Equal(t, instrIndex, ix.SignatureDatas[0].InstructionIndex) +} + +func TestUnmarshalVerifySignature(t *testing.T) { + // Test data + data, err := hex.DecodeString("012000000c0000610029000000b6462e955da5841b6d9e1e2529b830f00f31bf0b9e26079eabfde8da3ed9e3aa1d9a18d272bf50a11bc45ada709c9570b7b7825630f512be7673ff92cbdb5494b7e7890365d0eed04f46fc14b197dbf2f5529e0177afbe5f6e6d0b95e6b35ba205df8fbbf26f1d1f5f00c2eb0b000000005f66743a3162616561663731") + require.NoError(t, err) + + ix := secp256k1.NewSecp256k1InstructionBuilder() + decoder := bin.NewBorshDecoder(data) + ix.UnmarshalWithDecoder(decoder) + + hash := crypto.Keccak256(ix.SignatureDatas[0].Message) + recoveredWallet, err := crypto.SigToPub(hash, ix.SignatureDatas[0].Signature) + + require.NoError(t, err) + require.Equal( + t, + ix.SignatureDatas[0].EthAddress, + crypto.PubkeyToAddress(*recoveredWallet).Bytes(), + "signature recovers to declared signer eth address", + ) +} From 2e3046b8783c872f695d4311c4916ac307613d6e Mon Sep 17 00:00:00 2001 From: Marcus Pasell <3690498+rickyrombo@users.noreply.github.com> Date: Tue, 22 Apr 2025 19:11:57 -0700 Subject: [PATCH 2/3] Add EvaluateAttestations --- .../reward-manager/EvaluateAttestations.go | 3 - .../ChangeManagerAccount.go | 0 .../CreateSender.go | 0 .../CreateSenderPublic.go | 0 .../DeleteSender.go | 0 .../DeleteSenderPublic.go | 0 .../reward_manager/EvaluateAttestations.go | 185 ++++++++++++++++++ .../EvaluateAttestations_test.go | 60 ++++++ .../Init.go | 0 .../SubmitAttestation.go | 42 +--- .../instruction.go | 44 ++++- 11 files changed, 293 insertions(+), 41 deletions(-) delete mode 100644 api/solana/programs/reward-manager/EvaluateAttestations.go rename api/solana/programs/{reward-manager => reward_manager}/ChangeManagerAccount.go (100%) rename api/solana/programs/{reward-manager => reward_manager}/CreateSender.go (100%) rename api/solana/programs/{reward-manager => reward_manager}/CreateSenderPublic.go (100%) rename api/solana/programs/{reward-manager => reward_manager}/DeleteSender.go (100%) rename api/solana/programs/{reward-manager => reward_manager}/DeleteSenderPublic.go (100%) create mode 100644 api/solana/programs/reward_manager/EvaluateAttestations.go create mode 100644 api/solana/programs/reward_manager/EvaluateAttestations_test.go rename api/solana/programs/{reward-manager => reward_manager}/Init.go (100%) rename api/solana/programs/{reward-manager => reward_manager}/SubmitAttestation.go (66%) rename api/solana/programs/{reward-manager => reward_manager}/instruction.go (60%) diff --git a/api/solana/programs/reward-manager/EvaluateAttestations.go b/api/solana/programs/reward-manager/EvaluateAttestations.go deleted file mode 100644 index 24da4ef3..00000000 --- a/api/solana/programs/reward-manager/EvaluateAttestations.go +++ /dev/null @@ -1,3 +0,0 @@ -package reward_manager - -type EvaluateAttestation struct{} diff --git a/api/solana/programs/reward-manager/ChangeManagerAccount.go b/api/solana/programs/reward_manager/ChangeManagerAccount.go similarity index 100% rename from api/solana/programs/reward-manager/ChangeManagerAccount.go rename to api/solana/programs/reward_manager/ChangeManagerAccount.go diff --git a/api/solana/programs/reward-manager/CreateSender.go b/api/solana/programs/reward_manager/CreateSender.go similarity index 100% rename from api/solana/programs/reward-manager/CreateSender.go rename to api/solana/programs/reward_manager/CreateSender.go diff --git a/api/solana/programs/reward-manager/CreateSenderPublic.go b/api/solana/programs/reward_manager/CreateSenderPublic.go similarity index 100% rename from api/solana/programs/reward-manager/CreateSenderPublic.go rename to api/solana/programs/reward_manager/CreateSenderPublic.go diff --git a/api/solana/programs/reward-manager/DeleteSender.go b/api/solana/programs/reward_manager/DeleteSender.go similarity index 100% rename from api/solana/programs/reward-manager/DeleteSender.go rename to api/solana/programs/reward_manager/DeleteSender.go diff --git a/api/solana/programs/reward-manager/DeleteSenderPublic.go b/api/solana/programs/reward_manager/DeleteSenderPublic.go similarity index 100% rename from api/solana/programs/reward-manager/DeleteSenderPublic.go rename to api/solana/programs/reward_manager/DeleteSenderPublic.go diff --git a/api/solana/programs/reward_manager/EvaluateAttestations.go b/api/solana/programs/reward_manager/EvaluateAttestations.go new file mode 100644 index 00000000..044651fd --- /dev/null +++ b/api/solana/programs/reward_manager/EvaluateAttestations.go @@ -0,0 +1,185 @@ +package reward_manager + +import ( + "encoding/hex" + "strings" + + bin "github.com/gagliardetto/binary" + "github.com/gagliardetto/solana-go" +) + +type EvaluateAttestation struct { + // Instruction Data + Amount uint64 + DisbursementID string + ReceipientEthAddress string + + // Used for derivations + RewardManagerState solana.PublicKey `bin:"-" borsh_skip:"true"` + Payer solana.PublicKey `bin:"-" borsh_skip:"true"` + DestinationUserBank solana.PublicKey `bin:"-" borsh_skip:"true"` + TokenSource solana.PublicKey `bin:"-" borsh_skip:"true"` + AntiAbuseOracleEthAddress string `bin:"-" borsh_skip:"true"` + + // Accounts + solana.AccountMetaSlice `bin:"-" borsh_skip:"true"` +} + +func NewEvaluateAttestationInstructionBuilder() *EvaluateAttestation { + data := &EvaluateAttestation{} + return data +} + +func (inst *EvaluateAttestation) SetDisbursementID(challengedId string, specifier string) *EvaluateAttestation { + inst.DisbursementID = challengedId + ":" + specifier + return inst +} + +func (inst *EvaluateAttestation) SetRecipientEthAddress(recipientEthAddress string) *EvaluateAttestation { + inst.ReceipientEthAddress = recipientEthAddress + return inst +} + +func (inst *EvaluateAttestation) SetAmount(amount uint64) *EvaluateAttestation { + inst.Amount = amount + return inst +} + +func (inst *EvaluateAttestation) SetAntiAbuseOracleEthAddress(antiAbuseOracleAddress string) *EvaluateAttestation { + inst.AntiAbuseOracleEthAddress = antiAbuseOracleAddress + return inst +} + +func (inst *EvaluateAttestation) SetRewardManagerState(state solana.PublicKey) *EvaluateAttestation { + inst.RewardManagerState = state + return inst +} + +func (inst *EvaluateAttestation) SetTokenSource(tokenSource solana.PublicKey) *EvaluateAttestation { + inst.TokenSource = tokenSource + return inst +} + +func (inst *EvaluateAttestation) SetDestinationUserBank(userBank solana.PublicKey) *EvaluateAttestation { + inst.DestinationUserBank = userBank + return inst +} + +func (inst *EvaluateAttestation) SetPayer(payer solana.PublicKey) *EvaluateAttestation { + inst.Payer = payer + return inst +} + +func (inst EvaluateAttestation) Build() *Instruction { + authority, _, _ := deriveAuthority(ProgramID, inst.RewardManagerState) + attestations, _, _ := deriveAttestations(ProgramID, authority, inst.DisbursementID) + disbursement, _, _ := deriveDisbursement(ProgramID, authority, inst.DisbursementID) + antiAbuseOracle, _, _ := deriveSender(ProgramID, authority, inst.AntiAbuseOracleEthAddress) + + inst.AccountMetaSlice = []*solana.AccountMeta{ + { + PublicKey: attestations, + IsSigner: false, + IsWritable: true, + }, + { + PublicKey: inst.RewardManagerState, + IsSigner: false, + IsWritable: false, + }, + { + PublicKey: authority, + IsSigner: false, + IsWritable: false, + }, + { + PublicKey: inst.TokenSource, + IsSigner: false, + IsWritable: true, + }, + { + PublicKey: inst.DestinationUserBank, + IsSigner: false, + IsWritable: true, + }, + { + PublicKey: disbursement, + IsSigner: false, + IsWritable: true, + }, + { + PublicKey: antiAbuseOracle, + IsSigner: false, + IsWritable: false, + }, + { + PublicKey: inst.Payer, + IsSigner: true, + IsWritable: true, + }, + { + PublicKey: solana.SysVarRentPubkey, + IsSigner: false, + IsWritable: false, + }, + { + PublicKey: solana.TokenProgramID, + IsSigner: false, + IsWritable: false, + }, + { + PublicKey: solana.SystemProgramID, + IsSigner: false, + IsWritable: false, + }, + } + + return &Instruction{BaseVariant: bin.BaseVariant{ + Impl: inst, + TypeID: bin.TypeIDFromUint8(Instruction_EvaluateAttestations), + }} +} + +func (inst EvaluateAttestation) MarshalWithEncoder(encoder *bin.Encoder) error { + err := encoder.Encode(inst.Amount) + if err != nil { + return err + } + + err = encoder.Encode(inst.DisbursementID) + if err != nil { + return err + } + + address, err := hex.DecodeString(strings.TrimPrefix(inst.ReceipientEthAddress, "0x")) + if err != nil { + return err + } + return encoder.WriteBytes(address, false) +} + +func (inst *EvaluateAttestation) UnmarshalWithDecoder(decoder *bin.Decoder) error { + return decoder.Decode(&inst) +} + +func NewEvaluateAttestationInstruction( + challengeId string, + specifier string, + recipientEthAddress string, + amount uint64, + antiAbuseOracleAddress string, + rewardManagerState solana.PublicKey, + tokenSource solana.PublicKey, + destinationUserBank solana.PublicKey, + payer solana.PublicKey, +) *EvaluateAttestation { + return NewEvaluateAttestationInstructionBuilder(). + SetRewardManagerState(rewardManagerState). + SetDisbursementID(challengeId, specifier). + SetRecipientEthAddress(recipientEthAddress). + SetAmount(amount). + SetAntiAbuseOracleEthAddress(antiAbuseOracleAddress). + SetTokenSource(tokenSource). + SetDestinationUserBank(destinationUserBank). + SetPayer(payer) +} diff --git a/api/solana/programs/reward_manager/EvaluateAttestations_test.go b/api/solana/programs/reward_manager/EvaluateAttestations_test.go new file mode 100644 index 00000000..88c58230 --- /dev/null +++ b/api/solana/programs/reward_manager/EvaluateAttestations_test.go @@ -0,0 +1,60 @@ +package reward_manager_test + +import ( + "encoding/hex" + "testing" + + "bridgerton.audius.co/api/solana/programs/reward_manager" + "github.com/gagliardetto/solana-go" + "github.com/stretchr/testify/require" +) + +func TestEvaluateAttestationsInstruction(t *testing.T) { + challengeId := "ft" + specifier := "37364e80" + recipientEthAddress := "0x3f6d9fcf0d4466dd5886e3b1def017adfb7916b4" + amount := uint64(200000000) + antiAbuseOracleEthAddress := "0x00b6462e955dA5841b6D9e1E2529B830F00f31Bf" + + // Expected Accounts + rewardState := solana.MustPublicKeyFromBase58("GaiG9LDYHfZGqeNaoGRzFEnLiwUT7WiC6sA6FDJX9ZPq") + expectedAuthority := solana.MustPublicKeyFromBase58("6mpecd6bJCpH8oDwwjqPzTPU6QacnwW3cR9pAwEwkYJa") + tokenSource := solana.MustPublicKeyFromBase58("HJQj8P47BdA7ugjQEn45LaESYrxhiZDygmukt8iumFZJ") + destinationUserBank := solana.MustPublicKeyFromBase58("Cjv8dvVfWU8wUYAR82T5oZ4nHLB6EyGNvpPBzw3r76Qy") + expectedDisbursement := solana.MustPublicKeyFromBase58("3qQfuDEBWEmxRo5G4J2a4eYUVf9u1LWzLgRPndiwew2w") + expectedOracle := solana.MustPublicKeyFromBase58("FNz5mur7EFh1LyH5HDaKyWVx7vcfGK6gRizEpDqMfgGk") + payer := solana.MustPublicKeyFromBase58("E3CfijtAJwBSHfwFEViAUd3xp7c8TBxwC1eXn1Fgxp8h") + + // Use stage program ID + stageProgramId := solana.MustPublicKeyFromBase58("CDpzvz7DfgbF95jSSCHLX3ERkugyfgn9Fw8ypNZ1hfXp") + reward_manager.SetProgramID(stageProgramId) + + inst := reward_manager.NewEvaluateAttestationInstruction( + challengeId, + specifier, + recipientEthAddress, + amount, + antiAbuseOracleEthAddress, + rewardState, + tokenSource, + destinationUserBank, + payer, + ).Build() + + require.Equal(t, stageProgramId, inst.ProgramID()) + require.Len(t, inst.Accounts(), 11) + require.Equal(t, rewardState.String(), inst.Accounts()[1].PublicKey.String()) + require.Equal(t, expectedAuthority.String(), inst.Accounts()[2].PublicKey.String()) + require.Equal(t, tokenSource.String(), inst.Accounts()[3].PublicKey.String()) + require.Equal(t, destinationUserBank.String(), inst.Accounts()[4].PublicKey.String()) + require.Equal(t, expectedDisbursement.String(), inst.Accounts()[5].PublicKey.String()) + require.Equal(t, expectedOracle.String(), inst.Accounts()[6].PublicKey.String()) + require.Equal(t, payer.String(), inst.Accounts()[7].PublicKey.String()) + + // From successful stage transaction (signature 26gT9HVMhzBDzsKcsiKREYmGcXuZhjAJpCVUu9WFNhVMyKje8SdApYc4ev3HrumZB4LEXLUaPnKyriBPLmtzwrWp) + expectedData, err := hex.DecodeString("0700c2eb0b000000000b00000066743a33373336346538303f6d9fcf0d4466dd5886e3b1def017adfb7916b4") + require.NoError(t, err) + data, err := inst.Data() + require.NoError(t, err) + require.Equal(t, expectedData, data) +} diff --git a/api/solana/programs/reward-manager/Init.go b/api/solana/programs/reward_manager/Init.go similarity index 100% rename from api/solana/programs/reward-manager/Init.go rename to api/solana/programs/reward_manager/Init.go diff --git a/api/solana/programs/reward-manager/SubmitAttestation.go b/api/solana/programs/reward_manager/SubmitAttestation.go similarity index 66% rename from api/solana/programs/reward-manager/SubmitAttestation.go rename to api/solana/programs/reward_manager/SubmitAttestation.go index 1fa0ca31..af3ddfed 100644 --- a/api/solana/programs/reward-manager/SubmitAttestation.go +++ b/api/solana/programs/reward_manager/SubmitAttestation.go @@ -1,24 +1,20 @@ package reward_manager import ( - "encoding/hex" - bin "github.com/gagliardetto/binary" "github.com/gagliardetto/solana-go" ) -const ( - SenderSeedPrefix = "S_" - EthAddressByteLength = 20 - AttestationsSeedPrefix = "V_" -) - type SubmitAttestation struct { - DisbursementID string + // Instruction Data + DisbursementID string + + // Used for derivations SenderEthAddress string `bin:"-" borsh_skip:"true"` RewardManagerState solana.PublicKey `bin:"-" borsh_skip:"true"` Payer solana.PublicKey `bin:"-" borsh_skip:"true"` + // Accounts solana.AccountMetaSlice `bin:"-" borsh_skip:"true"` } @@ -47,34 +43,6 @@ func (inst *SubmitAttestation) SetPayer(payer solana.PublicKey) *SubmitAttestati return inst } -func deriveAuthority(programId solana.PublicKey, state solana.PublicKey) (solana.PublicKey, uint8, error) { - seeds := make([][]byte, 1) - seeds[0] = state.Bytes()[0:32] - return solana.FindProgramAddress(seeds, programId) -} - -func deriveSender(programId solana.PublicKey, authority solana.PublicKey, ethAddress string) (solana.PublicKey, uint8, error) { - - senderSeedPrefix := []byte(SenderSeedPrefix) - // Remove 0x and decode hex - decodedEthAddress, err := hex.DecodeString(ethAddress[2:]) - if err != nil { - return solana.PublicKey{}, 0, err - } - // Pad the eth address if necessary w/ leading 0 - senderSeed := make([]byte, len(senderSeedPrefix)+EthAddressByteLength) - copy(senderSeed, senderSeedPrefix) - copy(senderSeed[len(senderSeed)-len(decodedEthAddress):], decodedEthAddress) - return solana.FindProgramAddress([][]byte{authority.Bytes()[0:32], senderSeed}, programId) -} - -func deriveAttestations(programId solana.PublicKey, authority solana.PublicKey, disbursementId string) (solana.PublicKey, uint8, error) { - attestationsSeed := make([]byte, len(AttestationsSeedPrefix)+len(disbursementId)) - copy(attestationsSeed, []byte(AttestationsSeedPrefix)) - copy(attestationsSeed[len([]byte(AttestationsSeedPrefix)):], disbursementId) - return solana.FindProgramAddress([][]byte{authority.Bytes()[0:32], attestationsSeed}, programId) -} - func (inst SubmitAttestation) Build() *Instruction { authority, _, _ := deriveAuthority(ProgramID, inst.RewardManagerState) sender, _, _ := deriveSender(ProgramID, authority, inst.SenderEthAddress) diff --git a/api/solana/programs/reward-manager/instruction.go b/api/solana/programs/reward_manager/instruction.go similarity index 60% rename from api/solana/programs/reward-manager/instruction.go rename to api/solana/programs/reward_manager/instruction.go index 81869fd7..fb980e69 100644 --- a/api/solana/programs/reward-manager/instruction.go +++ b/api/solana/programs/reward_manager/instruction.go @@ -2,6 +2,7 @@ package reward_manager import ( "bytes" + "encoding/hex" "fmt" bin "github.com/gagliardetto/binary" @@ -9,6 +10,13 @@ import ( ag_text "github.com/gagliardetto/solana-go/text" ) +const ( + SenderSeedPrefix = "S_" + EthAddressByteLength = 20 + AttestationsSeedPrefix = "V_" + DisbursementSeedPrefix = "T_" +) + var ProgramID = solana.MustPublicKeyFromBase58("CDpzvz7DfgbF95jSSCHLX3ERkugyfgn9Fw8ypNZ1hfXp") func SetProgramID(pubkey solana.PublicKey) { @@ -76,7 +84,7 @@ var InstructionImplDef = bin.NewVariantDefinition( Name: "SubmitAttestation", Type: (*SubmitAttestation)(nil), }, { - Name: "EvaluateAttestation", Type: (*SubmitAttestation)(nil), + Name: "EvaluateAttestation", Type: (*EvaluateAttestation)(nil), }, }, ) @@ -118,3 +126,37 @@ func DecodeInstruction(accounts []*solana.AccountMeta, data []byte) (*Instructio } return inst, nil } + +func deriveAuthority(programId solana.PublicKey, state solana.PublicKey) (solana.PublicKey, uint8, error) { + seeds := make([][]byte, 1) + seeds[0] = state.Bytes()[0:32] + return solana.FindProgramAddress(seeds, programId) +} + +func deriveSender(programId solana.PublicKey, authority solana.PublicKey, ethAddress string) (solana.PublicKey, uint8, error) { + senderSeedPrefix := []byte(SenderSeedPrefix) + // Remove 0x and decode hex + decodedEthAddress, err := hex.DecodeString(ethAddress[2:]) + if err != nil { + return solana.PublicKey{}, 0, err + } + // Pad the eth address if necessary w/ leading 0 + senderSeed := make([]byte, len(senderSeedPrefix)+EthAddressByteLength) + copy(senderSeed, senderSeedPrefix) + copy(senderSeed[len(senderSeed)-len(decodedEthAddress):], decodedEthAddress) + return solana.FindProgramAddress([][]byte{authority.Bytes()[0:32], senderSeed}, programId) +} + +func deriveAttestations(programId solana.PublicKey, authority solana.PublicKey, disbursementId string) (solana.PublicKey, uint8, error) { + attestationsSeed := make([]byte, len(AttestationsSeedPrefix)+len(disbursementId)) + copy(attestationsSeed, []byte(AttestationsSeedPrefix)) + copy(attestationsSeed[len([]byte(AttestationsSeedPrefix)):], disbursementId) + return solana.FindProgramAddress([][]byte{authority.Bytes()[0:32], attestationsSeed}, programId) +} + +func deriveDisbursement(programId solana.PublicKey, authority solana.PublicKey, disbursementId string) (solana.PublicKey, uint8, error) { + disbursementSeed := make([]byte, len(DisbursementSeedPrefix)+len(disbursementId)) + copy(disbursementSeed, []byte(DisbursementSeedPrefix)) + copy(disbursementSeed[len([]byte(DisbursementSeedPrefix)):], disbursementId) + return solana.FindProgramAddress([][]byte{authority.Bytes()[0:32], disbursementSeed}, programId) +} From ce0317494b07a8b473fc7aa4de530e9ba6f4e913 Mon Sep 17 00:00:00 2001 From: Marcus Pasell <3690498+rickyrombo@users.noreply.github.com> Date: Tue, 22 Apr 2025 19:17:44 -0700 Subject: [PATCH 3/3] clarify --- .../programs/reward_manager/EvaluateAttestations_test.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/api/solana/programs/reward_manager/EvaluateAttestations_test.go b/api/solana/programs/reward_manager/EvaluateAttestations_test.go index 88c58230..99d21827 100644 --- a/api/solana/programs/reward_manager/EvaluateAttestations_test.go +++ b/api/solana/programs/reward_manager/EvaluateAttestations_test.go @@ -10,6 +10,7 @@ import ( ) func TestEvaluateAttestationsInstruction(t *testing.T) { + // Test data challengeId := "ft" specifier := "37364e80" recipientEthAddress := "0x3f6d9fcf0d4466dd5886e3b1def017adfb7916b4" @@ -17,6 +18,7 @@ func TestEvaluateAttestationsInstruction(t *testing.T) { antiAbuseOracleEthAddress := "0x00b6462e955dA5841b6D9e1E2529B830F00f31Bf" // Expected Accounts + // From successful stage transaction (signature 26gT9HVMhzBDzsKcsiKREYmGcXuZhjAJpCVUu9WFNhVMyKje8SdApYc4ev3HrumZB4LEXLUaPnKyriBPLmtzwrWp) rewardState := solana.MustPublicKeyFromBase58("GaiG9LDYHfZGqeNaoGRzFEnLiwUT7WiC6sA6FDJX9ZPq") expectedAuthority := solana.MustPublicKeyFromBase58("6mpecd6bJCpH8oDwwjqPzTPU6QacnwW3cR9pAwEwkYJa") tokenSource := solana.MustPublicKeyFromBase58("HJQj8P47BdA7ugjQEn45LaESYrxhiZDygmukt8iumFZJ") @@ -25,6 +27,10 @@ func TestEvaluateAttestationsInstruction(t *testing.T) { expectedOracle := solana.MustPublicKeyFromBase58("FNz5mur7EFh1LyH5HDaKyWVx7vcfGK6gRizEpDqMfgGk") payer := solana.MustPublicKeyFromBase58("E3CfijtAJwBSHfwFEViAUd3xp7c8TBxwC1eXn1Fgxp8h") + // Expected Data (from same tx) + expectedData, err := hex.DecodeString("0700c2eb0b000000000b00000066743a33373336346538303f6d9fcf0d4466dd5886e3b1def017adfb7916b4") + require.NoError(t, err) + // Use stage program ID stageProgramId := solana.MustPublicKeyFromBase58("CDpzvz7DfgbF95jSSCHLX3ERkugyfgn9Fw8ypNZ1hfXp") reward_manager.SetProgramID(stageProgramId) @@ -51,9 +57,6 @@ func TestEvaluateAttestationsInstruction(t *testing.T) { require.Equal(t, expectedOracle.String(), inst.Accounts()[6].PublicKey.String()) require.Equal(t, payer.String(), inst.Accounts()[7].PublicKey.String()) - // From successful stage transaction (signature 26gT9HVMhzBDzsKcsiKREYmGcXuZhjAJpCVUu9WFNhVMyKje8SdApYc4ev3HrumZB4LEXLUaPnKyriBPLmtzwrWp) - expectedData, err := hex.DecodeString("0700c2eb0b000000000b00000066743a33373336346538303f6d9fcf0d4466dd5886e3b1def017adfb7916b4") - require.NoError(t, err) data, err := inst.Data() require.NoError(t, err) require.Equal(t, expectedData, data)