2020-11-06 13:40:05 -08:00
|
|
|
package serum
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2020-11-06 14:36:03 -08:00
|
|
|
"math/big"
|
2020-11-06 13:40:05 -08:00
|
|
|
"os"
|
2020-11-06 13:52:19 -08:00
|
|
|
|
2020-11-06 13:40:05 -08:00
|
|
|
"github.com/dfuse-io/solana-go"
|
2020-11-06 14:04:34 -08:00
|
|
|
"github.com/dfuse-io/solana-go/token"
|
2020-11-06 13:40:05 -08:00
|
|
|
)
|
|
|
|
|
|
|
|
type MarketMeta struct {
|
2020-11-06 14:02:52 -08:00
|
|
|
Address solana.PublicKey `json:"address"`
|
|
|
|
Name string `json:"name"`
|
|
|
|
Deprecated bool `json:"deprecated"`
|
|
|
|
QuoteMint *token.Mint
|
|
|
|
BaseMint *token.Mint
|
2020-11-06 13:52:19 -08:00
|
|
|
|
2020-11-06 14:04:34 -08:00
|
|
|
MarketV2 *MarketV2
|
2020-11-06 13:40:05 -08:00
|
|
|
}
|
|
|
|
|
2020-11-06 14:36:03 -08:00
|
|
|
func (m *MarketMeta) baseSplTokenMultiplier() *big.Int {
|
|
|
|
return solana.DecimalsInBigInt(uint32(m.BaseMint.Decimals))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *MarketMeta) quoteSplTokenMultiplier() *big.Int {
|
2020-11-06 17:03:49 -08:00
|
|
|
return solana.DecimalsInBigInt(uint32(m.QuoteMint.Decimals))
|
|
|
|
}
|
|
|
|
|
|
|
|
func divideBnToNumber(numerator, denomiator *big.Int) *big.Int {
|
|
|
|
quotient := new(big.Int).Quo(numerator, denomiator)
|
|
|
|
rem := new(big.Int).Mod(numerator, denomiator)
|
|
|
|
gcd := new(big.Int).GCD(nil, nil, rem, denomiator)
|
|
|
|
n1 := new(big.Int).Quo(rem, gcd)
|
|
|
|
d1 := new(big.Int).Quo(denomiator, gcd)
|
|
|
|
div1 := new(big.Int).Quo(n1, d1)
|
|
|
|
return new(big.Int).Add(quotient, div1)
|
2020-11-06 14:36:03 -08:00
|
|
|
}
|
|
|
|
|
2020-11-06 17:03:49 -08:00
|
|
|
func (m *MarketMeta) PriceLotsToNumber(price *big.Int) *big.Int {
|
2020-11-06 14:36:03 -08:00
|
|
|
ratio := new(big.Int).Mul(big.NewInt(int64(m.MarketV2.QuoteLotSize)), m.baseSplTokenMultiplier())
|
|
|
|
numerator := new(big.Int).Mul(price, ratio)
|
|
|
|
denomiator := new(big.Int).Mul(big.NewInt(int64(m.MarketV2.BaseLotSize)), m.quoteSplTokenMultiplier())
|
2020-11-06 17:03:49 -08:00
|
|
|
return divideBnToNumber(numerator, denomiator)
|
2020-11-06 14:36:03 -08:00
|
|
|
}
|
|
|
|
|
2020-11-06 14:54:26 -08:00
|
|
|
func (m *MarketMeta) BaseSizeLotsToNumber(size *big.Int) *big.Float {
|
|
|
|
numerator := new(big.Int).Mul(size, big.NewInt(int64(m.MarketV2.BaseLotSize)))
|
|
|
|
denomiator := m.baseSplTokenMultiplier()
|
|
|
|
return new(big.Float).Quo(new(big.Float).SetInt(numerator), new(big.Float).SetInt(denomiator))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *MarketMeta) PriceNumberToLots(price *big.Int) *big.Float {
|
2020-11-06 14:36:03 -08:00
|
|
|
numerator := new(big.Int).Mul(price, m.quoteSplTokenMultiplier())
|
|
|
|
numerator = new(big.Int).Mul(numerator, big.NewInt(int64(m.MarketV2.BaseLotSize)))
|
|
|
|
|
|
|
|
denomiator := new(big.Int).Mul(m.baseSplTokenMultiplier(), big.NewInt(int64(m.MarketV2.QuoteLotSize)))
|
|
|
|
return new(big.Float).Quo(new(big.Float).SetInt(numerator), new(big.Float).SetInt(denomiator))
|
|
|
|
}
|
|
|
|
|
2020-11-06 13:40:05 -08:00
|
|
|
func KnownMarket() ([]*MarketMeta, error) {
|
|
|
|
f, err := os.Open("serum/markets.json")
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("unable to retrieve known markets: %w", err)
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
|
|
|
|
dec := json.NewDecoder(f)
|
|
|
|
var markets []*MarketMeta
|
|
|
|
err = dec.Decode(&markets)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("unable to decode known markets: %w", err)
|
|
|
|
}
|
|
|
|
return markets, nil
|
|
|
|
}
|