Skip to content

Commit

Permalink
feat(core/btc): add runes decode
Browse files Browse the repository at this point in the history
  • Loading branch information
Gkirito committed Apr 14, 2024
1 parent a2e2b99 commit dbc1736
Show file tree
Hide file tree
Showing 13 changed files with 689 additions and 0 deletions.
10 changes: 10 additions & 0 deletions core/btc/runes/cenotaph.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package runes

type Cenotaph struct {
Etching *Rune
Flaws uint32
Mint *RuneId
}

func (c Cenotaph) artifact() {
}
26 changes: 26 additions & 0 deletions core/btc/runes/edict.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package runes

import (
"github.com/btcsuite/btcd/wire"
"math/big"
)

type Edict struct {
Id RuneId
Amount big.Int
Output uint32
}

func NewEdictFromIntegers(tx *wire.MsgTx, id RuneId, amount big.Int, output big.Int) *Edict {
if output.BitLen() > 32 {
return nil
}
if int(output.Uint64()) > len(tx.TxOut) {
return nil
}
return &Edict{
Id: id,
Amount: amount,
Output: uint32(output.Uint64()),
}
}
42 changes: 42 additions & 0 deletions core/btc/runes/etching.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package runes

import "math/big"

type Etching struct {
Divisibility *byte
Premine *big.Int
Rune *Rune
Spacers *uint32
Symbol *rune
Terms *Terms
Turbo bool
}

const (
MaxDivisibility uint8 = 38
MaxSpacers uint32 = 0b00000111_11111111_11111111_11111111
)

func (e *Etching) Supply() *big.Int {
premine := big.NewInt(0)
if e.Premine != nil {
premine = e.Premine
}
cap := big.NewInt(0)
if e.Terms != nil && e.Terms.Cap != nil {
cap = e.Terms.Cap
}
amount := big.NewInt(0)
if e.Terms != nil && e.Terms.Amount != nil {
amount = e.Terms.Amount
}
mul := new(big.Int).Mul(cap, amount)
if mul.BitLen() > 128 {
return nil
}
supply := new(big.Int).Add(premine, mul)
if supply.BitLen() > 128 {
return nil
}
return supply
}
20 changes: 20 additions & 0 deletions core/btc/runes/flaw.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package runes

type Flaw byte

const (
EdictOutput Flaw = iota
EdictRuneId
InvalidScript
Opcode
SupplyOverflow
TrailingIntegers
TruncatedField
UnrecognizedEvenTag
UnrecognizedFlag
Varint
)

func (f Flaw) Flag() uint32 {
return 1 << uint32(f)
}
61 changes: 61 additions & 0 deletions core/btc/runes/message.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package runes

import (
"github.com/btcsuite/btcd/wire"
"github.com/coming-chat/wallet-SDK/core/btc/runes/runestone"
"math/big"
)

type Message struct {
Flaws uint32
Edicts []Edict
Fields map[string][]big.Int
}

func NewMessageFromIntegers(tx *wire.MsgTx, payload []big.Int) *Message {
var edicts []Edict
fields := make(map[string][]big.Int)
flaws := uint32(0)

for i := 0; i < len(payload); i += 2 {
tag := payload[i]
if tag.Cmp(runestone.Body.ToBigInt()) == 0 {
id := RuneId{}
for j := i + 1; j < len(payload); j += 4 {
if len(payload[j:]) < 4 {
flaws |= TrailingIntegers.Flag()
break
}

next := id.Next(payload[j], payload[j+1])
if next == nil {
flaws |= EdictRuneId.Flag()
break
}

edict := NewEdictFromIntegers(tx, *next, payload[j+2], payload[j+3])
if edict == nil {
flaws |= EdictOutput.Flag()
break
}

id = *next
edicts = append(edicts, *edict)
}
break
}

if i+1 >= len(payload) {
flaws |= TruncatedField.Flag()
break
}
value := payload[i+1]

fields[tag.String()] = append(fields[tag.String()], value)
}
return &Message{
flaws,
edicts,
fields,
}
}
24 changes: 24 additions & 0 deletions core/btc/runes/rune.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package runes

import (
"math/big"
"strings"
)

type Rune struct {
big.Int //uint128
}

func (r *Rune) String() string {
n := new(big.Int).Set(&r.Int)
if n.Cmp(new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 128), big.NewInt(1))) == 0 {
return "BCGDENLQRQWDSLRUGSNLBTMFIJAV"
}
n = n.And(n, big.NewInt(1))
symbol := strings.Builder{}
for n.Cmp(big.NewInt(0)) > 0 {
symbol.WriteByte("ABCDEFGHIJKLMNOPQRSTUVWXYZ"[new(big.Int).Mod(n.Sub(n, big.NewInt(1)), big.NewInt(26)).Int64()])
n = n.Div(n.Sub(n, big.NewInt(1)), big.NewInt(26))
}
return symbol.String()
}
22 changes: 22 additions & 0 deletions core/btc/runes/rune_id.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package runes

import "math/big"

type RuneId struct {
Block uint64
Tx uint32
}

func (r *RuneId) Next(block big.Int, tx big.Int) *RuneId {
if block.BitLen() > 64 || tx.BitLen() > 32 {
return nil
}
newBlock := r.Block + block.Uint64()
var newTx uint32
if newBlock == 0 {
newTx = r.Tx + uint32(tx.Uint64())
} else {
newTx = uint32(tx.Uint64())
}
return &RuneId{newBlock, newTx}
}
Loading

0 comments on commit dbc1736

Please sign in to comment.