Skip to content

Commit 07aab14

Browse files
authored
Merge pull request #44 from AudiusProject/mjp-rewards-4
Derive User Banks, Add Solana Config
2 parents 06bf76d + 1888a17 commit 07aab14

7 files changed

Lines changed: 199 additions & 4 deletions

File tree

api/server_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ func TestMain(m *testing.M) {
4444
}
4545

4646
app = NewApiServer(config.Config{
47-
DbUrl: "postgres://postgres:example@localhost:21300/test",
47+
DbUrl: "postgres://postgres:example@localhost:21300/test",
48+
DelegatePrivateKey: "0633fddb74e32b3cbc64382e405146319c11a1a52dc96598e557c5dbe2f31468",
4849
})
4950

5051
// seed db
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package claimable_tokens
2+
3+
import (
4+
"encoding/hex"
5+
"strings"
6+
7+
"github.com/gagliardetto/solana-go"
8+
"github.com/mr-tron/base58"
9+
)
10+
11+
func deriveAuthority(mint solana.PublicKey) (solana.PublicKey, uint8, error) {
12+
return solana.FindProgramAddress([][]byte{mint.Bytes()[:32]}, ProgramID)
13+
}
14+
15+
func DeriveUserBankAccount(mint solana.PublicKey, ethAddress string) (solana.PublicKey, error) {
16+
ethAddressBytes, err := hex.DecodeString(strings.TrimPrefix(ethAddress, "0x"))
17+
if err != nil {
18+
return solana.PublicKey{}, err
19+
}
20+
21+
seed := base58.Encode(ethAddressBytes)
22+
authority, _, err := deriveAuthority(mint)
23+
if err != nil {
24+
return solana.PublicKey{}, err
25+
}
26+
27+
pubkey, err := solana.CreateWithSeed(authority, seed, solana.TokenProgramID)
28+
if err != nil {
29+
return solana.PublicKey{}, err
30+
}
31+
32+
return pubkey, nil
33+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package claimable_tokens_test
2+
3+
import (
4+
"testing"
5+
6+
"bridgerton.audius.co/api/spl/programs/claimable_tokens"
7+
"github.com/gagliardetto/solana-go"
8+
"github.com/stretchr/testify/require"
9+
)
10+
11+
func TestDeriveUserBankAccount(t *testing.T) {
12+
mint := solana.MustPublicKeyFromBase58("9LzCMqDgTKYz9Drzqnpgee3SGa89up3a247ypMj2xrqM")
13+
ethAddress := "0xa507da823bf0c5dc44a759d0d398b7f52097da19"
14+
expectedUserBankAccount := solana.MustPublicKeyFromBase58("9oJLynXRLkWZkTXXExPXVbza5n8CzTZLvtJ1Y3pEJ2Pk")
15+
16+
userBankAccount, err := claimable_tokens.DeriveUserBankAccount(mint, ethAddress)
17+
require.NoError(t, err)
18+
require.Equal(t, expectedUserBankAccount.String(), userBankAccount.String())
19+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package claimable_tokens
2+
3+
import "github.com/gagliardetto/solana-go"
4+
5+
var ProgramID = solana.MustPublicKeyFromBase58("Ewkv3JahEFRKkcJmpoKB7pXbnUHwjAyXiwEo4ZY2rezQ")
6+
7+
func SetProgramID(pubkey solana.PublicKey) {
8+
ProgramID = pubkey
9+
}

api/spl/programs/reward_manager/instruction.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const (
1616
DisbursementSeedPrefix = "T_"
1717
)
1818

19-
var ProgramID = solana.MustPublicKeyFromBase58("CDpzvz7DfgbF95jSSCHLX3ERkugyfgn9Fw8ypNZ1hfXp")
19+
var ProgramID = solana.MustPublicKeyFromBase58("DDZDcYdQFEMwcu2Mwo75yGFjJ1mUQyyXLWzhZLEVFcei")
2020

2121
func SetProgramID(pubkey solana.PublicKey) {
2222
ProgramID = pubkey

config/config.go

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package config
22

33
import (
4+
"log"
45
"os"
56

67
_ "github.com/joho/godotenv/autoload"
@@ -15,6 +16,8 @@ type Config struct {
1516
PythonUpstreams []string
1617
NetworkTakeRate float64
1718
StakingBridgeUsdcPayoutWallet string
19+
SolanaConfig SolanaConfig
20+
AntiAbuseOracles []string
1821
}
1922

2023
var Cfg = Config{
@@ -25,21 +28,43 @@ var Cfg = Config{
2528
AxiomDataset: os.Getenv("axiomDataset"),
2629
NetworkTakeRate: 10,
2730
StakingBridgeUsdcPayoutWallet: "7vGA3fcjvxa3A11MAxmyhFtYowPLLCNyvoxxgN3NN2Vf",
31+
SolanaConfig: SolCfg,
2832
}
2933

3034
func init() {
31-
if os.Getenv("ENV") == "stage" {
35+
switch env := os.Getenv("ENV"); env {
36+
case "dev":
37+
fallthrough
38+
case "development":
39+
fallthrough
40+
case "":
41+
Cfg.AntiAbuseOracles = []string{"http://audius-protocol-discovery-provider-1"}
42+
case "stage":
43+
fallthrough
44+
case "staging":
45+
if Cfg.DelegatePrivateKey == "" {
46+
log.Fatalf("Missing required %s env var: delegatePrivateKey", env)
47+
}
48+
Cfg.AntiAbuseOracles = []string{"https://discoveryprovider.staging.audius.co"}
3249
Cfg.PythonUpstreams = []string{
3350
"https://discoveryprovider.staging.audius.co",
3451
"https://discoveryprovider2.staging.audius.co",
3552
"https://discoveryprovider3.staging.audius.co",
3653
"https://discoveryprovider5.staging.audius.co",
3754
}
38-
} else {
55+
case "prod":
56+
fallthrough
57+
case "production":
58+
if Cfg.DelegatePrivateKey == "" {
59+
log.Fatalf("Missing required %s env var: delegatePrivateKey", env)
60+
}
61+
Cfg.AntiAbuseOracles = []string{"https://discoveryprovider.audius.co"}
3962
Cfg.PythonUpstreams = []string{
4063
"https://discoveryprovider.audius.co",
4164
"https://discoveryprovider2.audius.co",
4265
"https://discoveryprovider3.audius.co",
4366
}
67+
default:
68+
log.Fatalf("Unknown environment: %s", env)
4469
}
4570
}

config/solana_config.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package config
2+
3+
import (
4+
"log"
5+
"os"
6+
"strings"
7+
8+
"bridgerton.audius.co/api/spl/programs/claimable_tokens"
9+
"bridgerton.audius.co/api/spl/programs/reward_manager"
10+
"github.com/gagliardetto/solana-go"
11+
)
12+
13+
type SolanaConfig struct {
14+
RpcProviders []string
15+
FeePayers []solana.Wallet
16+
SolanaRelay string
17+
18+
MintAudio solana.PublicKey
19+
20+
RewardManagerProgramID solana.PublicKey
21+
RewardManagerState solana.PublicKey
22+
RewardManagerLookupTable solana.PublicKey
23+
24+
ClaimableTokensProgramID solana.PublicKey
25+
}
26+
27+
var SolCfg = SolanaConfig{
28+
RpcProviders: strings.Split(os.Getenv("solanaRpcProviders"), ","),
29+
}
30+
31+
const (
32+
// Dev
33+
DevSolanaRelay = "http://audius-protocol-discovery-provider-1/solana/relay"
34+
DevMintAudio = "37RCjhgV1qGV2Q54EHFScdxZ22ydRMdKMtVgod47fDP3"
35+
DevRewardManagerProgramID = "testLsJKtyABc9UXJF8JWFKf1YH4LmqCWBC42c6akPb"
36+
DevRewardManagerState = "DJPzVothq58SmkpRb1ATn5ddN2Rpv1j2TcGvM3XsHf1c"
37+
DevRewardManagerLookupTable = "GNHKVSmHvoRBt1JJCxz7RSMfzDQGDGhGEjmhHyxb3K5J"
38+
DevClaimableTokensProgramID = "testHKV1B56fbvop4w6f2cTGEub9dRQ2Euta5VmqdX9"
39+
40+
// Stage
41+
StageSolanaRelay = "https://discoveryprovider.staging.audius.co/solana/relay"
42+
StageMintAudio = "BELGiMZQ34SDE6x2FUaML2UHDAgBLS64xvhXjX5tBBZo"
43+
StageRewardManagerProgramID = "CDpzvz7DfgbF95jSSCHLX3ERkugyfgn9Fw8ypNZ1hfXp"
44+
StageRewardManagerState = "GaiG9LDYHfZGqeNaoGRzFEnLiwUT7WiC6sA6FDJX9ZPq"
45+
StageRewardManagerLookupTable = "ChFCWjeFxM6SRySTfT46zXn2K7m89TJsft4HWzEtkB4J"
46+
StageClaimableTokensProgramID = "2sjQNmUfkV6yKKi4dPR8gWRgtyma5aiymE3aXL2RAZww"
47+
48+
// Prod
49+
ProdSolanaRelay = "https://discoveryprovider.audius.co/solana/relay"
50+
ProdMintAudio = "9LzCMqDgTKYz9Drzqnpgee3SGa89up3a247ypMj2xrqM"
51+
ProdRewardManagerProgramID = "DDZDcYdQFEMwcu2Mwo75yGFjJ1mUQyyXLWzhZLEVFcei"
52+
ProdRewardManagerState = "71hWFVYokLaN1PNYzTAWi13EfJ7Xt9VbSWUKsXUT8mxE"
53+
ProdRewardManagerLookupTable = "4UQwpGupH66RgQrWRqmPM9Two6VJEE68VZ7GeqZ3mvVv"
54+
ProdClaimableTokensProgramID = "Ewkv3JahEFRKkcJmpoKB7pXbnUHwjAyXiwEo4ZY2rezQ"
55+
)
56+
57+
func init() {
58+
keyString := os.Getenv("solanaFeePayerKeys")
59+
if keyString != "" {
60+
walletKeys := strings.Split(keyString, ",")
61+
SolCfg.FeePayers = make([]solana.Wallet, len(walletKeys))
62+
for i, privkeyString := range walletKeys {
63+
privkey := solana.MustPrivateKeyFromBase58(privkeyString)
64+
SolCfg.FeePayers[i] = solana.Wallet{
65+
PrivateKey: privkey,
66+
}
67+
}
68+
} else {
69+
SolCfg.FeePayers = make([]solana.Wallet, 0)
70+
}
71+
72+
switch env := os.Getenv("ENV"); env {
73+
case "dev":
74+
fallthrough
75+
case "development":
76+
fallthrough
77+
case "":
78+
SolCfg.SolanaRelay = DevSolanaRelay
79+
SolCfg.MintAudio = solana.MustPublicKeyFromBase58(DevMintAudio)
80+
SolCfg.RewardManagerProgramID = solana.MustPublicKeyFromBase58(DevRewardManagerProgramID)
81+
SolCfg.RewardManagerState = solana.MustPublicKeyFromBase58(DevRewardManagerState)
82+
SolCfg.RewardManagerLookupTable = solana.MustPublicKeyFromBase58(DevRewardManagerLookupTable)
83+
SolCfg.ClaimableTokensProgramID = solana.MustPublicKeyFromBase58(DevClaimableTokensProgramID)
84+
case "stage":
85+
fallthrough
86+
case "staging":
87+
SolCfg.SolanaRelay = StageSolanaRelay
88+
SolCfg.MintAudio = solana.MustPublicKeyFromBase58(StageMintAudio)
89+
SolCfg.RewardManagerProgramID = solana.MustPublicKeyFromBase58(StageRewardManagerProgramID)
90+
SolCfg.RewardManagerState = solana.MustPublicKeyFromBase58(StageRewardManagerState)
91+
SolCfg.RewardManagerLookupTable = solana.MustPublicKeyFromBase58(StageRewardManagerLookupTable)
92+
SolCfg.ClaimableTokensProgramID = solana.MustPublicKeyFromBase58(StageClaimableTokensProgramID)
93+
case "prod":
94+
fallthrough
95+
case "production":
96+
SolCfg.SolanaRelay = ProdSolanaRelay
97+
SolCfg.MintAudio = solana.MustPublicKeyFromBase58(ProdMintAudio)
98+
SolCfg.RewardManagerProgramID = solana.MustPublicKeyFromBase58(ProdRewardManagerProgramID)
99+
SolCfg.RewardManagerState = solana.MustPublicKeyFromBase58(ProdRewardManagerState)
100+
SolCfg.RewardManagerLookupTable = solana.MustPublicKeyFromBase58(ProdRewardManagerLookupTable)
101+
SolCfg.ClaimableTokensProgramID = solana.MustPublicKeyFromBase58(ProdClaimableTokensProgramID)
102+
default:
103+
log.Fatalf("Unknown environment: %s", env)
104+
}
105+
106+
reward_manager.SetProgramID(SolCfg.RewardManagerProgramID)
107+
claimable_tokens.SetProgramID(SolCfg.ClaimableTokensProgramID)
108+
}

0 commit comments

Comments
 (0)