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
3 changes: 3 additions & 0 deletions apps/solana/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@
CreatedAt time.Time

Uri string
Asset *bot.AssetNetwork

Check failure on line 54 in apps/solana/common.go

View workflow job for this annotation

GitHub Actions / lint

undefined: bot (typecheck)
PrivateKey *solana.PrivateKey

Check failure on line 55 in apps/solana/common.go

View workflow job for this annotation

GitHub Actions / lint

undefined: solana (typecheck)
}

type NonceAccount struct {
Address solana.PublicKey

Check failure on line 59 in apps/solana/common.go

View workflow job for this annotation

GitHub Actions / lint

undefined: solana (typecheck)
Hash solana.Hash

Check failure on line 60 in apps/solana/common.go

View workflow job for this annotation

GitHub Actions / lint

undefined: solana (typecheck)
}

type TokenTransfer struct {
Expand Down Expand Up @@ -414,6 +414,9 @@
}

func NonceAccountFromTx(tx *solana.Transaction) (*system.AdvanceNonceAccount, error) {
if len(tx.Message.Instructions) == 0 {
return nil, fmt.Errorf("transaction has no instructions")
}
ins := tx.Message.Instructions[0]
accounts, err := ins.ResolveInstructionAccounts(&tx.Message)
if err != nil {
Expand Down
13 changes: 11 additions & 2 deletions apps/solana/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ type AssetMetadata struct {
type Asset struct {
Address string `json:"address"`
Id string `json:"id"`
ProgramId string `json:"program_id"`
Supply string `json:"supply"`
Decimals uint32 `json:"decimals"`
IsInitialized bool `json:"is_initialized"`
MintAuthority string `json:"mint_authority"`
FreezeAuthority string `json:"freeze_authority"`
}
Expand Down Expand Up @@ -106,14 +109,17 @@ func (c *Client) RPCGetAsset(ctx context.Context, address string) (*Asset, error
if err != nil {
return nil, fmt.Errorf("solana.RPCGetAsset(%s) => %v", address, err)
}
if account == nil || account.Value == nil {
return nil, nil
}
data, err := account.Value.Data.MarshalJSON()
if err != nil {
panic(err)
return nil, fmt.Errorf("solana.RPCGetAsset(%s) marshal => %v", address, err)
}
var mint MintData
err = json.Unmarshal(data, &mint)
if err != nil {
panic(err)
return nil, fmt.Errorf("solana.RPCGetAsset(%s) unmarshal => %v", address, err)
}

mintAuthority := ""
Expand All @@ -127,7 +133,10 @@ func (c *Client) RPCGetAsset(ctx context.Context, address string) (*Asset, error
asset := &Asset{
Address: address,
Id: GenerateAssetId(address),
ProgramId: account.Value.Owner.String(),
Supply: mint.Parsed.Info.Supply,
Decimals: uint32(mint.Parsed.Info.Decimals),
IsInitialized: mint.Parsed.Info.IsInitialized,
MintAuthority: mintAuthority,
FreezeAuthority: freezeAuthority,
}
Expand Down
66 changes: 58 additions & 8 deletions apps/solana/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
"github.com/shopspring/decimal"
)

const solanaInnerIndexBase = int64(1_000_000_000)

func (c *Client) CreateNonceAccount(ctx context.Context, key, nonce string, rent uint64) (*solana.Transaction, error) {
payer, err := solana.PrivateKeyFromBase58(key)
if err != nil {
Expand Down Expand Up @@ -388,12 +390,19 @@ func (c *Client) getPriorityFeeInstruction(ctx context.Context) *computebudget.I
if err != nil {
panic(err)
}
fee := getAveragePriorityFee(recentFees)
return computebudget.NewSetComputeUnitPriceInstruction(fee).Build()
}

func getAveragePriorityFee(recentFees []rpc.PriorizationFeeResult) uint64 {
if len(recentFees) == 0 {
return 1000
}
total := decimal.NewFromInt(0)
for _, fee := range recentFees {
total = total.Add(decimal.NewFromUint64(fee.PrioritizationFee))
}
fee := total.Div(decimal.NewFromInt(int64(len(recentFees)))).BigInt().Uint64()
return computebudget.NewSetComputeUnitPriceInstruction(fee).Build()
return total.Div(decimal.NewFromInt(int64(len(recentFees)))).BigInt().Uint64()
}

func ExtractTransfersFromTransaction(ctx context.Context, tx *solana.Transaction, meta *rpc.TransactionMeta, exception *solana.PublicKey) ([]*Transfer, error) {
Expand Down Expand Up @@ -440,13 +449,12 @@ func ExtractTransfersFromTransaction(ctx context.Context, tx *solana.Transaction
}

for index, ix := range msg.Instructions {
baseIndex := int64(index+1) * 10000
if transfer := extractTransfersFromInstruction(&msg, ix, tokenAccounts, owners, transfers); transfer != nil {
if exception != nil && exception.String() == transfer.Receiver {
continue
}
transfer.Signature = hash
transfer.Index = baseIndex
transfer.Index = int64(index)
transfers = append(transfers, transfer)
}

Expand All @@ -456,7 +464,7 @@ func ExtractTransfersFromTransaction(ctx context.Context, tx *solana.Transaction
continue
}
transfer.Signature = hash
transfer.Index = baseIndex + int64(innerIndex) + 1
transfer.Index = (int64(index)+1)*solanaInnerIndexBase + int64(innerIndex)
transfers = append(transfers, transfer)
}
}
Expand All @@ -472,10 +480,23 @@ func ExtractTransferFromTransactionByIndex(ctx context.Context, tx *solana.Trans
msg := tx.Message

var (
tokenAccounts = map[solana.PublicKey]token.Account{}
owners = []*solana.PublicKey{}
innerInstructions = map[uint16][]solana.CompiledInstruction{}
tokenAccounts = map[solana.PublicKey]token.Account{}
owners = []*solana.PublicKey{}
)

for _, inner := range meta.InnerInstructions {
sis := make([]solana.CompiledInstruction, len(inner.Instructions))
for idx, ii := range inner.Instructions {
sis[idx] = solana.CompiledInstruction{
ProgramIDIndex: ii.ProgramIDIndex,
Accounts: ii.Accounts,
Data: ii.Data,
}
}
innerInstructions[inner.Index] = sis
}

bs := meta.PreTokenBalances
bs = append(bs, meta.PostTokenBalances...)
for _, balance := range bs {
Expand All @@ -492,7 +513,36 @@ func ExtractTransferFromTransactionByIndex(ctx context.Context, tx *solana.Trans
}
}

return extractTransfersFromInstruction(&msg, msg.Instructions[index], tokenAccounts, owners, nil)
ix, ok := instructionByTransferIndex(&msg, innerInstructions, index)
if !ok {
return nil
}
return extractTransfersFromInstruction(&msg, ix, tokenAccounts, owners, nil)
}

func instructionByTransferIndex(msg *solana.Message, innerInstructions map[uint16][]solana.CompiledInstruction, index int64) (solana.CompiledInstruction, bool) {
if index < 0 {
return solana.CompiledInstruction{}, false
}

if index < solanaInnerIndexBase {
if index >= int64(len(msg.Instructions)) {
return solana.CompiledInstruction{}, false
}
return msg.Instructions[index], true
Comment on lines +528 to +532
}

outerIndex := index/solanaInnerIndexBase - 1
if outerIndex < 0 || outerIndex >= int64(len(msg.Instructions)) {
return solana.CompiledInstruction{}, false
}

innerIndex := index % solanaInnerIndexBase
inners := innerInstructions[uint16(outerIndex)]
if innerIndex < 0 || innerIndex >= int64(len(inners)) {
return solana.CompiledInstruction{}, false
}
return inners[innerIndex], true
}

func ExtractMintsFromTransaction(tx *solana.Transaction) []string {
Expand Down
Loading
Loading