Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
2 changes: 2 additions & 0 deletions api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ func NewApiServer(config config.Config) *ApiServer {
rewardAttester: *rewards.NewRewardAttester(privateKey, []rewards.Reward{}),
solanaConfig: config.SolanaConfig,
antiAbuseOracles: config.AntiAbuseOracles,
validators: config.Nodes,
}

app.Use(recover.New(recover.Config{
Expand Down Expand Up @@ -258,6 +259,7 @@ type ApiServer struct {
rewardAttester rewards.RewardAttester
solanaConfig config.SolanaConfig
antiAbuseOracles []string
validators []config.Node
}

func (app *ApiServer) home(c *fiber.Ctx) error {
Expand Down
4 changes: 2 additions & 2 deletions api/spl/programs/reward_manager/EvaluateAttestations.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ func (inst *EvaluateAttestation) SetPayer(payer solana.PublicKey) *EvaluateAttes
}

func (inst EvaluateAttestation) Build() *Instruction {
authority, _, _ := deriveAuthority(ProgramID, inst.RewardManagerState)
attestations, _, _ := deriveAttestations(ProgramID, authority, inst.DisbursementID)
authority, _, _ := DeriveAuthorityAccount(ProgramID, inst.RewardManagerState)
attestations, _, _ := DeriveAttestationsAccount(ProgramID, authority, inst.DisbursementID)
disbursement, _, _ := deriveDisbursement(ProgramID, authority, inst.DisbursementID)
antiAbuseOracle, _, _ := deriveSender(ProgramID, authority, inst.AntiAbuseOracleEthAddress)

Expand Down
4 changes: 2 additions & 2 deletions api/spl/programs/reward_manager/SubmitAttestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ func (inst *SubmitAttestation) SetPayer(payer solana.PublicKey) *SubmitAttestati
}

func (inst SubmitAttestation) Build() *Instruction {
authority, _, _ := deriveAuthority(ProgramID, inst.RewardManagerState)
authority, _, _ := DeriveAuthorityAccount(ProgramID, inst.RewardManagerState)
sender, _, _ := deriveSender(ProgramID, authority, inst.SenderEthAddress)
attestations, _, _ := deriveAttestations(ProgramID, authority, inst.DisbursementID)
attestations, _, _ := DeriveAttestationsAccount(ProgramID, authority, inst.DisbursementID)

inst.AccountMetaSlice = []*solana.AccountMeta{
{
Expand Down
115 changes: 113 additions & 2 deletions api/spl/programs/reward_manager/accounts.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package reward_manager

import (
"encoding/binary"
"encoding/hex"
"errors"
"strings"

"github.com/AudiusProject/audiusd/pkg/rewards"
bin "github.com/gagliardetto/binary"
"github.com/gagliardetto/solana-go"
)

Expand All @@ -14,7 +18,114 @@ type RewardManagerState struct {
MinVotes uint8
}

func deriveAuthority(programId solana.PublicKey, state solana.PublicKey) (solana.PublicKey, uint8, error) {
type Attestation struct {
SenderEthAddress string
Claim rewards.RewardClaim
OperatorEthAddress string
}

func (data *Attestation) UnmarshalWithDecoder(decoder *bin.Decoder) error {
senderBytes, err := decoder.ReadNBytes(20)
if err != nil {
return err
}
data.SenderEthAddress = "0x" + hex.EncodeToString(senderBytes)

recipientBytes, err := decoder.ReadNBytes(20)
if err != nil {
return err
}
data.Claim.RecipientEthAddress = "0x" + hex.EncodeToString(recipientBytes)

// Read separator _
decoder.SkipBytes(uint(1))

amount, err := decoder.ReadUint64(binary.LittleEndian)
if err != nil {
return err
}
data.Claim.Amount = amount

// Read separator _
decoder.SkipBytes(uint(1))

disbursementIdBytes := []byte{}
bytesLeft := 32
for {
b, err := decoder.ReadByte()
if err != nil {
return err
}

if b == 0 || b == []byte("_")[0] {
break
}
bytesLeft = bytesLeft - 1
disbursementIdBytes = append(disbursementIdBytes, b)
}
disbursementIdParts := strings.Split(string(disbursementIdBytes), ":")
if len(disbursementIdParts) < 2 {
return errors.New("invalid disbursement ID")
}
data.Claim.RewardID = disbursementIdParts[0]
data.Claim.Specifier = strings.Join(disbursementIdParts[1:], ":")

oracleBytes, err := decoder.ReadNBytes(20)
if err != nil {
return err
}
data.Claim.AntiAbuseOracleEthAddress = "0x" + hex.EncodeToString(oracleBytes)
if data.Claim.AntiAbuseOracleEthAddress == "0x0000000000000000000000000000000000000000" {
data.Claim.AntiAbuseOracleEthAddress = ""
}

// Skip unused bytes
decoder.SkipBytes(uint(bytesLeft))

// claim padding
decoder.SkipBytes(uint(45))

operatorBytes, err := decoder.ReadBytes(20)
if err != nil {
return err
}
data.OperatorEthAddress = "0x" + hex.EncodeToString(operatorBytes)

return nil
}

type AttestationsAccountData struct {
Version uint8
RewardManagerState solana.PublicKey
Count uint8
Messages []Attestation
}

func (data *AttestationsAccountData) UnmarshalWithDecoder(decoder *bin.Decoder) error {
err := decoder.Decode(&data.Version)
if err != nil {
return err
}
err = decoder.Decode(&data.RewardManagerState)
if err != nil {
return err
}
err = decoder.Decode(&data.Count)
if err != nil {
return err
}

data.Messages = make([]Attestation, data.Count)
for i := range data.Count {
err = decoder.Decode(&data.Messages[i])
if err != nil {
return err
}
}
return nil
}

func DeriveAuthorityAccount(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)
Expand All @@ -34,7 +145,7 @@ func deriveSender(programId solana.PublicKey, authority solana.PublicKey, ethAdd
return solana.FindProgramAddress([][]byte{authority.Bytes()[0:32], senderSeed}, programId)
}

func deriveAttestations(programId solana.PublicKey, authority solana.PublicKey, disbursementId string) (solana.PublicKey, uint8, error) {
func DeriveAttestationsAccount(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)
Expand Down
60 changes: 60 additions & 0 deletions api/spl/programs/reward_manager/accounts_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package reward_manager_test

import (
"encoding/base64"
"testing"

"bridgerton.audius.co/api/spl/programs/reward_manager"
bin "github.com/gagliardetto/binary"
"github.com/stretchr/testify/require"
)

func TestDecodeAttestationsAccount(t *testing.T) {
testData, err := base64.StdEncoding.DecodeString("AeeCH+of/iC5SPD28pk1Fv5CZ/fBO1jttO39bISSUz9sBAC2Ri6VXaWEG22eHiUpuDDwDzG/nxMmaYsG6TJgMoFyC0Aizx+D7iJfAOH1BQAAAABfYjo1ZjI1NjEyOjI5MzVkYWNiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtkYulV2lhBttnh4lKbgw8A8xv/fJaRa9N6121O7dZTa4HClwbIBWnxMmaYsG6TJgMoFyC0Aizx+D7iJfAOH1BQAAAABfYjo1ZjI1NjEyOjI5MzVkYWNiXwC2Ri6VXaWEG22eHiUpuDDwDzG/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD3yWkWvTetdtTu3WU2uBwpcGyAVl6Yy+6qKs7ewIM6w9FjTip64PPCnxMmaYsG6TJgMoFyC0Aizx+D7iJfAOH1BQAAAABfYjo1ZjI1NjEyOjI5MzVkYWNiXwC2Ri6VXaWEG22eHiUpuDDwDzG/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABemMvuqirO3sCDOsPRY04qeuDzwo/PoQvTgIVwmH27Wx70q3RAD7/anxMmaYsG6TJgMoFyC0Aizx+D7iJfAOH1BQAAAABfYjo1ZjI1NjEyOjI5MzVkYWNiXwC2Ri6VXaWEG22eHiUpuDDwDzG/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACPz6EL04CFcJh9u1se9Kt0QA+/2gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==")
require.NoError(t, err)

result := reward_manager.AttestationsAccountData{}
result.UnmarshalWithDecoder(bin.NewBinDecoder(testData))

require.Equal(t, uint8(1), result.Version)
require.Equal(t, "GaiG9LDYHfZGqeNaoGRzFEnLiwUT7WiC6sA6FDJX9ZPq", result.RewardManagerState.String())
require.Equal(t, uint8(4), result.Count)
require.Len(t, result.Messages, 4)

// Message 1
require.Equal(t, "0x00b6462e955da5841b6d9e1e2529b830f00f31bf", result.Messages[0].SenderEthAddress)
require.Equal(t, uint64(100000000), result.Messages[0].Claim.Amount)
require.Equal(t, "b", result.Messages[0].Claim.RewardID)
require.Equal(t, "5f25612:2935dacb", result.Messages[0].Claim.Specifier)
require.Equal(t, "0x9f1326698b06e932603281720b4022cf1f83ee22", result.Messages[0].Claim.RecipientEthAddress)
require.Equal(t, "", result.Messages[0].Claim.AntiAbuseOracleEthAddress)
require.Equal(t, "0x00b6462e955da5841b6d9e1e2529b830f00f31bf", result.Messages[0].OperatorEthAddress)

// Message 2
require.Equal(t, "0xf7c96916bd37ad76d4eedd6536b81c29706c8056", result.Messages[1].SenderEthAddress)
require.Equal(t, uint64(100000000), result.Messages[1].Claim.Amount)
require.Equal(t, "b", result.Messages[1].Claim.RewardID)
require.Equal(t, "5f25612:2935dacb", result.Messages[1].Claim.Specifier)
require.Equal(t, "0x9f1326698b06e932603281720b4022cf1f83ee22", result.Messages[1].Claim.RecipientEthAddress)
require.Equal(t, "0x00b6462e955da5841b6d9e1e2529b830f00f31bf", result.Messages[1].Claim.AntiAbuseOracleEthAddress)
require.Equal(t, "0xf7c96916bd37ad76d4eedd6536b81c29706c8056", result.Messages[1].OperatorEthAddress)

// Message 3
require.Equal(t, "0x5e98cbeeaa2acedec0833ac3d1634e2a7ae0f3c2", result.Messages[2].SenderEthAddress)
require.Equal(t, uint64(100000000), result.Messages[2].Claim.Amount)
require.Equal(t, "b", result.Messages[2].Claim.RewardID)
require.Equal(t, "5f25612:2935dacb", result.Messages[2].Claim.Specifier)
require.Equal(t, "0x9f1326698b06e932603281720b4022cf1f83ee22", result.Messages[2].Claim.RecipientEthAddress)
require.Equal(t, "0x00b6462e955da5841b6d9e1e2529b830f00f31bf", result.Messages[2].Claim.AntiAbuseOracleEthAddress)
require.Equal(t, "0x5e98cbeeaa2acedec0833ac3d1634e2a7ae0f3c2", result.Messages[2].OperatorEthAddress)

// Message 4
require.Equal(t, "0x8fcfa10bd3808570987dbb5b1ef4ab74400fbfda", result.Messages[3].SenderEthAddress)
require.Equal(t, uint64(100000000), result.Messages[3].Claim.Amount)
require.Equal(t, "b", result.Messages[3].Claim.RewardID)
require.Equal(t, "5f25612:2935dacb", result.Messages[3].Claim.Specifier)
require.Equal(t, "0x9f1326698b06e932603281720b4022cf1f83ee22", result.Messages[3].Claim.RecipientEthAddress)
require.Equal(t, "0x00b6462e955da5841b6d9e1e2529b830f00f31bf", result.Messages[3].Claim.AntiAbuseOracleEthAddress)
require.Equal(t, "0x8fcfa10bd3808570987dbb5b1ef4ab74400fbfda", result.Messages[3].OperatorEthAddress)

}
Loading
Loading