From 4e01fc6e1217291cec9dc5ce4e24e305b613be36 Mon Sep 17 00:00:00 2001 From: jiedo Date: Sat, 11 May 2024 18:09:49 +0800 Subject: [PATCH] feat: support 5b ticker / self mint --- decimal/decimal.go | 8 ++++++ indexer/brc20_deploy.go | 51 +++++++++++++++++++++++++++++++-------- indexer/brc20_mint.go | 13 +++++++--- indexer/brc20_transfer.go | 13 +++++++--- indexer/init.go | 2 ++ model/model.go | 45 ++++++++++++++++++++++------------ utils/utils.go | 27 +++++++++++++++++++++ 7 files changed, 126 insertions(+), 33 deletions(-) diff --git a/decimal/decimal.go b/decimal/decimal.go index b40d84c..74a2c1a 100644 --- a/decimal/decimal.go +++ b/decimal/decimal.go @@ -245,6 +245,14 @@ func (d *Decimal) IsOverflowUint64() bool { return false } +func (d *Decimal) GetMaxUint64() *Decimal { + if d == nil { + return nil + } + integerPart := new(big.Int).SetUint64(math.MaxUint64) + value := new(big.Int).Mul(integerPart, precisionFactor[d.Precition]) + return &Decimal{Precition: d.Precition, Value: value} +} func (d *Decimal) Float64() float64 { if d == nil { return 0 diff --git a/indexer/brc20_deploy.go b/indexer/brc20_deploy.go index c67b6e0..d444f95 100644 --- a/indexer/brc20_deploy.go +++ b/indexer/brc20_deploy.go @@ -4,11 +4,11 @@ import ( "errors" "log" "strconv" - "strings" "github.com/unisat-wallet/libbrc20-indexer/constant" "github.com/unisat-wallet/libbrc20-indexer/decimal" "github.com/unisat-wallet/libbrc20-indexer/model" + "github.com/unisat-wallet/libbrc20-indexer/utils" ) func (g *BRC20ModuleIndexer) ProcessDeploy(data *model.InscriptionBRC20Data) error { @@ -17,12 +17,22 @@ func (g *BRC20ModuleIndexer) ProcessDeploy(data *model.InscriptionBRC20Data) err return nil } - // check tick/amt - if len(body.BRC20Tick) != 4 { + // check tick + uniqueLowerTicker, err := utils.GetValidUniqueLowerTickerTicker(body.BRC20Tick) + if err != nil { return nil - // return errors.New("deploy, tick length not 4") + // return errors.New("deploy, tick length not 4 or 5") + } + if len(body.BRC20Tick) == 5 { + if body.BRC20SelfMint != "true" { + return nil + // return errors.New("deploy, tick length 5, but not self_mint") + } + if data.Height < g.EnableSelfMintHeight { + return nil + // return errors.New("deploy, tick length 5, but not enabled") + } } - uniqueLowerTicker := strings.ToLower(body.BRC20Tick) if _, ok := g.InscriptionsTickerInfoMap[uniqueLowerTicker]; ok { // dup ticker return nil // return errors.New("deploy, but tick exist") @@ -40,6 +50,10 @@ func (g *BRC20ModuleIndexer) ProcessDeploy(data *model.InscriptionBRC20Data) err tinfo.Data.BRC20Decimal = body.BRC20Decimal tinfo.Data.BRC20Minted = "0" tinfo.InscriptionNumberStart = data.InscriptionNumber + if len(body.BRC20Tick) == 5 && body.BRC20SelfMint == "true" { + tinfo.SelfMint = true + tinfo.Data.BRC20SelfMint = "true" + } // dec if dec, err := strconv.ParseUint(tinfo.Data.BRC20Decimal, 10, 64); err != nil || dec > 18 { @@ -62,10 +76,19 @@ func (g *BRC20ModuleIndexer) ProcessDeploy(data *model.InscriptionBRC20Data) err ) return errors.New("deploy, but max invalid") } else { - if max.Sign() <= 0 || max.IsOverflowUint64() { - return errors.New("deploy, but max invalid (range)") + if max.Sign() < 0 || max.IsOverflowUint64() { + return nil + // return errors.New("deploy, but max invalid (range)") + } + if max.Sign() == 0 { + if tinfo.SelfMint { + tinfo.Max = max.GetMaxUint64() + } else { + return errors.New("deploy, but max invalid (0)") + } + } else { + tinfo.Max = max } - tinfo.Max = max } // lim @@ -77,10 +100,18 @@ func (g *BRC20ModuleIndexer) ProcessDeploy(data *model.InscriptionBRC20Data) err ) return errors.New("deploy, but lim invalid") } else { - if lim.Sign() <= 0 || lim.IsOverflowUint64() { + if lim.Sign() < 0 || lim.IsOverflowUint64() { return errors.New("deploy, but lim invalid (range)") } - tinfo.Limit = lim + if lim.Sign() == 0 { + if tinfo.SelfMint { + tinfo.Limit = lim.GetMaxUint64() + } else { + return errors.New("deploy, but lim invalid (0)") + } + } else { + tinfo.Limit = lim + } } tokenInfo := &model.BRC20TokenInfo{Ticker: body.BRC20Tick, Deploy: tinfo} diff --git a/indexer/brc20_mint.go b/indexer/brc20_mint.go index ca32310..366c5d6 100644 --- a/indexer/brc20_mint.go +++ b/indexer/brc20_mint.go @@ -3,12 +3,12 @@ package indexer import ( "errors" "fmt" - "strings" "time" "github.com/unisat-wallet/libbrc20-indexer/constant" "github.com/unisat-wallet/libbrc20-indexer/decimal" "github.com/unisat-wallet/libbrc20-indexer/model" + "github.com/unisat-wallet/libbrc20-indexer/utils" ) func (g *BRC20ModuleIndexer) ProcessMint(data *model.InscriptionBRC20Data) error { @@ -18,17 +18,22 @@ func (g *BRC20ModuleIndexer) ProcessMint(data *model.InscriptionBRC20Data) error } // check tick - if len(body.BRC20Tick) != 4 { + uniqueLowerTicker, err := utils.GetValidUniqueLowerTickerTicker(body.BRC20Tick) + if err != nil { return nil - // return errors.New("mint, tick length not 4") + // return errors.New("mint, tick length not 4 or 5") } - uniqueLowerTicker := strings.ToLower(body.BRC20Tick) tokenInfo, ok := g.InscriptionsTickerInfoMap[uniqueLowerTicker] if !ok { return nil // return errors.New(fmt.Sprintf("mint %s, but tick not exist", body.BRC20Tick)) } tinfo := tokenInfo.Deploy + if tinfo.SelfMint { + if utils.DecodeInscriptionFromBin(data.Parent) != tinfo.GetInscriptionId() { + return errors.New(fmt.Sprintf("self mint %s, but parent invalid", body.BRC20Tick)) + } + } // check mint amount amt, err := decimal.NewDecimalFromString(body.BRC20Amount, int(tinfo.Decimal)) diff --git a/indexer/brc20_transfer.go b/indexer/brc20_transfer.go index bb3086f..2a3b9b2 100644 --- a/indexer/brc20_transfer.go +++ b/indexer/brc20_transfer.go @@ -129,6 +129,12 @@ func (g *BRC20ModuleIndexer) ProcessTransfer(data *model.InscriptionBRC20Data, t tokenBalance.History = append(tokenBalance.History, toHistory) tokenBalance.HistoryReceive = append(tokenBalance.HistoryReceive, toHistory) + //////////////////////////////////////////////////////////////// + // skip module deposit if self mint for now + if tokenInfo.Deploy.SelfMint { + return nil + } + //////////////////////////////////////////////////////////////// // module conditional approve (black withdraw) if g.ThisTxId != data.TxId { @@ -182,11 +188,12 @@ func (g *BRC20ModuleIndexer) ProcessInscribeTransfer(data *model.InscriptionBRC2 } // check tick - if len(body.BRC20Tick) != 4 { + uniqueLowerTicker, err := utils.GetValidUniqueLowerTickerTicker(body.BRC20Tick) + if err != nil { return nil - // return errors.New("transfer, tick length not 4") + // return errors.New("transfer, tick length not 4 or 5") } - uniqueLowerTicker := strings.ToLower(body.BRC20Tick) + tokenInfo, ok := g.InscriptionsTickerInfoMap[uniqueLowerTicker] if !ok { return nil diff --git a/indexer/init.go b/indexer/init.go index 4719049..887e0e3 100644 --- a/indexer/init.go +++ b/indexer/init.go @@ -9,6 +9,7 @@ import ( ) type BRC20ModuleIndexer struct { + EnableSelfMintHeight uint32 // brc20 base AllHistory []*model.BRC20History UserAllHistory map[string]*model.BRC20UserHistory @@ -194,6 +195,7 @@ func (g *BRC20ModuleIndexer) GenerateApproveEventsByApprove(owner string, balanc func (copyDup *BRC20ModuleIndexer) deepCopyBRC20Data(base *BRC20ModuleIndexer) { // history + copyDup.EnableSelfMintHeight = base.EnableSelfMintHeight // for _, h := range base.AllHistory { // copyDup.AllHistory = append(copyDup.AllHistory, h) // } diff --git a/model/model.go b/model/model.go index f2bbab1..ee90fab 100644 --- a/model/model.go +++ b/model/model.go @@ -34,6 +34,7 @@ type InscriptionBRC20Data struct { PkScript string `json:"-"` InscriptionNumber int64 + Parent []byte ContentBody []byte CreateIdxKey string @@ -54,13 +55,14 @@ func (data *InscriptionBRC20Data) GetInscriptionId() string { } type InscriptionBRC20InfoResp struct { - Operation string `json:"op,omitempty"` - BRC20Tick string `json:"tick,omitempty"` - BRC20Max string `json:"max,omitempty"` - BRC20Limit string `json:"lim,omitempty"` - BRC20Amount string `json:"amt,omitempty"` - BRC20Decimal string `json:"decimal,omitempty"` - BRC20Minted string `json:"minted,omitempty"` + Operation string `json:"op,omitempty"` + BRC20Tick string `json:"tick,omitempty"` + BRC20Max string `json:"max,omitempty"` + BRC20Limit string `json:"lim,omitempty"` + BRC20Amount string `json:"amt,omitempty"` + BRC20Decimal string `json:"decimal,omitempty"` + BRC20Minted string `json:"minted,omitempty"` + BRC20SelfMint string `json:"self_mint,omitempty"` } // decode protocal @@ -113,12 +115,13 @@ func (body *InscriptionBRC20MintTransferContent) Unmarshal(contentBody []byte) ( // decode deploy data type InscriptionBRC20DeployContent struct { - Proto string `json:"p,omitempty"` - Operation string `json:"op,omitempty"` - BRC20Tick string `json:"tick,omitempty"` - BRC20Max string `json:"max,omitempty"` - BRC20Limit string `json:"lim,omitempty"` - BRC20Decimal string `json:"dec,omitempty"` + Proto string `json:"p,omitempty"` + Operation string `json:"op,omitempty"` + BRC20Tick string `json:"tick,omitempty"` + BRC20Max string `json:"max,omitempty"` + BRC20Limit string `json:"lim,omitempty"` + BRC20Decimal string `json:"dec,omitempty"` + BRC20SelfMint string `json:"self_mint,omitempty"` } func (body *InscriptionBRC20DeployContent) Unmarshal(contentBody []byte) (err error) { @@ -135,6 +138,12 @@ func (body *InscriptionBRC20DeployContent) Unmarshal(contentBody []byte) (err er if v, ok := bodyMap["tick"].(string); ok { body.BRC20Tick = v } + if _, ok := bodyMap["self_mint"]; ok { // has self_mint + body.BRC20SelfMint = "false" + } + if v, ok := bodyMap["self_mint"].(string); ok { // self_mint is string + body.BRC20SelfMint = v + } if v, ok := bodyMap["max"].(string); ok { body.BRC20Max = v } @@ -180,7 +189,8 @@ type InscriptionBRC20TickInfo struct { Tick string Amount *decimal.Decimal `json:"-"` //ContentBody []byte `json:"content"` - Meta *InscriptionBRC20Data + Meta *InscriptionBRC20Data + SelfMint bool `json:"-"` Max *decimal.Decimal `json:"-"` Limit *decimal.Decimal `json:"-"` @@ -219,8 +229,10 @@ func (d *InscriptionBRC20TickInfo) GetInscriptionId() string { } func (in *InscriptionBRC20TickInfo) DeepCopy() (copy *InscriptionBRC20TickInfo) { copy = &InscriptionBRC20TickInfo{ - Data: in.Data, - Decimal: in.Decimal, + Tick: in.Tick, + SelfMint: in.SelfMint, + Data: in.Data, + Decimal: in.Decimal, TxId: in.TxId, Idx: in.Idx, @@ -258,6 +270,7 @@ func (in *InscriptionBRC20TickInfo) DeepCopy() (copy *InscriptionBRC20TickInfo) func NewInscriptionBRC20TickInfo(tick, operation string, data *InscriptionBRC20Data) *InscriptionBRC20TickInfo { info := &InscriptionBRC20TickInfo{ + Tick: tick, Data: &InscriptionBRC20InfoResp{ BRC20Tick: tick, Operation: operation, diff --git a/utils/utils.go b/utils/utils.go index e8d1a2d..06ae7ca 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -24,6 +24,13 @@ func DecodeTokensFromSwapPair(tickPair string) (token0, token1 string, err error return token0, token1, nil } +func GetValidUniqueLowerTickerTicker(ticker string) (lowerTicker string, err error) { + if len(ticker) != 4 && len(ticker) != 5 { + return "", errors.New("ticker len invalid") + } + lowerTicker = strings.ToLower(ticker) + return lowerTicker, nil +} // single sha256 hash func GetSha256(data []byte) (hash []byte) { @@ -146,3 +153,23 @@ func GetModuleFromScript(script []byte) (module string, ok bool) { module = fmt.Sprintf("%si%d", HashString(script[2:34]), idx) return module, true } +func DecodeInscriptionFromBin(script []byte) (id string) { + n := len(script) + if n < 32 || n > 36 { + return "" + } + var idx uint32 + if n == 32 { + idx = uint32(0) + } else if n <= 33 { + idx = uint32(script[32]) + } else if n <= 34 { + idx = uint32(binary.LittleEndian.Uint16(script[32:34])) + } else if n <= 35 { + idx = uint32(script[32]) | uint32(script[33])<<8 | uint32(script[34])<<16 + } else if n <= 36 { + idx = binary.LittleEndian.Uint32(script[32:36]) + } + id = fmt.Sprintf("%si%d", HashString(script[:32]), idx) + return id +}