mirror of
https://github.com/alexgo-io/gaze-brc20-indexer.git
synced 2026-01-12 14:34:54 +08:00
feat: brc20 indexing logic
This commit is contained in:
@@ -50,10 +50,8 @@ CREATE TABLE IF NOT EXISTS "brc20_tick_entry_states" (
|
||||
PRIMARY KEY ("tick", "block_height")
|
||||
);
|
||||
|
||||
CREATE SEQUENCE IF NOT EXISTS brc20_event_id_seq;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "brc20_event_deploys" (
|
||||
"id" BIGINT PRIMARY KEY DEFAULT nextval('brc20_event_id_seq'),
|
||||
"id" BIGINT PRIMARY KEY NOT NULL,
|
||||
"inscription_id" TEXT NOT NULL,
|
||||
"inscription_number" BIGINT NOT NULL,
|
||||
"tick" TEXT NOT NULL, -- lowercase of original_tick
|
||||
@@ -73,7 +71,7 @@ CREATE TABLE IF NOT EXISTS "brc20_event_deploys" (
|
||||
CREATE INDEX IF NOT EXISTS brc20_event_deploys_block_height_idx ON "brc20_event_deploys" USING BTREE ("block_height");
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "brc20_event_mints" (
|
||||
"id" BIGINT PRIMARY KEY DEFAULT nextval('brc20_event_id_seq'),
|
||||
"id" BIGINT PRIMARY KEY NOT NULL,
|
||||
"inscription_id" TEXT NOT NULL,
|
||||
"inscription_number" BIGINT NOT NULL,
|
||||
"tick" TEXT NOT NULL, -- lowercase of original_tick
|
||||
@@ -91,7 +89,7 @@ CREATE TABLE IF NOT EXISTS "brc20_event_mints" (
|
||||
CREATE INDEX IF NOT EXISTS brc20_event_mints_block_height_idx ON "brc20_event_mints" USING BTREE ("block_height");
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "brc20_event_inscribe_transfers" (
|
||||
"id" BIGINT PRIMARY KEY DEFAULT nextval('brc20_event_id_seq'),
|
||||
"id" BIGINT PRIMARY KEY NOT NULL,
|
||||
"inscription_id" TEXT NOT NULL,
|
||||
"inscription_number" BIGINT NOT NULL,
|
||||
"tick" TEXT NOT NULL, -- lowercase of original_tick
|
||||
@@ -108,9 +106,10 @@ CREATE TABLE IF NOT EXISTS "brc20_event_inscribe_transfers" (
|
||||
"amount" DECIMAL NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS brc20_event_inscribe_transfers_block_height_idx ON "brc20_event_inscribe_transfers" USING BTREE ("block_height");
|
||||
CREATE INDEX IF NOT EXISTS brc20_event_inscribe_transfers_inscription_id_idx ON "brc20_event_inscribe_transfers" USING BTREE ("inscription_id"); -- used for validating transfer transfer events
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "brc20_event_transfer_transfers" (
|
||||
"id" BIGINT PRIMARY KEY DEFAULT nextval('brc20_event_id_seq'),
|
||||
"id" BIGINT PRIMARY KEY NOT NULL,
|
||||
"inscription_id" TEXT NOT NULL,
|
||||
"inscription_number" BIGINT NOT NULL,
|
||||
"tick" TEXT NOT NULL, -- lowercase of original_tick
|
||||
@@ -126,6 +125,7 @@ CREATE TABLE IF NOT EXISTS "brc20_event_transfer_transfers" (
|
||||
"to_pkscript" TEXT NOT NULL,
|
||||
"to_satpoint" TEXT NOT NULL,
|
||||
"to_output_index" INT NOT NULL,
|
||||
"spent_as_fee" BOOLEAN NOT NULL,
|
||||
"amount" DECIMAL NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS brc20_event_transfer_transfers_block_height_idx ON "brc20_event_transfer_transfers" USING BTREE ("block_height");
|
||||
@@ -156,6 +156,7 @@ CREATE TABLE IF NOT EXISTS "brc20_inscription_entries" (
|
||||
"created_at" TIMESTAMP NOT NULL,
|
||||
"created_at_height" INT NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS brc20_inscription_entries_id_number_idx ON "brc20_inscription_entries" USING BTREE ("id", "number");
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "brc20_inscription_entry_states" (
|
||||
"id" TEXT NOT NULL,
|
||||
@@ -168,6 +169,8 @@ CREATE TABLE IF NOT EXISTS "brc20_inscription_transfers" (
|
||||
"inscription_id" TEXT NOT NULL,
|
||||
"block_height" INT NOT NULL,
|
||||
"tx_index" INT NOT NULL,
|
||||
"tx_hash" TEXT NOT NULL,
|
||||
"from_input_index" INT NOT NULL,
|
||||
"old_satpoint_tx_hash" TEXT,
|
||||
"old_satpoint_out_idx" INT,
|
||||
"old_satpoint_offset" BIGINT,
|
||||
@@ -177,6 +180,7 @@ CREATE TABLE IF NOT EXISTS "brc20_inscription_transfers" (
|
||||
"new_pkscript" TEXT NOT NULL,
|
||||
"new_output_value" BIGINT NOT NULL,
|
||||
"sent_as_fee" BOOLEAN NOT NULL,
|
||||
"transfer_count" INT NOT NULL,
|
||||
PRIMARY KEY ("inscription_id", "block_height", "tx_index")
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS brc20_inscription_transfers_block_height_tx_index_idx ON "brc20_inscription_transfers" USING BTREE ("block_height", "tx_index");
|
||||
|
||||
@@ -35,6 +35,43 @@ SELECT * FROM "brc20_tick_entries"
|
||||
LEFT JOIN "states" ON "brc20_tick_entries"."tick" = "states"."tick"
|
||||
WHERE "brc20_tick_entries"."tick" = ANY(@ticks::text[]);
|
||||
|
||||
-- name: GetInscriptionNumbersByIds :many
|
||||
SELECT id, number FROM "brc20_inscription_entries" WHERE "id" = ANY(@inscription_ids::text[]);
|
||||
|
||||
-- name: GetInscriptionParentsByIds :many
|
||||
SELECT id, parents FROM "brc20_inscription_entries" WHERE "id" = ANY(@inscription_ids::text[]);
|
||||
|
||||
-- name: GetLatestEventIds :one
|
||||
WITH "latest_deploy_id" AS (
|
||||
SELECT "id" FROM "brc20_event_deploys" ORDER BY "id" DESC LIMIT 1
|
||||
),
|
||||
"latest_mint_id" AS (
|
||||
SELECT "id" FROM "brc20_event_mints" ORDER BY "id" DESC LIMIT 1
|
||||
),
|
||||
"latest_inscribe_transfer_id" AS (
|
||||
SELECT "id" FROM "brc20_event_inscribe_transfers" ORDER BY "id" DESC LIMIT 1
|
||||
),
|
||||
"latest_transfer_transfer_id" AS (
|
||||
SELECT "id" FROM "brc20_event_transfer_transfers" ORDER BY "id" DESC LIMIT 1
|
||||
)
|
||||
SELECT
|
||||
(SELECT "id" FROM "latest_deploy_id") AS "event_deploy_id",
|
||||
(SELECT "id" FROM "latest_mint_id") AS "event_mint_id",
|
||||
(SELECT "id" FROM "latest_inscribe_transfer_id") AS "event_inscribe_transfer_id",
|
||||
(SELECT "id" FROM "latest_transfer_transfer_id") AS "event_transfer_transfer_id";
|
||||
|
||||
-- name: GetBalancesBatchAtHeight :many
|
||||
SELECT DISTINCT ON ("brc20_balances"."pkscript", "brc20_balances"."tick") "brc20_balances".* FROM "brc20_balances"
|
||||
INNER JOIN (
|
||||
SELECT
|
||||
unnest(@pkscript_arr::text[]) AS "pkscript",
|
||||
unnest(@tick_arr::text[]) AS "tick"
|
||||
) "queries" ON "brc20_balances"."pkscript" = "queries"."pkscript" AND "brc20_balances"."tick" = "queries"."tick" AND "brc20_balances"."block_height" <= @block_height
|
||||
ORDER BY "brc20_balances"."pkscript", "brc20_balances"."tick", "block_height" DESC;
|
||||
|
||||
-- name: GetEventInscribeTransfersByInscriptionIds :many
|
||||
SELECT * FROM "brc20_event_inscribe_transfers" WHERE "inscription_id" = ANY(@inscription_ids::text[]);
|
||||
|
||||
-- name: CreateIndexedBlock :exec
|
||||
INSERT INTO "brc20_indexed_blocks" ("height", "hash", "event_hash", "cumulative_event_hash") VALUES ($1, $2, $3, $4);
|
||||
|
||||
@@ -54,7 +91,7 @@ INSERT INTO "brc20_inscription_entries" ("id", "number", "sequence_number", "del
|
||||
INSERT INTO "brc20_inscription_entry_states" ("id", "block_height", "transfer_count") VALUES ($1, $2, $3);
|
||||
|
||||
-- name: CreateInscriptionTransfers :batchexec
|
||||
INSERT INTO "brc20_inscription_transfers" ("inscription_id", "block_height", "tx_index", "old_satpoint_tx_hash", "old_satpoint_out_idx", "old_satpoint_offset", "new_satpoint_tx_hash", "new_satpoint_out_idx", "new_satpoint_offset", "new_pkscript", "new_output_value", "sent_as_fee") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12);
|
||||
INSERT INTO "brc20_inscription_transfers" ("inscription_id", "block_height", "tx_index", "tx_hash", "from_input_index", "old_satpoint_tx_hash", "old_satpoint_out_idx", "old_satpoint_offset", "new_satpoint_tx_hash", "new_satpoint_out_idx", "new_satpoint_offset", "new_pkscript", "new_output_value", "sent_as_fee", "transfer_count") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15);
|
||||
|
||||
-- name: CreateEventDeploys :batchexec
|
||||
INSERT INTO "brc20_event_deploys" ("inscription_id", "inscription_number", "tick", "original_tick", "tx_hash", "block_height", "tx_index", "timestamp", "pkscript", "satpoint", "total_supply", "decimals", "limit_per_mint", "is_self_mint") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14);
|
||||
@@ -66,7 +103,7 @@ INSERT INTO "brc20_event_mints" ("inscription_id", "inscription_number", "tick",
|
||||
INSERT INTO "brc20_event_inscribe_transfers" ("inscription_id", "inscription_number", "tick", "original_tick", "tx_hash", "block_height", "tx_index", "timestamp", "pkscript", "satpoint", "output_index", "sats_amount", "amount") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13);
|
||||
|
||||
-- name: CreateEventTransferTransfers :batchexec
|
||||
INSERT INTO "brc20_event_transfer_transfers" ("inscription_id", "inscription_number", "tick", "original_tick", "tx_hash", "block_height", "tx_index", "timestamp", "from_pkscript", "from_satpoint", "from_input_index", "to_pkscript", "to_satpoint", "to_output_index", "amount") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15);
|
||||
INSERT INTO "brc20_event_transfer_transfers" ("inscription_id", "inscription_number", "tick", "original_tick", "tx_hash", "block_height", "tx_index", "timestamp", "from_pkscript", "from_satpoint", "from_input_index", "to_pkscript", "to_satpoint", "to_output_index", "spent_as_fee", "amount") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16);
|
||||
|
||||
-- name: DeleteIndexedBlocksSinceHeight :exec
|
||||
DELETE FROM "brc20_indexed_blocks" WHERE "height" >= $1;
|
||||
|
||||
@@ -28,7 +28,12 @@ type BRC20ReaderDataGateway interface {
|
||||
GetProcessorStats(ctx context.Context) (*entity.ProcessorStats, error)
|
||||
GetInscriptionTransfersInOutPoints(ctx context.Context, outPoints []wire.OutPoint) (map[ordinals.SatPoint][]*entity.InscriptionTransfer, error)
|
||||
GetInscriptionEntriesByIds(ctx context.Context, ids []ordinals.InscriptionId) (map[ordinals.InscriptionId]*ordinals.InscriptionEntry, error)
|
||||
GetInscriptionNumbersByIds(ctx context.Context, ids []ordinals.InscriptionId) (map[ordinals.InscriptionId]int64, error)
|
||||
GetInscriptionParentsByIds(ctx context.Context, ids []ordinals.InscriptionId) (map[ordinals.InscriptionId]ordinals.InscriptionId, error)
|
||||
GetBalancesBatchAtHeight(ctx context.Context, blockHeight uint64, queries []GetBalancesBatchAtHeightQuery) (map[string]map[string]*entity.Balance, error)
|
||||
GetTickEntriesByTicks(ctx context.Context, ticks []string) (map[string]*entity.TickEntry, error)
|
||||
GetEventInscribeTransfersByInscriptionIds(ctx context.Context, ids []ordinals.InscriptionId) (map[ordinals.InscriptionId]*entity.EventInscribeTransfer, error)
|
||||
GetLatestEventId(ctx context.Context) (uint64, error)
|
||||
}
|
||||
|
||||
type BRC20WriterDataGateway interface {
|
||||
@@ -58,3 +63,9 @@ type BRC20WriterDataGateway interface {
|
||||
DeleteInscriptionEntryStatesSinceHeight(ctx context.Context, height uint64) error
|
||||
DeleteInscriptionTransfersSinceHeight(ctx context.Context, height uint64) error
|
||||
}
|
||||
|
||||
type GetBalancesBatchAtHeightQuery struct {
|
||||
PkScriptHex string
|
||||
Tick string
|
||||
BlockHeight uint64
|
||||
}
|
||||
|
||||
11
modules/brc20/internal/entity/balance.go
Normal file
11
modules/brc20/internal/entity/balance.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package entity
|
||||
|
||||
import "github.com/shopspring/decimal"
|
||||
|
||||
type Balance struct {
|
||||
PkScript []byte
|
||||
Tick string
|
||||
BlockHeight uint64
|
||||
OverallBalance decimal.Decimal
|
||||
AvailableBalance decimal.Decimal
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
type EventDeploy struct {
|
||||
Id uint64
|
||||
InscriptionId ordinals.InscriptionId
|
||||
InscriptionNumber uint64
|
||||
InscriptionNumber int64
|
||||
Tick string
|
||||
OriginalTick string
|
||||
TxHash chainhash.Hash
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
type EventInscribeTransfer struct {
|
||||
Id uint64
|
||||
InscriptionId ordinals.InscriptionId
|
||||
InscriptionNumber uint64
|
||||
InscriptionNumber int64
|
||||
Tick string
|
||||
OriginalTick string
|
||||
TxHash chainhash.Hash
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
type EventMint struct {
|
||||
Id uint64
|
||||
InscriptionId ordinals.InscriptionId
|
||||
InscriptionNumber uint64
|
||||
InscriptionNumber int64
|
||||
Tick string
|
||||
OriginalTick string
|
||||
TxHash chainhash.Hash
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
type EventTransferTransfer struct {
|
||||
Id uint64
|
||||
InscriptionId ordinals.InscriptionId
|
||||
InscriptionNumber uint64
|
||||
InscriptionNumber int64
|
||||
Tick string
|
||||
OriginalTick string
|
||||
TxHash chainhash.Hash
|
||||
@@ -25,5 +25,6 @@ type EventTransferTransfer struct {
|
||||
ToPkScript []byte
|
||||
ToSatPoint ordinals.SatPoint
|
||||
ToOutputIndex uint32
|
||||
SpentAsFee bool
|
||||
Amount decimal.Decimal
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
type OriginOld struct {
|
||||
Content []byte
|
||||
OldSatPoint ordinals.SatPoint
|
||||
InputIndex uint32
|
||||
}
|
||||
type OriginNew struct {
|
||||
Inscription ordinals.Inscription
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
package entity
|
||||
|
||||
import "github.com/gaze-network/indexer-network/modules/brc20/internal/ordinals"
|
||||
import (
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/gaze-network/indexer-network/modules/brc20/internal/ordinals"
|
||||
)
|
||||
|
||||
type InscriptionTransfer struct {
|
||||
InscriptionId ordinals.InscriptionId
|
||||
BlockHeight uint64
|
||||
TxIndex uint32
|
||||
TxHash chainhash.Hash
|
||||
Content []byte
|
||||
FromInputIndex uint32
|
||||
OldSatPoint ordinals.SatPoint
|
||||
NewSatPoint ordinals.SatPoint
|
||||
NewPkScript []byte
|
||||
NewOutputValue uint64
|
||||
SentAsFee bool
|
||||
TransferCount uint32
|
||||
}
|
||||
|
||||
@@ -110,6 +110,110 @@ func (r *Repository) GetInscriptionEntriesByIds(ctx context.Context, ids []ordin
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *Repository) GetInscriptionNumbersByIds(ctx context.Context, ids []ordinals.InscriptionId) (map[ordinals.InscriptionId]int64, error) {
|
||||
idStrs := lo.Map(ids, func(id ordinals.InscriptionId, _ int) string { return id.String() })
|
||||
models, err := r.queries.GetInscriptionNumbersByIds(ctx, idStrs)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
result := make(map[ordinals.InscriptionId]int64)
|
||||
for _, model := range models {
|
||||
inscriptionId, err := ordinals.NewInscriptionIdFromString(model.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse inscription id")
|
||||
}
|
||||
result[inscriptionId] = model.Number
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *Repository) GetInscriptionParentsByIds(ctx context.Context, ids []ordinals.InscriptionId) (map[ordinals.InscriptionId]ordinals.InscriptionId, error) {
|
||||
idStrs := lo.Map(ids, func(id ordinals.InscriptionId, _ int) string { return id.String() })
|
||||
models, err := r.queries.GetInscriptionParentsByIds(ctx, idStrs)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
result := make(map[ordinals.InscriptionId]ordinals.InscriptionId)
|
||||
for _, model := range models {
|
||||
if len(model.Parents) == 0 {
|
||||
// no parent
|
||||
continue
|
||||
}
|
||||
if len(model.Parents) > 1 {
|
||||
// sanity check, should not happen since 0.14 ord supports only 1 parent
|
||||
continue
|
||||
}
|
||||
inscriptionId, err := ordinals.NewInscriptionIdFromString(model.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse inscription id")
|
||||
}
|
||||
parentId, err := ordinals.NewInscriptionIdFromString(model.Parents[0])
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse parent id")
|
||||
}
|
||||
result[inscriptionId] = parentId
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *Repository) GetLatestEventId(ctx context.Context) (uint64, error) {
|
||||
row, err := r.queries.GetLatestEventIds(ctx)
|
||||
if err != nil {
|
||||
return 0, errors.WithStack(err)
|
||||
}
|
||||
return uint64(max(row.EventDeployID, row.EventMintID, row.EventInscribeTransferID, row.EventTransferTransferID)), nil
|
||||
}
|
||||
|
||||
func (r *Repository) GetBalancesBatchAtHeight(ctx context.Context, blockHeight uint64, queries []datagateway.GetBalancesBatchAtHeightQuery) (map[string]map[string]*entity.Balance, error) {
|
||||
pkScripts := make([]string, 0)
|
||||
ticks := make([]string, 0)
|
||||
for _, query := range queries {
|
||||
pkScripts = append(pkScripts, query.PkScriptHex)
|
||||
ticks = append(ticks, query.Tick)
|
||||
}
|
||||
models, err := r.queries.GetBalancesBatchAtHeight(ctx, gen.GetBalancesBatchAtHeightParams{
|
||||
PkscriptArr: pkScripts,
|
||||
TickArr: ticks,
|
||||
BlockHeight: int32(blockHeight),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
result := make(map[string]map[string]*entity.Balance)
|
||||
for _, model := range models {
|
||||
balance, err := mapBalanceModelToType(model)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse balance model")
|
||||
}
|
||||
if _, ok := result[model.Pkscript]; !ok {
|
||||
result[model.Pkscript] = make(map[string]*entity.Balance)
|
||||
}
|
||||
result[model.Pkscript][model.Tick] = &balance
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *Repository) GetEventInscribeTransfersByInscriptionIds(ctx context.Context, ids []ordinals.InscriptionId) (map[ordinals.InscriptionId]*entity.EventInscribeTransfer, error) {
|
||||
idStrs := lo.Map(ids, func(id ordinals.InscriptionId, _ int) string { return id.String() })
|
||||
models, err := r.queries.GetEventInscribeTransfersByInscriptionIds(ctx, idStrs)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
result := make(map[ordinals.InscriptionId]*entity.EventInscribeTransfer)
|
||||
for _, model := range models {
|
||||
event, err := mapEventInscribeTransferModelToType(model)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse event inscribe transfer model")
|
||||
}
|
||||
result[event.InscriptionId] = &event
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *Repository) GetTickEntriesByTicks(ctx context.Context, ticks []string) (map[string]*entity.TickEntry, error) {
|
||||
models, err := r.queries.GetTickEntriesByTicks(ctx, ticks)
|
||||
if err != nil {
|
||||
|
||||
@@ -231,7 +231,7 @@ func (b *CreateEventMintsBatchResults) Close() error {
|
||||
}
|
||||
|
||||
const createEventTransferTransfers = `-- name: CreateEventTransferTransfers :batchexec
|
||||
INSERT INTO "brc20_event_transfer_transfers" ("inscription_id", "inscription_number", "tick", "original_tick", "tx_hash", "block_height", "tx_index", "timestamp", "from_pkscript", "from_satpoint", "from_input_index", "to_pkscript", "to_satpoint", "to_output_index", "amount") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
|
||||
INSERT INTO "brc20_event_transfer_transfers" ("inscription_id", "inscription_number", "tick", "original_tick", "tx_hash", "block_height", "tx_index", "timestamp", "from_pkscript", "from_satpoint", "from_input_index", "to_pkscript", "to_satpoint", "to_output_index", "spent_as_fee", "amount") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)
|
||||
`
|
||||
|
||||
type CreateEventTransferTransfersBatchResults struct {
|
||||
@@ -255,6 +255,7 @@ type CreateEventTransferTransfersParams struct {
|
||||
ToPkscript string
|
||||
ToSatpoint string
|
||||
ToOutputIndex int32
|
||||
SpentAsFee bool
|
||||
Amount pgtype.Numeric
|
||||
}
|
||||
|
||||
@@ -276,6 +277,7 @@ func (q *Queries) CreateEventTransferTransfers(ctx context.Context, arg []Create
|
||||
a.ToPkscript,
|
||||
a.ToSatpoint,
|
||||
a.ToOutputIndex,
|
||||
a.SpentAsFee,
|
||||
a.Amount,
|
||||
}
|
||||
batch.Queue(createEventTransferTransfers, vals...)
|
||||
@@ -432,7 +434,7 @@ func (b *CreateInscriptionEntryStatesBatchResults) Close() error {
|
||||
}
|
||||
|
||||
const createInscriptionTransfers = `-- name: CreateInscriptionTransfers :batchexec
|
||||
INSERT INTO "brc20_inscription_transfers" ("inscription_id", "block_height", "tx_index", "old_satpoint_tx_hash", "old_satpoint_out_idx", "old_satpoint_offset", "new_satpoint_tx_hash", "new_satpoint_out_idx", "new_satpoint_offset", "new_pkscript", "new_output_value", "sent_as_fee") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
|
||||
INSERT INTO "brc20_inscription_transfers" ("inscription_id", "block_height", "tx_index", "tx_hash", "from_input_index", "old_satpoint_tx_hash", "old_satpoint_out_idx", "old_satpoint_offset", "new_satpoint_tx_hash", "new_satpoint_out_idx", "new_satpoint_offset", "new_pkscript", "new_output_value", "sent_as_fee", "transfer_count") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
|
||||
`
|
||||
|
||||
type CreateInscriptionTransfersBatchResults struct {
|
||||
@@ -445,6 +447,8 @@ type CreateInscriptionTransfersParams struct {
|
||||
InscriptionID string
|
||||
BlockHeight int32
|
||||
TxIndex int32
|
||||
TxHash string
|
||||
FromInputIndex int32
|
||||
OldSatpointTxHash pgtype.Text
|
||||
OldSatpointOutIdx pgtype.Int4
|
||||
OldSatpointOffset pgtype.Int8
|
||||
@@ -454,6 +458,7 @@ type CreateInscriptionTransfersParams struct {
|
||||
NewPkscript string
|
||||
NewOutputValue int64
|
||||
SentAsFee bool
|
||||
TransferCount int32
|
||||
}
|
||||
|
||||
func (q *Queries) CreateInscriptionTransfers(ctx context.Context, arg []CreateInscriptionTransfersParams) *CreateInscriptionTransfersBatchResults {
|
||||
@@ -463,6 +468,8 @@ func (q *Queries) CreateInscriptionTransfers(ctx context.Context, arg []CreateIn
|
||||
a.InscriptionID,
|
||||
a.BlockHeight,
|
||||
a.TxIndex,
|
||||
a.TxHash,
|
||||
a.FromInputIndex,
|
||||
a.OldSatpointTxHash,
|
||||
a.OldSatpointOutIdx,
|
||||
a.OldSatpointOffset,
|
||||
@@ -472,6 +479,7 @@ func (q *Queries) CreateInscriptionTransfers(ctx context.Context, arg []CreateIn
|
||||
a.NewPkscript,
|
||||
a.NewOutputValue,
|
||||
a.SentAsFee,
|
||||
a.TransferCount,
|
||||
}
|
||||
batch.Queue(createInscriptionTransfers, vals...)
|
||||
}
|
||||
|
||||
@@ -161,6 +161,87 @@ func (q *Queries) DeleteTickEntryStatesSinceHeight(ctx context.Context, blockHei
|
||||
return err
|
||||
}
|
||||
|
||||
const getBalancesBatchAtHeight = `-- name: GetBalancesBatchAtHeight :many
|
||||
SELECT DISTINCT ON ("brc20_balances"."pkscript", "brc20_balances"."tick") brc20_balances.pkscript, brc20_balances.block_height, brc20_balances.tick, brc20_balances.overall_balance, brc20_balances.available_balance FROM "brc20_balances"
|
||||
INNER JOIN (
|
||||
SELECT
|
||||
unnest($1::text[]) AS "pkscript",
|
||||
unnest($2::text[]) AS "tick"
|
||||
) "queries" ON "brc20_balances"."pkscript" = "queries"."pkscript" AND "brc20_balances"."tick" = "queries"."tick" AND "brc20_balances"."block_height" <= $3
|
||||
ORDER BY "brc20_balances"."pkscript", "brc20_balances"."tick", "block_height" DESC
|
||||
`
|
||||
|
||||
type GetBalancesBatchAtHeightParams struct {
|
||||
PkscriptArr []string
|
||||
TickArr []string
|
||||
BlockHeight int32
|
||||
}
|
||||
|
||||
func (q *Queries) GetBalancesBatchAtHeight(ctx context.Context, arg GetBalancesBatchAtHeightParams) ([]Brc20Balance, error) {
|
||||
rows, err := q.db.Query(ctx, getBalancesBatchAtHeight, arg.PkscriptArr, arg.TickArr, arg.BlockHeight)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Brc20Balance
|
||||
for rows.Next() {
|
||||
var i Brc20Balance
|
||||
if err := rows.Scan(
|
||||
&i.Pkscript,
|
||||
&i.BlockHeight,
|
||||
&i.Tick,
|
||||
&i.OverallBalance,
|
||||
&i.AvailableBalance,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getEventInscribeTransfersByInscriptionIds = `-- name: GetEventInscribeTransfersByInscriptionIds :many
|
||||
SELECT id, inscription_id, inscription_number, tick, original_tick, tx_hash, block_height, tx_index, timestamp, pkscript, satpoint, output_index, sats_amount, amount FROM "brc20_event_inscribe_transfers" WHERE "inscription_id" = ANY($1::text[])
|
||||
`
|
||||
|
||||
func (q *Queries) GetEventInscribeTransfersByInscriptionIds(ctx context.Context, inscriptionIds []string) ([]Brc20EventInscribeTransfer, error) {
|
||||
rows, err := q.db.Query(ctx, getEventInscribeTransfersByInscriptionIds, inscriptionIds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Brc20EventInscribeTransfer
|
||||
for rows.Next() {
|
||||
var i Brc20EventInscribeTransfer
|
||||
if err := rows.Scan(
|
||||
&i.Id,
|
||||
&i.InscriptionID,
|
||||
&i.InscriptionNumber,
|
||||
&i.Tick,
|
||||
&i.OriginalTick,
|
||||
&i.TxHash,
|
||||
&i.BlockHeight,
|
||||
&i.TxIndex,
|
||||
&i.Timestamp,
|
||||
&i.Pkscript,
|
||||
&i.Satpoint,
|
||||
&i.OutputIndex,
|
||||
&i.SatsAmount,
|
||||
&i.Amount,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getIndexedBlockByHeight = `-- name: GetIndexedBlockByHeight :one
|
||||
SELECT height, hash, event_hash, cumulative_event_hash FROM "brc20_indexed_blocks" WHERE "height" = $1
|
||||
`
|
||||
@@ -247,8 +328,66 @@ func (q *Queries) GetInscriptionEntriesByIds(ctx context.Context, inscriptionIds
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getInscriptionNumbersByIds = `-- name: GetInscriptionNumbersByIds :many
|
||||
SELECT id, number FROM "brc20_inscription_entries" WHERE "id" = ANY($1::text[])
|
||||
`
|
||||
|
||||
type GetInscriptionNumbersByIdsRow struct {
|
||||
Id string
|
||||
Number int64
|
||||
}
|
||||
|
||||
func (q *Queries) GetInscriptionNumbersByIds(ctx context.Context, inscriptionIds []string) ([]GetInscriptionNumbersByIdsRow, error) {
|
||||
rows, err := q.db.Query(ctx, getInscriptionNumbersByIds, inscriptionIds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetInscriptionNumbersByIdsRow
|
||||
for rows.Next() {
|
||||
var i GetInscriptionNumbersByIdsRow
|
||||
if err := rows.Scan(&i.Id, &i.Number); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getInscriptionParentsByIds = `-- name: GetInscriptionParentsByIds :many
|
||||
SELECT id, parents FROM "brc20_inscription_entries" WHERE "id" = ANY($1::text[])
|
||||
`
|
||||
|
||||
type GetInscriptionParentsByIdsRow struct {
|
||||
Id string
|
||||
Parents []string
|
||||
}
|
||||
|
||||
func (q *Queries) GetInscriptionParentsByIds(ctx context.Context, inscriptionIds []string) ([]GetInscriptionParentsByIdsRow, error) {
|
||||
rows, err := q.db.Query(ctx, getInscriptionParentsByIds, inscriptionIds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetInscriptionParentsByIdsRow
|
||||
for rows.Next() {
|
||||
var i GetInscriptionParentsByIdsRow
|
||||
if err := rows.Scan(&i.Id, &i.Parents); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getInscriptionTransfersInOutPoints = `-- name: GetInscriptionTransfersInOutPoints :many
|
||||
SELECT it.inscription_id, it.block_height, it.tx_index, it.old_satpoint_tx_hash, it.old_satpoint_out_idx, it.old_satpoint_offset, it.new_satpoint_tx_hash, it.new_satpoint_out_idx, it.new_satpoint_offset, it.new_pkscript, it.new_output_value, it.sent_as_fee, "ie"."content" FROM (
|
||||
SELECT it.inscription_id, it.block_height, it.tx_index, it.tx_hash, it.from_input_index, it.old_satpoint_tx_hash, it.old_satpoint_out_idx, it.old_satpoint_offset, it.new_satpoint_tx_hash, it.new_satpoint_out_idx, it.new_satpoint_offset, it.new_pkscript, it.new_output_value, it.sent_as_fee, it.transfer_count, "ie"."content" FROM (
|
||||
SELECT
|
||||
unnest($1::text[]) AS "tx_hash",
|
||||
unnest($2::int[]) AS "tx_out_idx"
|
||||
@@ -266,6 +405,8 @@ type GetInscriptionTransfersInOutPointsRow struct {
|
||||
InscriptionID string
|
||||
BlockHeight int32
|
||||
TxIndex int32
|
||||
TxHash string
|
||||
FromInputIndex int32
|
||||
OldSatpointTxHash pgtype.Text
|
||||
OldSatpointOutIdx pgtype.Int4
|
||||
OldSatpointOffset pgtype.Int8
|
||||
@@ -275,6 +416,7 @@ type GetInscriptionTransfersInOutPointsRow struct {
|
||||
NewPkscript string
|
||||
NewOutputValue int64
|
||||
SentAsFee bool
|
||||
TransferCount int32
|
||||
Content []byte
|
||||
}
|
||||
|
||||
@@ -291,6 +433,8 @@ func (q *Queries) GetInscriptionTransfersInOutPoints(ctx context.Context, arg Ge
|
||||
&i.InscriptionID,
|
||||
&i.BlockHeight,
|
||||
&i.TxIndex,
|
||||
&i.TxHash,
|
||||
&i.FromInputIndex,
|
||||
&i.OldSatpointTxHash,
|
||||
&i.OldSatpointOutIdx,
|
||||
&i.OldSatpointOffset,
|
||||
@@ -300,6 +444,7 @@ func (q *Queries) GetInscriptionTransfersInOutPoints(ctx context.Context, arg Ge
|
||||
&i.NewPkscript,
|
||||
&i.NewOutputValue,
|
||||
&i.SentAsFee,
|
||||
&i.TransferCount,
|
||||
&i.Content,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
@@ -312,6 +457,45 @@ func (q *Queries) GetInscriptionTransfersInOutPoints(ctx context.Context, arg Ge
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getLatestEventIds = `-- name: GetLatestEventIds :one
|
||||
WITH "latest_deploy_id" AS (
|
||||
SELECT "id" FROM "brc20_event_deploys" ORDER BY "id" DESC LIMIT 1
|
||||
),
|
||||
"latest_mint_id" AS (
|
||||
SELECT "id" FROM "brc20_event_mints" ORDER BY "id" DESC LIMIT 1
|
||||
),
|
||||
"latest_inscribe_transfer_id" AS (
|
||||
SELECT "id" FROM "brc20_event_inscribe_transfers" ORDER BY "id" DESC LIMIT 1
|
||||
),
|
||||
"latest_transfer_transfer_id" AS (
|
||||
SELECT "id" FROM "brc20_event_transfer_transfers" ORDER BY "id" DESC LIMIT 1
|
||||
)
|
||||
SELECT
|
||||
(SELECT "id" FROM "latest_deploy_id") AS "event_deploy_id",
|
||||
(SELECT "id" FROM "latest_mint_id") AS "event_mint_id",
|
||||
(SELECT "id" FROM "latest_inscribe_transfer_id") AS "event_inscribe_transfer_id",
|
||||
(SELECT "id" FROM "latest_transfer_transfer_id") AS "event_transfer_transfer_id"
|
||||
`
|
||||
|
||||
type GetLatestEventIdsRow struct {
|
||||
EventDeployID int64
|
||||
EventMintID int64
|
||||
EventInscribeTransferID int64
|
||||
EventTransferTransferID int64
|
||||
}
|
||||
|
||||
func (q *Queries) GetLatestEventIds(ctx context.Context) (GetLatestEventIdsRow, error) {
|
||||
row := q.db.QueryRow(ctx, getLatestEventIds)
|
||||
var i GetLatestEventIdsRow
|
||||
err := row.Scan(
|
||||
&i.EventDeployID,
|
||||
&i.EventMintID,
|
||||
&i.EventInscribeTransferID,
|
||||
&i.EventTransferTransferID,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getLatestIndexedBlock = `-- name: GetLatestIndexedBlock :one
|
||||
SELECT height, hash, event_hash, cumulative_event_hash FROM "brc20_indexed_blocks" ORDER BY "height" DESC LIMIT 1
|
||||
`
|
||||
|
||||
@@ -83,6 +83,7 @@ type Brc20EventTransferTransfer struct {
|
||||
ToPkscript string
|
||||
ToSatpoint string
|
||||
ToOutputIndex int32
|
||||
SpentAsFee bool
|
||||
Amount pgtype.Numeric
|
||||
}
|
||||
|
||||
@@ -130,6 +131,8 @@ type Brc20InscriptionTransfer struct {
|
||||
InscriptionID string
|
||||
BlockHeight int32
|
||||
TxIndex int32
|
||||
TxHash string
|
||||
FromInputIndex int32
|
||||
OldSatpointTxHash pgtype.Text
|
||||
OldSatpointOutIdx pgtype.Int4
|
||||
OldSatpointOffset pgtype.Int8
|
||||
@@ -139,6 +142,7 @@ type Brc20InscriptionTransfer struct {
|
||||
NewPkscript string
|
||||
NewOutputValue int64
|
||||
SentAsFee bool
|
||||
TransferCount int32
|
||||
}
|
||||
|
||||
type Brc20ProcessorStat struct {
|
||||
|
||||
@@ -257,6 +257,10 @@ func mapInscriptionTransferModelToType(src gen.GetInscriptionTransfersInOutPoint
|
||||
if err != nil {
|
||||
return entity.InscriptionTransfer{}, errors.Wrap(err, "invalid inscription id")
|
||||
}
|
||||
txHash, err := chainhash.NewHashFromStr(src.TxHash)
|
||||
if err != nil {
|
||||
return entity.InscriptionTransfer{}, errors.Wrap(err, "invalid tx hash")
|
||||
}
|
||||
var oldSatPoint, newSatPoint ordinals.SatPoint
|
||||
if src.OldSatpointTxHash.Valid {
|
||||
if !src.OldSatpointOutIdx.Valid || !src.OldSatpointOffset.Valid {
|
||||
@@ -299,12 +303,15 @@ func mapInscriptionTransferModelToType(src gen.GetInscriptionTransfersInOutPoint
|
||||
InscriptionId: inscriptionId,
|
||||
BlockHeight: uint64(src.BlockHeight),
|
||||
TxIndex: uint32(src.TxIndex),
|
||||
TxHash: *txHash,
|
||||
FromInputIndex: uint32(src.FromInputIndex),
|
||||
Content: src.Content,
|
||||
OldSatPoint: oldSatPoint,
|
||||
NewSatPoint: newSatPoint,
|
||||
NewPkScript: newPkScript,
|
||||
NewOutputValue: uint64(src.NewOutputValue),
|
||||
SentAsFee: src.SentAsFee,
|
||||
TransferCount: uint32(src.TransferCount),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -313,6 +320,8 @@ func mapInscriptionTransferTypeToParams(src entity.InscriptionTransfer) gen.Crea
|
||||
InscriptionID: src.InscriptionId.String(),
|
||||
BlockHeight: int32(src.BlockHeight),
|
||||
TxIndex: int32(src.TxIndex),
|
||||
TxHash: src.TxHash.String(),
|
||||
FromInputIndex: int32(src.FromInputIndex),
|
||||
OldSatpointTxHash: lo.Ternary(src.OldSatPoint != ordinals.SatPoint{}, pgtype.Text{String: src.OldSatPoint.OutPoint.Hash.String(), Valid: true}, pgtype.Text{}),
|
||||
OldSatpointOutIdx: lo.Ternary(src.OldSatPoint != ordinals.SatPoint{}, pgtype.Int4{Int32: int32(src.OldSatPoint.OutPoint.Index), Valid: true}, pgtype.Int4{}),
|
||||
OldSatpointOffset: lo.Ternary(src.OldSatPoint != ordinals.SatPoint{}, pgtype.Int8{Int64: int64(src.OldSatPoint.Offset), Valid: true}, pgtype.Int8{}),
|
||||
@@ -322,6 +331,7 @@ func mapInscriptionTransferTypeToParams(src entity.InscriptionTransfer) gen.Crea
|
||||
NewPkscript: hex.EncodeToString(src.NewPkScript),
|
||||
NewOutputValue: int64(src.NewOutputValue),
|
||||
SentAsFee: src.SentAsFee,
|
||||
TransferCount: int32(src.TransferCount),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,7 +355,7 @@ func mapEventDeployModelToType(src gen.Brc20EventDeploy) (entity.EventDeploy, er
|
||||
return entity.EventDeploy{
|
||||
Id: uint64(src.Id),
|
||||
InscriptionId: inscriptionId,
|
||||
InscriptionNumber: uint64(src.InscriptionNumber),
|
||||
InscriptionNumber: src.InscriptionNumber,
|
||||
Tick: src.Tick,
|
||||
OriginalTick: src.OriginalTick,
|
||||
TxHash: *txHash,
|
||||
@@ -368,7 +378,7 @@ func mapEventDeployTypeToParams(src entity.EventDeploy) (gen.CreateEventDeploysP
|
||||
}
|
||||
return gen.CreateEventDeploysParams{
|
||||
InscriptionID: src.InscriptionId.String(),
|
||||
InscriptionNumber: int64(src.InscriptionNumber),
|
||||
InscriptionNumber: src.InscriptionNumber,
|
||||
Tick: src.Tick,
|
||||
OriginalTick: src.OriginalTick,
|
||||
TxHash: src.TxHash.String(),
|
||||
@@ -412,7 +422,7 @@ func mapEventMintModelToType(src gen.Brc20EventMint) (entity.EventMint, error) {
|
||||
return entity.EventMint{
|
||||
Id: uint64(src.Id),
|
||||
InscriptionId: inscriptionId,
|
||||
InscriptionNumber: uint64(src.InscriptionNumber),
|
||||
InscriptionNumber: src.InscriptionNumber,
|
||||
Tick: src.Tick,
|
||||
OriginalTick: src.OriginalTick,
|
||||
TxHash: *txHash,
|
||||
@@ -437,7 +447,7 @@ func mapEventMintTypeToParams(src entity.EventMint) (gen.CreateEventMintsParams,
|
||||
}
|
||||
return gen.CreateEventMintsParams{
|
||||
InscriptionID: src.InscriptionId.String(),
|
||||
InscriptionNumber: int64(src.InscriptionNumber),
|
||||
InscriptionNumber: src.InscriptionNumber,
|
||||
Tick: src.Tick,
|
||||
OriginalTick: src.OriginalTick,
|
||||
TxHash: src.TxHash.String(),
|
||||
@@ -471,7 +481,7 @@ func mapEventInscribeTransferModelToType(src gen.Brc20EventInscribeTransfer) (en
|
||||
return entity.EventInscribeTransfer{
|
||||
Id: uint64(src.Id),
|
||||
InscriptionId: inscriptionId,
|
||||
InscriptionNumber: uint64(src.InscriptionNumber),
|
||||
InscriptionNumber: src.InscriptionNumber,
|
||||
Tick: src.Tick,
|
||||
OriginalTick: src.OriginalTick,
|
||||
TxHash: *txHash,
|
||||
@@ -493,7 +503,7 @@ func mapEventInscribeTransferTypeToParams(src entity.EventInscribeTransfer) (gen
|
||||
}
|
||||
return gen.CreateEventInscribeTransfersParams{
|
||||
InscriptionID: src.InscriptionId.String(),
|
||||
InscriptionNumber: int64(src.InscriptionNumber),
|
||||
InscriptionNumber: src.InscriptionNumber,
|
||||
Tick: src.Tick,
|
||||
OriginalTick: src.OriginalTick,
|
||||
TxHash: src.TxHash.String(),
|
||||
@@ -536,7 +546,7 @@ func mapEventTransferTransferModelToType(src gen.Brc20EventTransferTransfer) (en
|
||||
return entity.EventTransferTransfer{
|
||||
Id: uint64(src.Id),
|
||||
InscriptionId: inscriptionId,
|
||||
InscriptionNumber: uint64(src.InscriptionNumber),
|
||||
InscriptionNumber: src.InscriptionNumber,
|
||||
Tick: src.Tick,
|
||||
OriginalTick: src.OriginalTick,
|
||||
TxHash: *txHash,
|
||||
@@ -549,6 +559,7 @@ func mapEventTransferTransferModelToType(src gen.Brc20EventTransferTransfer) (en
|
||||
ToPkScript: toPkScript,
|
||||
ToSatPoint: toSatPoint,
|
||||
ToOutputIndex: uint32(src.ToOutputIndex),
|
||||
SpentAsFee: src.SpentAsFee,
|
||||
Amount: decimalFromNumeric(src.Amount).Decimal,
|
||||
}, nil
|
||||
}
|
||||
@@ -560,7 +571,7 @@ func mapEventTransferTransferTypeToParams(src entity.EventTransferTransfer) (gen
|
||||
}
|
||||
return gen.CreateEventTransferTransfersParams{
|
||||
InscriptionID: src.InscriptionId.String(),
|
||||
InscriptionNumber: int64(src.InscriptionNumber),
|
||||
InscriptionNumber: src.InscriptionNumber,
|
||||
Tick: src.Tick,
|
||||
OriginalTick: src.OriginalTick,
|
||||
TxHash: src.TxHash.String(),
|
||||
@@ -573,6 +584,21 @@ func mapEventTransferTransferTypeToParams(src entity.EventTransferTransfer) (gen
|
||||
ToPkscript: hex.EncodeToString(src.ToPkScript),
|
||||
ToSatpoint: src.ToSatPoint.String(),
|
||||
ToOutputIndex: int32(src.ToOutputIndex),
|
||||
SpentAsFee: src.SpentAsFee,
|
||||
Amount: numericFromDecimal(src.Amount),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func mapBalanceModelToType(src gen.Brc20Balance) (entity.Balance, error) {
|
||||
pkScript, err := hex.DecodeString(src.Pkscript)
|
||||
if err != nil {
|
||||
return entity.Balance{}, errors.Wrap(err, "failed to parse pkscript")
|
||||
}
|
||||
return entity.Balance{
|
||||
PkScript: pkScript,
|
||||
Tick: src.Tick,
|
||||
BlockHeight: uint64(src.BlockHeight),
|
||||
OverallBalance: decimalFromNumeric(src.OverallBalance).Decimal,
|
||||
AvailableBalance: decimalFromNumeric(src.AvailableBalance).Decimal,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -40,10 +40,18 @@ type Processor struct {
|
||||
// cache
|
||||
outPointValueCache *lru.Cache[wire.OutPoint, uint64]
|
||||
|
||||
// flush buffers
|
||||
// flush buffers - inscription states
|
||||
newInscriptionTransfers []*entity.InscriptionTransfer
|
||||
newInscriptionEntries map[ordinals.InscriptionId]*ordinals.InscriptionEntry
|
||||
newInscriptionEntryStates map[ordinals.InscriptionId]*ordinals.InscriptionEntry
|
||||
// flush buffers - brc20 states
|
||||
newTickEntries map[string]*entity.TickEntry
|
||||
newTickEntryStates map[string]*entity.TickEntry
|
||||
newEventDeploys []*entity.EventDeploy
|
||||
newEventMints []*entity.EventMint
|
||||
newEventInscribeTransfers []*entity.EventInscribeTransfer
|
||||
newEventTransferTransfers []*entity.EventTransferTransfer
|
||||
newBalances map[string]map[string]*entity.Balance
|
||||
}
|
||||
|
||||
// TODO: move this to config
|
||||
@@ -73,6 +81,14 @@ func NewProcessor(brc20Dg datagateway.BRC20DataGateway, indexerInfoDg datagatewa
|
||||
newInscriptionTransfers: make([]*entity.InscriptionTransfer, 0),
|
||||
newInscriptionEntries: make(map[ordinals.InscriptionId]*ordinals.InscriptionEntry),
|
||||
newInscriptionEntryStates: make(map[ordinals.InscriptionId]*ordinals.InscriptionEntry),
|
||||
|
||||
newTickEntries: make(map[string]*entity.TickEntry),
|
||||
newTickEntryStates: make(map[string]*entity.TickEntry),
|
||||
newEventDeploys: make([]*entity.EventDeploy, 0),
|
||||
newEventMints: make([]*entity.EventMint, 0),
|
||||
newEventInscribeTransfers: make([]*entity.EventInscribeTransfer, 0),
|
||||
newEventTransferTransfers: make([]*entity.EventTransferTransfer, 0),
|
||||
newBalances: make(map[string]map[string]*entity.Balance),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
package brc20
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"time"
|
||||
|
||||
"github.com/cockroachdb/errors"
|
||||
"github.com/gaze-network/indexer-network/core/types"
|
||||
"github.com/gaze-network/indexer-network/modules/brc20/internal/brc20"
|
||||
"github.com/gaze-network/indexer-network/modules/brc20/internal/datagateway"
|
||||
"github.com/gaze-network/indexer-network/modules/brc20/internal/entity"
|
||||
"github.com/gaze-network/indexer-network/modules/brc20/internal/ordinals"
|
||||
"github.com/gaze-network/indexer-network/pkg/logger"
|
||||
"github.com/gaze-network/indexer-network/pkg/logger/slogx"
|
||||
"github.com/samber/lo"
|
||||
@@ -25,26 +29,93 @@ func (p *Processor) processBRC20States(ctx context.Context, transfers []*entity.
|
||||
payloads = append(payloads, payload)
|
||||
ticks[payload.Tick] = struct{}{}
|
||||
}
|
||||
entries, err := p.getTickEntriesByTicks(ctx, lo.Keys(ticks))
|
||||
// TODO: concurrently fetch from db to optimize speed
|
||||
tickEntries, err := p.brc20Dg.GetTickEntriesByTicks(ctx, lo.Keys(ticks))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get inscription entries by ids")
|
||||
}
|
||||
|
||||
// preload required data to reduce individual data fetching during process
|
||||
inscriptionIds := make([]ordinals.InscriptionId, 0)
|
||||
inscriptionIdsToFetchParent := make([]ordinals.InscriptionId, 0)
|
||||
inscriptionIdsToFetchEventInscribeTransfer := make([]ordinals.InscriptionId, 0)
|
||||
balancesToFetch := make([]datagateway.GetBalancesBatchAtHeightQuery, 0) // pkscript -> tick -> struct{}
|
||||
for _, payload := range payloads {
|
||||
inscriptionIds = append(inscriptionIds, payload.Transfer.InscriptionId)
|
||||
if payload.Op == brc20.OperationMint {
|
||||
// preload parent id to validate mint events with self mint
|
||||
if entry := tickEntries[payload.Tick]; entry.IsSelfMint {
|
||||
inscriptionIdsToFetchParent = append(inscriptionIdsToFetchParent, payload.Transfer.InscriptionId)
|
||||
}
|
||||
}
|
||||
if payload.Op == brc20.OperationTransfer {
|
||||
if payload.Transfer.OldSatPoint == (ordinals.SatPoint{}) {
|
||||
// preload balance to validate inscribe transfer event
|
||||
balancesToFetch = append(balancesToFetch, datagateway.GetBalancesBatchAtHeightQuery{
|
||||
PkScriptHex: hex.EncodeToString(payload.Transfer.NewPkScript),
|
||||
Tick: payload.Tick,
|
||||
})
|
||||
} else {
|
||||
// preload inscribe-transfer events to validate transfer-transfer event
|
||||
inscriptionIdsToFetchEventInscribeTransfer = append(inscriptionIdsToFetchEventInscribeTransfer, payload.Transfer.InscriptionId)
|
||||
}
|
||||
}
|
||||
}
|
||||
inscriptionIdsToNumber, err := p.getInscriptionNumbersByIds(ctx, lo.Uniq(inscriptionIds))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get inscription numbers by ids")
|
||||
}
|
||||
inscriptionIdsToParent, err := p.getInscriptionParentsByIds(ctx, lo.Uniq(inscriptionIdsToFetchParent))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get inscription parents by ids")
|
||||
}
|
||||
latestEventId, err := p.brc20Dg.GetLatestEventId(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get latest event id")
|
||||
}
|
||||
// pkscript -> tick -> balance
|
||||
balances, err := p.brc20Dg.GetBalancesBatchAtHeight(ctx, uint64(blockHeader.Height-1), balancesToFetch)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get balances batch at height")
|
||||
}
|
||||
eventInscribeTransfers, err := p.brc20Dg.GetEventInscribeTransfersByInscriptionIds(ctx, lo.Uniq(inscriptionIdsToFetchEventInscribeTransfer))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get event inscribe transfers by inscription ids")
|
||||
}
|
||||
|
||||
newTickEntries := make(map[string]*entity.TickEntry)
|
||||
newTickEntryStates := make(map[string]*entity.TickEntry)
|
||||
// newDeployEvents := make([]*entity.EventDeploy, 0)
|
||||
// newMintEvents := make([]*entity.EventMint, 0)
|
||||
// newTransferEvents := make([]*entity.EventTransfer, 0)
|
||||
newEventDeploys := make([]*entity.EventDeploy, 0)
|
||||
newEventMints := make([]*entity.EventMint, 0)
|
||||
newEventInscribeTransfers := make([]*entity.EventInscribeTransfer, 0)
|
||||
newEventTransferTransfers := make([]*entity.EventTransferTransfer, 0)
|
||||
newBalances := make(map[string]map[string]*entity.Balance)
|
||||
|
||||
for _, payload := range payloads {
|
||||
entry := entries[payload.Tick]
|
||||
tickEntry := tickEntries[payload.Tick]
|
||||
|
||||
if payload.Transfer.SentAsFee && payload.Transfer.OldSatPoint == (ordinals.SatPoint{}) {
|
||||
logger.DebugContext(ctx, "found inscription inscribed as fee, skipping...",
|
||||
slogx.String("tick", payload.Tick),
|
||||
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
switch payload.Op {
|
||||
case brc20.OperationDeploy:
|
||||
if entry != nil {
|
||||
if payload.Transfer.TransferCount > 1 {
|
||||
logger.DebugContext(ctx, "found deploy inscription but it is already used, skipping...",
|
||||
slogx.String("tick", payload.Tick),
|
||||
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
||||
slogx.Uint32("transferCount", payload.Transfer.TransferCount),
|
||||
)
|
||||
continue
|
||||
}
|
||||
if tickEntry != nil {
|
||||
logger.DebugContext(ctx, "found deploy inscription but tick already exists, skipping...",
|
||||
slogx.String("tick", payload.Tick),
|
||||
slogx.Stringer("entryInscriptionId", entry.DeployInscriptionId),
|
||||
slogx.Stringer("entryInscriptionId", tickEntry.DeployInscriptionId),
|
||||
slogx.Stringer("currentInscriptionId", payload.Transfer.InscriptionId),
|
||||
)
|
||||
continue
|
||||
@@ -58,7 +129,7 @@ func (p *Processor) processBRC20States(ctx context.Context, transfers []*entity.
|
||||
IsSelfMint: payload.SelfMint,
|
||||
DeployInscriptionId: payload.Transfer.InscriptionId,
|
||||
DeployedAt: blockHeader.Timestamp,
|
||||
DeployedAtHeight: uint64(blockHeader.Height),
|
||||
DeployedAtHeight: payload.Transfer.BlockHeight,
|
||||
MintedAmount: decimal.Zero,
|
||||
BurnedAmount: decimal.Zero,
|
||||
CompletedAt: time.Time{},
|
||||
@@ -67,57 +138,335 @@ func (p *Processor) processBRC20States(ctx context.Context, transfers []*entity.
|
||||
newTickEntries[payload.Tick] = tickEntry
|
||||
newTickEntryStates[payload.Tick] = tickEntry
|
||||
// update entries for other operations in same block
|
||||
entries[payload.Tick] = tickEntry
|
||||
tickEntries[payload.Tick] = tickEntry
|
||||
|
||||
// TODO: handle deploy action
|
||||
newEventDeploys = append(newEventDeploys, &entity.EventDeploy{
|
||||
Id: latestEventId + 1,
|
||||
InscriptionId: payload.Transfer.InscriptionId,
|
||||
InscriptionNumber: inscriptionIdsToNumber[payload.Transfer.InscriptionId],
|
||||
Tick: payload.Tick,
|
||||
OriginalTick: payload.OriginalTick,
|
||||
TxHash: payload.Transfer.TxHash,
|
||||
BlockHeight: payload.Transfer.BlockHeight,
|
||||
TxIndex: payload.Transfer.TxIndex,
|
||||
Timestamp: blockHeader.Timestamp,
|
||||
PkScript: payload.Transfer.NewPkScript,
|
||||
SatPoint: payload.Transfer.NewSatPoint,
|
||||
TotalSupply: payload.Max,
|
||||
Decimals: payload.Dec,
|
||||
LimitPerMint: payload.Lim,
|
||||
IsSelfMint: payload.SelfMint,
|
||||
})
|
||||
latestEventId++
|
||||
case brc20.OperationMint:
|
||||
if entry == nil {
|
||||
if payload.Transfer.TransferCount > 1 {
|
||||
logger.DebugContext(ctx, "found mint inscription but it is already used, skipping...",
|
||||
slogx.String("tick", payload.Tick),
|
||||
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
||||
slogx.Uint32("transferCount", payload.Transfer.TransferCount),
|
||||
)
|
||||
continue
|
||||
}
|
||||
if tickEntry == nil {
|
||||
logger.DebugContext(ctx, "found mint inscription but tick does not exist, skipping...",
|
||||
slogx.String("tick", payload.Tick),
|
||||
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
||||
)
|
||||
continue
|
||||
}
|
||||
if -payload.Amt.Exponent() > int32(entry.Decimals) {
|
||||
if -payload.Amt.Exponent() > int32(tickEntry.Decimals) {
|
||||
logger.DebugContext(ctx, "found mint inscription but amount has invalid decimals, skipping...",
|
||||
slogx.String("tick", payload.Tick),
|
||||
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
||||
slogx.Stringer("amount", payload.Amt),
|
||||
slogx.Uint16("entryDecimals", entry.Decimals),
|
||||
slogx.Uint16("entryDecimals", tickEntry.Decimals),
|
||||
slogx.Int32("payloadDecimals", -payload.Amt.Exponent()),
|
||||
)
|
||||
continue
|
||||
}
|
||||
// TODO: handle mint action
|
||||
if tickEntry.MintedAmount.GreaterThanOrEqual(tickEntry.TotalSupply) {
|
||||
logger.DebugContext(ctx, "found mint inscription but total supply is reached, skipping...",
|
||||
slogx.String("tick", payload.Tick),
|
||||
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
||||
slogx.Stringer("mintedAmount", tickEntry.MintedAmount),
|
||||
slogx.Stringer("totalSupply", tickEntry.TotalSupply),
|
||||
)
|
||||
continue
|
||||
}
|
||||
if payload.Amt.GreaterThan(tickEntry.LimitPerMint) {
|
||||
logger.DebugContext(ctx, "found mint inscription but amount exceeds limit per mint, skipping...",
|
||||
slogx.String("tick", payload.Tick),
|
||||
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
||||
slogx.Stringer("amount", payload.Amt),
|
||||
slogx.Stringer("limitPerMint", tickEntry.LimitPerMint),
|
||||
)
|
||||
continue
|
||||
}
|
||||
mintableAmount := tickEntry.TotalSupply.Sub(tickEntry.MintedAmount)
|
||||
if payload.Amt.GreaterThan(mintableAmount) {
|
||||
payload.Amt = mintableAmount
|
||||
}
|
||||
var parentId *ordinals.InscriptionId
|
||||
if tickEntry.IsSelfMint {
|
||||
parentIdValue, ok := inscriptionIdsToParent[payload.Transfer.InscriptionId]
|
||||
if !ok {
|
||||
logger.DebugContext(ctx, "found mint inscription for self mint tick, but it does not have a parent, skipping...",
|
||||
slogx.String("tick", payload.Tick),
|
||||
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
||||
)
|
||||
continue
|
||||
}
|
||||
if parentIdValue != tickEntry.DeployInscriptionId {
|
||||
logger.DebugContext(ctx, "found mint inscription for self mint tick, but parent id does not match deploy inscription id, skipping...",
|
||||
slogx.String("tick", payload.Tick),
|
||||
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
||||
slogx.Stringer("parentId", parentId),
|
||||
slogx.Stringer("deployInscriptionId", tickEntry.DeployInscriptionId),
|
||||
)
|
||||
}
|
||||
parentId = &parentIdValue
|
||||
}
|
||||
|
||||
tickEntry.MintedAmount = tickEntry.MintedAmount.Add(payload.Amt)
|
||||
if tickEntry.MintedAmount.GreaterThanOrEqual(tickEntry.TotalSupply) {
|
||||
tickEntry.CompletedAt = blockHeader.Timestamp
|
||||
tickEntry.CompletedAtHeight = payload.Transfer.BlockHeight
|
||||
}
|
||||
|
||||
newTickEntryStates[payload.Tick] = tickEntry
|
||||
newEventMints = append(newEventMints, &entity.EventMint{
|
||||
Id: latestEventId + 1,
|
||||
InscriptionId: payload.Transfer.InscriptionId,
|
||||
InscriptionNumber: inscriptionIdsToNumber[payload.Transfer.InscriptionId],
|
||||
Tick: payload.Tick,
|
||||
OriginalTick: payload.OriginalTick,
|
||||
TxHash: payload.Transfer.TxHash,
|
||||
BlockHeight: payload.Transfer.BlockHeight,
|
||||
TxIndex: payload.Transfer.TxIndex,
|
||||
Timestamp: blockHeader.Timestamp,
|
||||
PkScript: payload.Transfer.NewPkScript,
|
||||
SatPoint: payload.Transfer.NewSatPoint,
|
||||
Amount: payload.Amt,
|
||||
ParentId: parentId,
|
||||
})
|
||||
latestEventId++
|
||||
case brc20.OperationTransfer:
|
||||
if entry == nil {
|
||||
if payload.Transfer.TransferCount > 2 {
|
||||
logger.DebugContext(ctx, "found mint inscription but it is already used, skipping...",
|
||||
slogx.String("tick", payload.Tick),
|
||||
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
||||
slogx.Uint32("transferCount", payload.Transfer.TransferCount),
|
||||
)
|
||||
continue
|
||||
}
|
||||
if tickEntry == nil {
|
||||
logger.DebugContext(ctx, "found transfer inscription but tick does not exist, skipping...",
|
||||
slogx.String("tick", payload.Tick),
|
||||
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
||||
)
|
||||
continue
|
||||
}
|
||||
if -payload.Amt.Exponent() > int32(entry.Decimals) {
|
||||
if -payload.Amt.Exponent() > int32(tickEntry.Decimals) {
|
||||
logger.DebugContext(ctx, "found transfer inscription but amount has invalid decimals, skipping...",
|
||||
slogx.String("tick", payload.Tick),
|
||||
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
||||
slogx.Stringer("amount", payload.Amt),
|
||||
slogx.Uint16("entryDecimals", entry.Decimals),
|
||||
slogx.Uint16("entryDecimals", tickEntry.Decimals),
|
||||
slogx.Int32("payloadDecimals", -payload.Amt.Exponent()),
|
||||
)
|
||||
continue
|
||||
}
|
||||
// TODO: handle transfer action
|
||||
|
||||
if payload.Transfer.OldSatPoint == (ordinals.SatPoint{}) {
|
||||
// inscribe transfer event
|
||||
pkScriptHex := hex.EncodeToString(payload.Transfer.NewPkScript)
|
||||
balance, ok := balances[pkScriptHex][payload.Tick]
|
||||
if !ok {
|
||||
balance = &entity.Balance{
|
||||
PkScript: payload.Transfer.NewPkScript,
|
||||
Tick: payload.Tick,
|
||||
BlockHeight: uint64(blockHeader.Height - 1),
|
||||
OverallBalance: decimal.Zero, // defaults balance to zero if not found
|
||||
AvailableBalance: decimal.Zero,
|
||||
}
|
||||
}
|
||||
if payload.Amt.GreaterThan(balance.AvailableBalance) {
|
||||
logger.DebugContext(ctx, "found transfer inscription but amount exceeds available balance, skipping...",
|
||||
slogx.String("tick", payload.Tick),
|
||||
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
||||
slogx.Stringer("amount", payload.Amt),
|
||||
slogx.Stringer("availableBalance", balance.AvailableBalance),
|
||||
)
|
||||
continue
|
||||
}
|
||||
// update balance state
|
||||
balance.BlockHeight = uint64(blockHeader.Height)
|
||||
balance.AvailableBalance = balance.AvailableBalance.Sub(payload.Amt)
|
||||
if _, ok := balances[pkScriptHex]; !ok {
|
||||
balances[pkScriptHex] = make(map[string]*entity.Balance)
|
||||
}
|
||||
balances[pkScriptHex][payload.Tick] = balance
|
||||
if _, ok := newBalances[pkScriptHex]; !ok {
|
||||
newBalances[pkScriptHex] = make(map[string]*entity.Balance)
|
||||
}
|
||||
newBalances[pkScriptHex][payload.Tick] = &entity.Balance{}
|
||||
|
||||
event := &entity.EventInscribeTransfer{
|
||||
Id: latestEventId + 1,
|
||||
InscriptionId: payload.Transfer.InscriptionId,
|
||||
InscriptionNumber: inscriptionIdsToNumber[payload.Transfer.InscriptionId],
|
||||
Tick: payload.Tick,
|
||||
OriginalTick: payload.OriginalTick,
|
||||
TxHash: payload.Transfer.TxHash,
|
||||
BlockHeight: payload.Transfer.BlockHeight,
|
||||
TxIndex: payload.Transfer.TxIndex,
|
||||
Timestamp: blockHeader.Timestamp,
|
||||
PkScript: payload.Transfer.NewPkScript,
|
||||
SatPoint: payload.Transfer.NewSatPoint,
|
||||
OutputIndex: payload.Transfer.NewSatPoint.OutPoint.Index,
|
||||
SatsAmount: payload.Transfer.NewOutputValue,
|
||||
Amount: payload.Amt,
|
||||
}
|
||||
latestEventId++
|
||||
eventInscribeTransfers[payload.Transfer.InscriptionId] = event
|
||||
newEventInscribeTransfers = append(newEventInscribeTransfers, event)
|
||||
} else {
|
||||
// transfer transfer event
|
||||
inscribeTransfer, ok := eventInscribeTransfers[payload.Transfer.InscriptionId]
|
||||
if !ok {
|
||||
logger.DebugContext(ctx, "found transfer transfer event but inscribe transfer does not exist, skipping...",
|
||||
slogx.String("tick", payload.Tick),
|
||||
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
if payload.Transfer.SentAsFee {
|
||||
// return balance to sender
|
||||
fromPkScriptHex := hex.EncodeToString(inscribeTransfer.PkScript)
|
||||
fromBalance, ok := balances[fromPkScriptHex][payload.Tick]
|
||||
if !ok {
|
||||
logger.DebugContext(ctx, "found transfer transfer event but from balance does not exist, skipping...",
|
||||
slogx.String("tick", payload.Tick),
|
||||
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
||||
slogx.String("pkScript", fromPkScriptHex),
|
||||
)
|
||||
continue
|
||||
}
|
||||
fromBalance.BlockHeight = uint64(blockHeader.Height)
|
||||
fromBalance.AvailableBalance = fromBalance.AvailableBalance.Sub(payload.Amt)
|
||||
if _, ok := balances[fromPkScriptHex]; !ok {
|
||||
balances[fromPkScriptHex] = make(map[string]*entity.Balance)
|
||||
}
|
||||
balances[fromPkScriptHex][payload.Tick] = fromBalance
|
||||
if _, ok := newBalances[fromPkScriptHex]; !ok {
|
||||
newBalances[fromPkScriptHex] = make(map[string]*entity.Balance)
|
||||
}
|
||||
newBalances[fromPkScriptHex][payload.Tick] = fromBalance
|
||||
|
||||
newEventTransferTransfers = append(newEventTransferTransfers, &entity.EventTransferTransfer{
|
||||
Id: latestEventId + 1,
|
||||
InscriptionId: payload.Transfer.InscriptionId,
|
||||
InscriptionNumber: inscriptionIdsToNumber[payload.Transfer.InscriptionId],
|
||||
Tick: payload.Tick,
|
||||
OriginalTick: payload.OriginalTick,
|
||||
TxHash: payload.Transfer.TxHash,
|
||||
BlockHeight: payload.Transfer.BlockHeight,
|
||||
TxIndex: payload.Transfer.TxIndex,
|
||||
Timestamp: blockHeader.Timestamp,
|
||||
FromPkScript: inscribeTransfer.PkScript,
|
||||
FromSatPoint: inscribeTransfer.SatPoint,
|
||||
FromInputIndex: payload.Transfer.FromInputIndex,
|
||||
ToPkScript: payload.Transfer.NewPkScript,
|
||||
ToSatPoint: payload.Transfer.NewSatPoint,
|
||||
ToOutputIndex: payload.Transfer.NewSatPoint.OutPoint.Index,
|
||||
SpentAsFee: true,
|
||||
Amount: payload.Amt,
|
||||
})
|
||||
} else {
|
||||
// subtract balance from sender
|
||||
fromPkScriptHex := hex.EncodeToString(inscribeTransfer.PkScript)
|
||||
fromBalance, ok := balances[fromPkScriptHex][payload.Tick]
|
||||
if !ok {
|
||||
logger.DebugContext(ctx, "found transfer transfer event but from balance does not exist, skipping...",
|
||||
slogx.String("tick", payload.Tick),
|
||||
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
||||
slogx.String("pkScript", fromPkScriptHex),
|
||||
)
|
||||
continue
|
||||
}
|
||||
fromBalance.BlockHeight = uint64(blockHeader.Height)
|
||||
fromBalance.OverallBalance = fromBalance.OverallBalance.Sub(payload.Amt)
|
||||
if _, ok := balances[fromPkScriptHex]; !ok {
|
||||
balances[fromPkScriptHex] = make(map[string]*entity.Balance)
|
||||
}
|
||||
balances[fromPkScriptHex][payload.Tick] = fromBalance
|
||||
if _, ok := newBalances[fromPkScriptHex]; !ok {
|
||||
newBalances[fromPkScriptHex] = make(map[string]*entity.Balance)
|
||||
}
|
||||
newBalances[fromPkScriptHex][payload.Tick] = fromBalance
|
||||
|
||||
// add balance to receiver
|
||||
if bytes.Equal(payload.Transfer.NewPkScript, []byte{0x6a}) {
|
||||
// burn if sent to OP_RETURN
|
||||
tickEntry.BurnedAmount = tickEntry.BurnedAmount.Add(payload.Amt)
|
||||
tickEntries[payload.Tick] = tickEntry
|
||||
newTickEntryStates[payload.Tick] = tickEntry
|
||||
} else {
|
||||
toPkScriptHex := hex.EncodeToString(payload.Transfer.NewPkScript)
|
||||
toBalance, ok := balances[toPkScriptHex][payload.Tick]
|
||||
if !ok {
|
||||
toBalance = &entity.Balance{
|
||||
PkScript: payload.Transfer.NewPkScript,
|
||||
Tick: payload.Tick,
|
||||
BlockHeight: uint64(blockHeader.Height),
|
||||
OverallBalance: decimal.Zero, // defaults balance to zero if not found
|
||||
AvailableBalance: decimal.Zero,
|
||||
}
|
||||
}
|
||||
toBalance.BlockHeight = uint64(blockHeader.Height)
|
||||
toBalance.OverallBalance = toBalance.OverallBalance.Add(payload.Amt)
|
||||
toBalance.AvailableBalance = toBalance.AvailableBalance.Add(payload.Amt)
|
||||
if _, ok := balances[toPkScriptHex]; !ok {
|
||||
balances[toPkScriptHex] = make(map[string]*entity.Balance)
|
||||
}
|
||||
balances[toPkScriptHex][payload.Tick] = toBalance
|
||||
if _, ok := newBalances[toPkScriptHex]; !ok {
|
||||
newBalances[toPkScriptHex] = make(map[string]*entity.Balance)
|
||||
}
|
||||
newBalances[toPkScriptHex][payload.Tick] = toBalance
|
||||
}
|
||||
|
||||
newEventTransferTransfers = append(newEventTransferTransfers, &entity.EventTransferTransfer{
|
||||
Id: latestEventId + 1,
|
||||
InscriptionId: payload.Transfer.InscriptionId,
|
||||
InscriptionNumber: inscriptionIdsToNumber[payload.Transfer.InscriptionId],
|
||||
Tick: payload.Tick,
|
||||
OriginalTick: payload.OriginalTick,
|
||||
TxHash: payload.Transfer.TxHash,
|
||||
BlockHeight: payload.Transfer.BlockHeight,
|
||||
TxIndex: payload.Transfer.TxIndex,
|
||||
Timestamp: blockHeader.Timestamp,
|
||||
FromPkScript: inscribeTransfer.PkScript,
|
||||
FromSatPoint: inscribeTransfer.SatPoint,
|
||||
FromInputIndex: payload.Transfer.FromInputIndex,
|
||||
ToPkScript: payload.Transfer.NewPkScript,
|
||||
ToSatPoint: payload.Transfer.NewSatPoint,
|
||||
ToOutputIndex: payload.Transfer.NewSatPoint.OutPoint.Index,
|
||||
SpentAsFee: false,
|
||||
Amount: payload.Amt,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p.newTickEntries = newTickEntries
|
||||
p.newTickEntryStates = newTickEntryStates
|
||||
p.newEventDeploys = newEventDeploys
|
||||
p.newEventMints = newEventMints
|
||||
p.newEventInscribeTransfers = newEventInscribeTransfers
|
||||
p.newEventTransferTransfers = newEventTransferTransfers
|
||||
p.newBalances = newBalances
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Processor) getTickEntriesByTicks(ctx context.Context, ticks []string) (map[string]*entity.TickEntry, error) {
|
||||
// TODO: get from buffer if exists
|
||||
result, err := p.brc20Dg.GetTickEntriesByTicks(ctx, ticks)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get tick entries by ticks")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -80,6 +80,7 @@ func (p *Processor) processInscriptionTx(ctx context.Context, tx *types.Transact
|
||||
OriginOld: &entity.OriginOld{
|
||||
OldSatPoint: satPoint,
|
||||
Content: transfer.Content,
|
||||
InputIndex: uint32(i),
|
||||
},
|
||||
})
|
||||
if _, ok := inscribeOffsets[offset]; !ok {
|
||||
@@ -289,17 +290,6 @@ func (p *Processor) processInscriptionTx(ctx context.Context, tx *types.Transact
|
||||
func (p *Processor) updateInscriptionLocation(ctx context.Context, newSatPoint ordinals.SatPoint, flotsam *entity.Flotsam, sentAsFee bool, tx *types.Transaction, blockHeader types.BlockHeader) error {
|
||||
txOut := tx.TxOut[newSatPoint.OutPoint.Index]
|
||||
if flotsam.OriginOld != nil {
|
||||
transfer := &entity.InscriptionTransfer{
|
||||
InscriptionId: flotsam.InscriptionId,
|
||||
BlockHeight: uint64(flotsam.Tx.BlockHeight), // use flotsam's tx to track tx that initiated the transfer
|
||||
TxIndex: flotsam.Tx.Index, // use flotsam's tx to track tx that initiated the transfer
|
||||
Content: flotsam.OriginOld.Content,
|
||||
OldSatPoint: flotsam.OriginOld.OldSatPoint,
|
||||
NewSatPoint: newSatPoint,
|
||||
NewPkScript: txOut.PkScript,
|
||||
NewOutputValue: uint64(txOut.Value),
|
||||
SentAsFee: sentAsFee,
|
||||
}
|
||||
entry, err := p.getInscriptionEntryById(ctx, flotsam.InscriptionId)
|
||||
if err != nil {
|
||||
// skip inscriptions without entry (likely non-brc20 inscriptions)
|
||||
@@ -309,6 +299,20 @@ func (p *Processor) updateInscriptionLocation(ctx context.Context, newSatPoint o
|
||||
return errors.Wrap(err, "failed to get inscription entry")
|
||||
}
|
||||
entry.TransferCount++
|
||||
transfer := &entity.InscriptionTransfer{
|
||||
InscriptionId: flotsam.InscriptionId,
|
||||
BlockHeight: uint64(flotsam.Tx.BlockHeight), // use flotsam's tx to track tx that initiated the transfer
|
||||
TxIndex: flotsam.Tx.Index, // use flotsam's tx to track tx that initiated the transfer
|
||||
TxHash: flotsam.Tx.TxHash,
|
||||
Content: flotsam.OriginOld.Content,
|
||||
FromInputIndex: flotsam.OriginOld.InputIndex,
|
||||
OldSatPoint: flotsam.OriginOld.OldSatPoint,
|
||||
NewSatPoint: newSatPoint,
|
||||
NewPkScript: txOut.PkScript,
|
||||
NewOutputValue: uint64(txOut.Value),
|
||||
SentAsFee: sentAsFee,
|
||||
TransferCount: entry.TransferCount,
|
||||
}
|
||||
|
||||
// track transfers even if transfer count exceeds 2 (because we need to check for reinscriptions)
|
||||
p.newInscriptionTransfers = append(p.newInscriptionTransfers, transfer)
|
||||
@@ -337,12 +341,15 @@ func (p *Processor) updateInscriptionLocation(ctx context.Context, newSatPoint o
|
||||
InscriptionId: flotsam.InscriptionId,
|
||||
BlockHeight: uint64(flotsam.Tx.BlockHeight), // use flotsam's tx to track tx that initiated the transfer
|
||||
TxIndex: flotsam.Tx.Index, // use flotsam's tx to track tx that initiated the transfer
|
||||
TxHash: flotsam.Tx.TxHash,
|
||||
Content: origin.Inscription.Content,
|
||||
FromInputIndex: 0, // unused
|
||||
OldSatPoint: ordinals.SatPoint{},
|
||||
NewSatPoint: newSatPoint,
|
||||
NewPkScript: txOut.PkScript,
|
||||
NewOutputValue: uint64(txOut.Value),
|
||||
SentAsFee: sentAsFee,
|
||||
TransferCount: 1, // count inscription as first transfer
|
||||
}
|
||||
entry := &ordinals.InscriptionEntry{
|
||||
Id: flotsam.InscriptionId,
|
||||
@@ -510,6 +517,58 @@ func (p *Processor) getInscriptionEntriesByIds(ctx context.Context, ids []ordina
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *Processor) getInscriptionNumbersByIds(ctx context.Context, ids []ordinals.InscriptionId) (map[ordinals.InscriptionId]int64, error) {
|
||||
// try to get from cache if exists
|
||||
result := make(map[ordinals.InscriptionId]int64)
|
||||
|
||||
idsToFetch := make([]ordinals.InscriptionId, 0)
|
||||
for _, id := range ids {
|
||||
if entry, ok := p.newInscriptionEntryStates[id]; ok {
|
||||
result[id] = int64(entry.Number)
|
||||
} else {
|
||||
idsToFetch = append(idsToFetch, id)
|
||||
}
|
||||
}
|
||||
|
||||
if len(idsToFetch) == 0 {
|
||||
inscriptions, err := p.brc20Dg.GetInscriptionNumbersByIds(ctx, idsToFetch)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get inscriptions by outpoint")
|
||||
}
|
||||
for id, number := range inscriptions {
|
||||
result[id] = number
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *Processor) getInscriptionParentsByIds(ctx context.Context, ids []ordinals.InscriptionId) (map[ordinals.InscriptionId]ordinals.InscriptionId, error) {
|
||||
// try to get from cache if exists
|
||||
result := make(map[ordinals.InscriptionId]ordinals.InscriptionId)
|
||||
|
||||
idsToFetch := make([]ordinals.InscriptionId, 0)
|
||||
for _, id := range ids {
|
||||
if entry, ok := p.newInscriptionEntryStates[id]; ok {
|
||||
if entry.Inscription.Parent != nil {
|
||||
result[id] = *entry.Inscription.Parent
|
||||
}
|
||||
} else {
|
||||
idsToFetch = append(idsToFetch, id)
|
||||
}
|
||||
}
|
||||
|
||||
if len(idsToFetch) == 0 {
|
||||
inscriptions, err := p.brc20Dg.GetInscriptionParentsByIds(ctx, idsToFetch)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get inscriptions by outpoint")
|
||||
}
|
||||
for id, parent := range inscriptions {
|
||||
result[id] = parent
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *Processor) getBlockSubsidy(blockHeight uint64) uint64 {
|
||||
return uint64(blockchain.CalcBlockSubsidy(int32(blockHeight), p.network.ChainParams()))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user