Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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