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
12 changes: 12 additions & 0 deletions ocp/currency/data_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package currency
import (
"context"
"crypto/ed25519"
"fmt"
"strings"
"sync"
"time"
Expand All @@ -22,6 +23,7 @@ import (
"github.com/code-payments/ocp-server/ocp/data/currency"
"github.com/code-payments/ocp-server/solana/currencycreator"
timelock_token "github.com/code-payments/ocp-server/solana/timelock/v1"
"github.com/code-payments/ocp-server/usdc"
)

// LiveExchangeRateData represents live exchange rate data with its pre-signed response
Expand Down Expand Up @@ -368,6 +370,16 @@ func (m *MintDataProvider) GetProtoMint(ctx context.Context, mint *common.Accoun
},
CreatedAt: timestamppb.New(time.Time{}),
}
case usdc.Mint:
protoMetadata = &currencypb.Mint{
Address: mint.ToProto(),
Decimals: uint32(usdc.Decimals),
Name: usdc.Name,
Symbol: usdc.Symbol,
Description: " ",
ImageUrl: fmt.Sprintf("%s/%s/icon.png", config.CurrencyAssetsBaseUrl, usdc.Mint),
CreatedAt: timestamppb.New(time.Time{}),
}
default:
var err error
metadataRecord, ok := m.getCachedCurrencyMetadata(mint)
Expand Down
48 changes: 47 additions & 1 deletion ocp/rpc/account/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ import (
"github.com/code-payments/ocp-server/ocp/common"
currency_util "github.com/code-payments/ocp-server/ocp/currency"
ocp_data "github.com/code-payments/ocp-server/ocp/data"
"github.com/code-payments/ocp-server/ocp/data/account"
"github.com/code-payments/ocp-server/ocp/data/action"
"github.com/code-payments/ocp-server/ocp/rpc"
account_worker "github.com/code-payments/ocp-server/ocp/worker/account"
timelock_token_v1 "github.com/code-payments/ocp-server/solana/timelock/v1"
"github.com/code-payments/ocp-server/usdc"
)

var (
Expand Down Expand Up @@ -166,18 +168,33 @@ func (s *server) GetTokenAccountInfos(ctx context.Context, req *accountpb.GetTok
}

var hasGiftCardAccount bool
var hasPrimaryAccount bool
var allRecords []*common.AccountRecords
for _, recordsByType := range allRecordsByMintAndType {
for _, batchRecords := range recordsByType {
for _, records := range batchRecords {
if records.General.AccountType == commonpb.AccountType_REMOTE_SEND_GIFT_CARD {
hasGiftCardAccount = true
}
if records.General.AccountType == commonpb.AccountType_PRIMARY {
hasPrimaryAccount = true
}
allRecords = append(allRecords, records)
}
}
}

// Owners with a PRIMARY account also expose their external USDC associated
// token account so clients can observe the off-L2 USDC balance.
if hasPrimaryAccount {
usdcAtaRecords, err := buildUsdcAtaRecords(owner)
if err != nil {
log.With(zap.Error(err)).Warn("failure building usdc ata records")
return nil, status.Error(codes.Internal, "")
}
allRecords = append(allRecords, usdcAtaRecords)
}

// Filter account records based on client request
//
// todo: this needs tests
Expand Down Expand Up @@ -487,7 +504,14 @@ func (s *server) getProtoAccountInfo(ctx context.Context, records *common.Accoun
var liveReserveState *currencypb.VerifiedLaunchpadCurrencyReserveState
switch records.General.AccountType {
case commonpb.AccountType_SWAP, commonpb.AccountType_ASSOCIATED_TOKEN_ACCOUNT:
// Unused account types, which likely don't have any mint metadata ATM.
// Well-known mints we know we have metadata for
switch mintAccount.PublicKey().ToBase58() {
case usdc.Mint:
mintMetadata, err = s.mintDataProvider.GetProtoMint(ctx, mintAccount)
if err != nil {
return nil, err
}
}
default:
mintMetadata, err = s.mintDataProvider.GetProtoMint(ctx, mintAccount)
if err != nil {
Expand Down Expand Up @@ -576,6 +600,28 @@ func (s *server) addRequestingOwnerMetadata(ctx context.Context, resp *accountpb
return cloned, nil
}

func buildUsdcAtaRecords(owner *common.Account) (*common.AccountRecords, error) {
usdcMint, err := common.NewAccountFromPublicKeyString(usdc.Mint)
if err != nil {
return nil, err
}

ata, err := owner.ToAssociatedTokenAccount(usdcMint)
if err != nil {
return nil, err
}

return &common.AccountRecords{
General: &account.Record{
OwnerAccount: owner.PublicKey().ToBase58(),
AuthorityAccount: owner.PublicKey().ToBase58(),
TokenAccount: ata.PublicKey().ToBase58(),
MintAccount: usdcMint.PublicKey().ToBase58(),
AccountType: commonpb.AccountType_ASSOCIATED_TOKEN_ACCOUNT,
},
}, nil
}

func (s *server) updateCachedResponse(resp *accountpb.GetTokenAccountInfosResponse) {
for _, ai := range resp.TokenAccountInfos {
switch ai.AccountType {
Expand Down
29 changes: 26 additions & 3 deletions ocp/rpc/account/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/code-payments/ocp-server/solana/currencycreator"
timelock_token_v1 "github.com/code-payments/ocp-server/solana/timelock/v1"
"github.com/code-payments/ocp-server/testutil"
"github.com/code-payments/ocp-server/usdc"
)

type testEnv struct {
Expand Down Expand Up @@ -187,7 +188,29 @@ func TestGetTokenAccountInfos_UserAccounts_HappyPath(t *testing.T) {
resp, err := env.client.GetTokenAccountInfos(env.ctx, req)
require.NoError(t, err)
assert.Equal(t, accountpb.GetTokenAccountInfosResponse_OK, resp.Result)
assert.Len(t, resp.TokenAccountInfos, 5)
assert.Len(t, resp.TokenAccountInfos, 6)

usdcMint, err := common.NewAccountFromPublicKeyString(usdc.Mint)
require.NoError(t, err)
usdcAta, err := ownerAccount.ToAssociatedTokenAccount(usdcMint)
require.NoError(t, err)
usdcAtaInfo, ok := resp.TokenAccountInfos[usdcAta.PublicKey().ToBase58()]
require.True(t, ok)
assert.Equal(t, commonpb.AccountType_ASSOCIATED_TOKEN_ACCOUNT, usdcAtaInfo.AccountType)
assert.Equal(t, ownerAccount.PublicKey().ToBytes(), usdcAtaInfo.Owner.Value)
assert.Equal(t, ownerAccount.PublicKey().ToBytes(), usdcAtaInfo.Authority.Value)
assert.Equal(t, usdcMint.PublicKey().ToBytes(), usdcAtaInfo.Mint.Value)
assert.Equal(t, accountpb.TokenAccountInfo_BALANCE_SOURCE_BLOCKCHAIN, usdcAtaInfo.BalanceSource)
assert.Equal(t, accountpb.TokenAccountInfo_MANAGEMENT_STATE_NONE, usdcAtaInfo.ManagementState)
assert.Equal(t, accountpb.TokenAccountInfo_BLOCKCHAIN_STATE_UNKNOWN, usdcAtaInfo.BlockchainState)
require.NotNil(t, usdcAtaInfo.MintMetadata)
assert.Equal(t, usdcMint.PublicKey().ToBytes(), usdcAtaInfo.MintMetadata.Address.Value)
assert.EqualValues(t, usdc.Decimals, usdcAtaInfo.MintMetadata.Decimals)
assert.Equal(t, usdc.Name, usdcAtaInfo.MintMetadata.Name)
assert.Equal(t, usdc.Symbol, usdcAtaInfo.MintMetadata.Symbol)
assert.Nil(t, usdcAtaInfo.MintMetadata.VmMetadata)
assert.Nil(t, usdcAtaInfo.MintMetadata.LaunchpadMetadata)
assert.Nil(t, usdcAtaInfo.LiveReserveState)

for _, tc := range []struct {
authority *common.Account
Expand Down Expand Up @@ -606,7 +629,7 @@ func TestGetTokenAccountInfos_BlockchainState(t *testing.T) {
resp, err := env.client.GetTokenAccountInfos(env.ctx, req)
require.NoError(t, err)
assert.Equal(t, accountpb.GetTokenAccountInfosResponse_OK, resp.Result)
assert.Len(t, resp.TokenAccountInfos, 1)
assert.Len(t, resp.TokenAccountInfos, 2)

accountInfo, ok := resp.TokenAccountInfos[accountRecords.Timelock.VaultAddress]
require.True(t, ok)
Expand Down Expand Up @@ -674,7 +697,7 @@ func TestGetTokenAccountInfos_ManagementState(t *testing.T) {
resp, err := env.client.GetTokenAccountInfos(env.ctx, req)
require.NoError(t, err)
assert.Equal(t, accountpb.GetTokenAccountInfosResponse_OK, resp.Result)
assert.Len(t, resp.TokenAccountInfos, 1)
assert.Len(t, resp.TokenAccountInfos, 2)

accountInfo, ok := resp.TokenAccountInfos[accountRecords.Timelock.VaultAddress]
require.True(t, ok)
Expand Down
6 changes: 5 additions & 1 deletion usdc/usdc.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package usdc

const (
Mint = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
Name = "USDC"
Symbol = "USDC"

Mint = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"

QuarksPerUsdc = 1000000
Decimals = 6
)
Loading