mirror of
https://github.com/alexgo-io/gaze-brc20-indexer.git
synced 2026-01-12 22:22:19 +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")
|
PRIMARY KEY ("tick", "block_height")
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE SEQUENCE IF NOT EXISTS brc20_event_id_seq;
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS "brc20_event_deploys" (
|
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_id" TEXT NOT NULL,
|
||||||
"inscription_number" BIGINT NOT NULL,
|
"inscription_number" BIGINT NOT NULL,
|
||||||
"tick" TEXT NOT NULL, -- lowercase of original_tick
|
"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 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" (
|
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_id" TEXT NOT NULL,
|
||||||
"inscription_number" BIGINT NOT NULL,
|
"inscription_number" BIGINT NOT NULL,
|
||||||
"tick" TEXT NOT NULL, -- lowercase of original_tick
|
"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 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" (
|
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_id" TEXT NOT NULL,
|
||||||
"inscription_number" BIGINT NOT NULL,
|
"inscription_number" BIGINT NOT NULL,
|
||||||
"tick" TEXT NOT NULL, -- lowercase of original_tick
|
"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
|
"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_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" (
|
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_id" TEXT NOT NULL,
|
||||||
"inscription_number" BIGINT NOT NULL,
|
"inscription_number" BIGINT NOT NULL,
|
||||||
"tick" TEXT NOT NULL, -- lowercase of original_tick
|
"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_pkscript" TEXT NOT NULL,
|
||||||
"to_satpoint" TEXT NOT NULL,
|
"to_satpoint" TEXT NOT NULL,
|
||||||
"to_output_index" INT NOT NULL,
|
"to_output_index" INT NOT NULL,
|
||||||
|
"spent_as_fee" BOOLEAN NOT NULL,
|
||||||
"amount" DECIMAL 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");
|
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" TIMESTAMP NOT NULL,
|
||||||
"created_at_height" INT 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" (
|
CREATE TABLE IF NOT EXISTS "brc20_inscription_entry_states" (
|
||||||
"id" TEXT NOT NULL,
|
"id" TEXT NOT NULL,
|
||||||
@@ -168,6 +169,8 @@ CREATE TABLE IF NOT EXISTS "brc20_inscription_transfers" (
|
|||||||
"inscription_id" TEXT NOT NULL,
|
"inscription_id" TEXT NOT NULL,
|
||||||
"block_height" INT NOT NULL,
|
"block_height" INT NOT NULL,
|
||||||
"tx_index" 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_tx_hash" TEXT,
|
||||||
"old_satpoint_out_idx" INT,
|
"old_satpoint_out_idx" INT,
|
||||||
"old_satpoint_offset" BIGINT,
|
"old_satpoint_offset" BIGINT,
|
||||||
@@ -177,6 +180,7 @@ CREATE TABLE IF NOT EXISTS "brc20_inscription_transfers" (
|
|||||||
"new_pkscript" TEXT NOT NULL,
|
"new_pkscript" TEXT NOT NULL,
|
||||||
"new_output_value" BIGINT NOT NULL,
|
"new_output_value" BIGINT NOT NULL,
|
||||||
"sent_as_fee" BOOLEAN NOT NULL,
|
"sent_as_fee" BOOLEAN NOT NULL,
|
||||||
|
"transfer_count" INT NOT NULL,
|
||||||
PRIMARY KEY ("inscription_id", "block_height", "tx_index")
|
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");
|
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"
|
LEFT JOIN "states" ON "brc20_tick_entries"."tick" = "states"."tick"
|
||||||
WHERE "brc20_tick_entries"."tick" = ANY(@ticks::text[]);
|
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
|
-- name: CreateIndexedBlock :exec
|
||||||
INSERT INTO "brc20_indexed_blocks" ("height", "hash", "event_hash", "cumulative_event_hash") VALUES ($1, $2, $3, $4);
|
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);
|
INSERT INTO "brc20_inscription_entry_states" ("id", "block_height", "transfer_count") VALUES ($1, $2, $3);
|
||||||
|
|
||||||
-- name: CreateInscriptionTransfers :batchexec
|
-- 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
|
-- 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);
|
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);
|
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
|
-- 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
|
-- name: DeleteIndexedBlocksSinceHeight :exec
|
||||||
DELETE FROM "brc20_indexed_blocks" WHERE "height" >= $1;
|
DELETE FROM "brc20_indexed_blocks" WHERE "height" >= $1;
|
||||||
|
|||||||
@@ -28,7 +28,12 @@ type BRC20ReaderDataGateway interface {
|
|||||||
GetProcessorStats(ctx context.Context) (*entity.ProcessorStats, error)
|
GetProcessorStats(ctx context.Context) (*entity.ProcessorStats, error)
|
||||||
GetInscriptionTransfersInOutPoints(ctx context.Context, outPoints []wire.OutPoint) (map[ordinals.SatPoint][]*entity.InscriptionTransfer, 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)
|
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)
|
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 {
|
type BRC20WriterDataGateway interface {
|
||||||
@@ -58,3 +63,9 @@ type BRC20WriterDataGateway interface {
|
|||||||
DeleteInscriptionEntryStatesSinceHeight(ctx context.Context, height uint64) error
|
DeleteInscriptionEntryStatesSinceHeight(ctx context.Context, height uint64) error
|
||||||
DeleteInscriptionTransfersSinceHeight(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 {
|
type EventDeploy struct {
|
||||||
Id uint64
|
Id uint64
|
||||||
InscriptionId ordinals.InscriptionId
|
InscriptionId ordinals.InscriptionId
|
||||||
InscriptionNumber uint64
|
InscriptionNumber int64
|
||||||
Tick string
|
Tick string
|
||||||
OriginalTick string
|
OriginalTick string
|
||||||
TxHash chainhash.Hash
|
TxHash chainhash.Hash
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
type EventInscribeTransfer struct {
|
type EventInscribeTransfer struct {
|
||||||
Id uint64
|
Id uint64
|
||||||
InscriptionId ordinals.InscriptionId
|
InscriptionId ordinals.InscriptionId
|
||||||
InscriptionNumber uint64
|
InscriptionNumber int64
|
||||||
Tick string
|
Tick string
|
||||||
OriginalTick string
|
OriginalTick string
|
||||||
TxHash chainhash.Hash
|
TxHash chainhash.Hash
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
type EventMint struct {
|
type EventMint struct {
|
||||||
Id uint64
|
Id uint64
|
||||||
InscriptionId ordinals.InscriptionId
|
InscriptionId ordinals.InscriptionId
|
||||||
InscriptionNumber uint64
|
InscriptionNumber int64
|
||||||
Tick string
|
Tick string
|
||||||
OriginalTick string
|
OriginalTick string
|
||||||
TxHash chainhash.Hash
|
TxHash chainhash.Hash
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
type EventTransferTransfer struct {
|
type EventTransferTransfer struct {
|
||||||
Id uint64
|
Id uint64
|
||||||
InscriptionId ordinals.InscriptionId
|
InscriptionId ordinals.InscriptionId
|
||||||
InscriptionNumber uint64
|
InscriptionNumber int64
|
||||||
Tick string
|
Tick string
|
||||||
OriginalTick string
|
OriginalTick string
|
||||||
TxHash chainhash.Hash
|
TxHash chainhash.Hash
|
||||||
@@ -25,5 +25,6 @@ type EventTransferTransfer struct {
|
|||||||
ToPkScript []byte
|
ToPkScript []byte
|
||||||
ToSatPoint ordinals.SatPoint
|
ToSatPoint ordinals.SatPoint
|
||||||
ToOutputIndex uint32
|
ToOutputIndex uint32
|
||||||
|
SpentAsFee bool
|
||||||
Amount decimal.Decimal
|
Amount decimal.Decimal
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
type OriginOld struct {
|
type OriginOld struct {
|
||||||
Content []byte
|
Content []byte
|
||||||
OldSatPoint ordinals.SatPoint
|
OldSatPoint ordinals.SatPoint
|
||||||
|
InputIndex uint32
|
||||||
}
|
}
|
||||||
type OriginNew struct {
|
type OriginNew struct {
|
||||||
Inscription ordinals.Inscription
|
Inscription ordinals.Inscription
|
||||||
|
|||||||
@@ -1,15 +1,21 @@
|
|||||||
package entity
|
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 {
|
type InscriptionTransfer struct {
|
||||||
InscriptionId ordinals.InscriptionId
|
InscriptionId ordinals.InscriptionId
|
||||||
BlockHeight uint64
|
BlockHeight uint64
|
||||||
TxIndex uint32
|
TxIndex uint32
|
||||||
|
TxHash chainhash.Hash
|
||||||
Content []byte
|
Content []byte
|
||||||
|
FromInputIndex uint32
|
||||||
OldSatPoint ordinals.SatPoint
|
OldSatPoint ordinals.SatPoint
|
||||||
NewSatPoint ordinals.SatPoint
|
NewSatPoint ordinals.SatPoint
|
||||||
NewPkScript []byte
|
NewPkScript []byte
|
||||||
NewOutputValue uint64
|
NewOutputValue uint64
|
||||||
SentAsFee bool
|
SentAsFee bool
|
||||||
|
TransferCount uint32
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,6 +110,110 @@ func (r *Repository) GetInscriptionEntriesByIds(ctx context.Context, ids []ordin
|
|||||||
return result, nil
|
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) {
|
func (r *Repository) GetTickEntriesByTicks(ctx context.Context, ticks []string) (map[string]*entity.TickEntry, error) {
|
||||||
models, err := r.queries.GetTickEntriesByTicks(ctx, ticks)
|
models, err := r.queries.GetTickEntriesByTicks(ctx, ticks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ func (b *CreateEventMintsBatchResults) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const createEventTransferTransfers = `-- name: CreateEventTransferTransfers :batchexec
|
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 {
|
type CreateEventTransferTransfersBatchResults struct {
|
||||||
@@ -255,6 +255,7 @@ type CreateEventTransferTransfersParams struct {
|
|||||||
ToPkscript string
|
ToPkscript string
|
||||||
ToSatpoint string
|
ToSatpoint string
|
||||||
ToOutputIndex int32
|
ToOutputIndex int32
|
||||||
|
SpentAsFee bool
|
||||||
Amount pgtype.Numeric
|
Amount pgtype.Numeric
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,6 +277,7 @@ func (q *Queries) CreateEventTransferTransfers(ctx context.Context, arg []Create
|
|||||||
a.ToPkscript,
|
a.ToPkscript,
|
||||||
a.ToSatpoint,
|
a.ToSatpoint,
|
||||||
a.ToOutputIndex,
|
a.ToOutputIndex,
|
||||||
|
a.SpentAsFee,
|
||||||
a.Amount,
|
a.Amount,
|
||||||
}
|
}
|
||||||
batch.Queue(createEventTransferTransfers, vals...)
|
batch.Queue(createEventTransferTransfers, vals...)
|
||||||
@@ -432,7 +434,7 @@ func (b *CreateInscriptionEntryStatesBatchResults) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const createInscriptionTransfers = `-- name: CreateInscriptionTransfers :batchexec
|
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 {
|
type CreateInscriptionTransfersBatchResults struct {
|
||||||
@@ -445,6 +447,8 @@ type CreateInscriptionTransfersParams struct {
|
|||||||
InscriptionID string
|
InscriptionID string
|
||||||
BlockHeight int32
|
BlockHeight int32
|
||||||
TxIndex int32
|
TxIndex int32
|
||||||
|
TxHash string
|
||||||
|
FromInputIndex int32
|
||||||
OldSatpointTxHash pgtype.Text
|
OldSatpointTxHash pgtype.Text
|
||||||
OldSatpointOutIdx pgtype.Int4
|
OldSatpointOutIdx pgtype.Int4
|
||||||
OldSatpointOffset pgtype.Int8
|
OldSatpointOffset pgtype.Int8
|
||||||
@@ -454,6 +458,7 @@ type CreateInscriptionTransfersParams struct {
|
|||||||
NewPkscript string
|
NewPkscript string
|
||||||
NewOutputValue int64
|
NewOutputValue int64
|
||||||
SentAsFee bool
|
SentAsFee bool
|
||||||
|
TransferCount int32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateInscriptionTransfers(ctx context.Context, arg []CreateInscriptionTransfersParams) *CreateInscriptionTransfersBatchResults {
|
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.InscriptionID,
|
||||||
a.BlockHeight,
|
a.BlockHeight,
|
||||||
a.TxIndex,
|
a.TxIndex,
|
||||||
|
a.TxHash,
|
||||||
|
a.FromInputIndex,
|
||||||
a.OldSatpointTxHash,
|
a.OldSatpointTxHash,
|
||||||
a.OldSatpointOutIdx,
|
a.OldSatpointOutIdx,
|
||||||
a.OldSatpointOffset,
|
a.OldSatpointOffset,
|
||||||
@@ -472,6 +479,7 @@ func (q *Queries) CreateInscriptionTransfers(ctx context.Context, arg []CreateIn
|
|||||||
a.NewPkscript,
|
a.NewPkscript,
|
||||||
a.NewOutputValue,
|
a.NewOutputValue,
|
||||||
a.SentAsFee,
|
a.SentAsFee,
|
||||||
|
a.TransferCount,
|
||||||
}
|
}
|
||||||
batch.Queue(createInscriptionTransfers, vals...)
|
batch.Queue(createInscriptionTransfers, vals...)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,6 +161,87 @@ func (q *Queries) DeleteTickEntryStatesSinceHeight(ctx context.Context, blockHei
|
|||||||
return err
|
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
|
const getIndexedBlockByHeight = `-- name: GetIndexedBlockByHeight :one
|
||||||
SELECT height, hash, event_hash, cumulative_event_hash FROM "brc20_indexed_blocks" WHERE "height" = $1
|
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
|
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
|
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
|
SELECT
|
||||||
unnest($1::text[]) AS "tx_hash",
|
unnest($1::text[]) AS "tx_hash",
|
||||||
unnest($2::int[]) AS "tx_out_idx"
|
unnest($2::int[]) AS "tx_out_idx"
|
||||||
@@ -266,6 +405,8 @@ type GetInscriptionTransfersInOutPointsRow struct {
|
|||||||
InscriptionID string
|
InscriptionID string
|
||||||
BlockHeight int32
|
BlockHeight int32
|
||||||
TxIndex int32
|
TxIndex int32
|
||||||
|
TxHash string
|
||||||
|
FromInputIndex int32
|
||||||
OldSatpointTxHash pgtype.Text
|
OldSatpointTxHash pgtype.Text
|
||||||
OldSatpointOutIdx pgtype.Int4
|
OldSatpointOutIdx pgtype.Int4
|
||||||
OldSatpointOffset pgtype.Int8
|
OldSatpointOffset pgtype.Int8
|
||||||
@@ -275,6 +416,7 @@ type GetInscriptionTransfersInOutPointsRow struct {
|
|||||||
NewPkscript string
|
NewPkscript string
|
||||||
NewOutputValue int64
|
NewOutputValue int64
|
||||||
SentAsFee bool
|
SentAsFee bool
|
||||||
|
TransferCount int32
|
||||||
Content []byte
|
Content []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,6 +433,8 @@ func (q *Queries) GetInscriptionTransfersInOutPoints(ctx context.Context, arg Ge
|
|||||||
&i.InscriptionID,
|
&i.InscriptionID,
|
||||||
&i.BlockHeight,
|
&i.BlockHeight,
|
||||||
&i.TxIndex,
|
&i.TxIndex,
|
||||||
|
&i.TxHash,
|
||||||
|
&i.FromInputIndex,
|
||||||
&i.OldSatpointTxHash,
|
&i.OldSatpointTxHash,
|
||||||
&i.OldSatpointOutIdx,
|
&i.OldSatpointOutIdx,
|
||||||
&i.OldSatpointOffset,
|
&i.OldSatpointOffset,
|
||||||
@@ -300,6 +444,7 @@ func (q *Queries) GetInscriptionTransfersInOutPoints(ctx context.Context, arg Ge
|
|||||||
&i.NewPkscript,
|
&i.NewPkscript,
|
||||||
&i.NewOutputValue,
|
&i.NewOutputValue,
|
||||||
&i.SentAsFee,
|
&i.SentAsFee,
|
||||||
|
&i.TransferCount,
|
||||||
&i.Content,
|
&i.Content,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -312,6 +457,45 @@ func (q *Queries) GetInscriptionTransfersInOutPoints(ctx context.Context, arg Ge
|
|||||||
return items, nil
|
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
|
const getLatestIndexedBlock = `-- name: GetLatestIndexedBlock :one
|
||||||
SELECT height, hash, event_hash, cumulative_event_hash FROM "brc20_indexed_blocks" ORDER BY "height" DESC LIMIT 1
|
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
|
ToPkscript string
|
||||||
ToSatpoint string
|
ToSatpoint string
|
||||||
ToOutputIndex int32
|
ToOutputIndex int32
|
||||||
|
SpentAsFee bool
|
||||||
Amount pgtype.Numeric
|
Amount pgtype.Numeric
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,6 +131,8 @@ type Brc20InscriptionTransfer struct {
|
|||||||
InscriptionID string
|
InscriptionID string
|
||||||
BlockHeight int32
|
BlockHeight int32
|
||||||
TxIndex int32
|
TxIndex int32
|
||||||
|
TxHash string
|
||||||
|
FromInputIndex int32
|
||||||
OldSatpointTxHash pgtype.Text
|
OldSatpointTxHash pgtype.Text
|
||||||
OldSatpointOutIdx pgtype.Int4
|
OldSatpointOutIdx pgtype.Int4
|
||||||
OldSatpointOffset pgtype.Int8
|
OldSatpointOffset pgtype.Int8
|
||||||
@@ -139,6 +142,7 @@ type Brc20InscriptionTransfer struct {
|
|||||||
NewPkscript string
|
NewPkscript string
|
||||||
NewOutputValue int64
|
NewOutputValue int64
|
||||||
SentAsFee bool
|
SentAsFee bool
|
||||||
|
TransferCount int32
|
||||||
}
|
}
|
||||||
|
|
||||||
type Brc20ProcessorStat struct {
|
type Brc20ProcessorStat struct {
|
||||||
|
|||||||
@@ -257,6 +257,10 @@ func mapInscriptionTransferModelToType(src gen.GetInscriptionTransfersInOutPoint
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return entity.InscriptionTransfer{}, errors.Wrap(err, "invalid inscription id")
|
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
|
var oldSatPoint, newSatPoint ordinals.SatPoint
|
||||||
if src.OldSatpointTxHash.Valid {
|
if src.OldSatpointTxHash.Valid {
|
||||||
if !src.OldSatpointOutIdx.Valid || !src.OldSatpointOffset.Valid {
|
if !src.OldSatpointOutIdx.Valid || !src.OldSatpointOffset.Valid {
|
||||||
@@ -299,12 +303,15 @@ func mapInscriptionTransferModelToType(src gen.GetInscriptionTransfersInOutPoint
|
|||||||
InscriptionId: inscriptionId,
|
InscriptionId: inscriptionId,
|
||||||
BlockHeight: uint64(src.BlockHeight),
|
BlockHeight: uint64(src.BlockHeight),
|
||||||
TxIndex: uint32(src.TxIndex),
|
TxIndex: uint32(src.TxIndex),
|
||||||
|
TxHash: *txHash,
|
||||||
|
FromInputIndex: uint32(src.FromInputIndex),
|
||||||
Content: src.Content,
|
Content: src.Content,
|
||||||
OldSatPoint: oldSatPoint,
|
OldSatPoint: oldSatPoint,
|
||||||
NewSatPoint: newSatPoint,
|
NewSatPoint: newSatPoint,
|
||||||
NewPkScript: newPkScript,
|
NewPkScript: newPkScript,
|
||||||
NewOutputValue: uint64(src.NewOutputValue),
|
NewOutputValue: uint64(src.NewOutputValue),
|
||||||
SentAsFee: src.SentAsFee,
|
SentAsFee: src.SentAsFee,
|
||||||
|
TransferCount: uint32(src.TransferCount),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,6 +320,8 @@ func mapInscriptionTransferTypeToParams(src entity.InscriptionTransfer) gen.Crea
|
|||||||
InscriptionID: src.InscriptionId.String(),
|
InscriptionID: src.InscriptionId.String(),
|
||||||
BlockHeight: int32(src.BlockHeight),
|
BlockHeight: int32(src.BlockHeight),
|
||||||
TxIndex: int32(src.TxIndex),
|
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{}),
|
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{}),
|
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{}),
|
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),
|
NewPkscript: hex.EncodeToString(src.NewPkScript),
|
||||||
NewOutputValue: int64(src.NewOutputValue),
|
NewOutputValue: int64(src.NewOutputValue),
|
||||||
SentAsFee: src.SentAsFee,
|
SentAsFee: src.SentAsFee,
|
||||||
|
TransferCount: int32(src.TransferCount),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,7 +355,7 @@ func mapEventDeployModelToType(src gen.Brc20EventDeploy) (entity.EventDeploy, er
|
|||||||
return entity.EventDeploy{
|
return entity.EventDeploy{
|
||||||
Id: uint64(src.Id),
|
Id: uint64(src.Id),
|
||||||
InscriptionId: inscriptionId,
|
InscriptionId: inscriptionId,
|
||||||
InscriptionNumber: uint64(src.InscriptionNumber),
|
InscriptionNumber: src.InscriptionNumber,
|
||||||
Tick: src.Tick,
|
Tick: src.Tick,
|
||||||
OriginalTick: src.OriginalTick,
|
OriginalTick: src.OriginalTick,
|
||||||
TxHash: *txHash,
|
TxHash: *txHash,
|
||||||
@@ -368,7 +378,7 @@ func mapEventDeployTypeToParams(src entity.EventDeploy) (gen.CreateEventDeploysP
|
|||||||
}
|
}
|
||||||
return gen.CreateEventDeploysParams{
|
return gen.CreateEventDeploysParams{
|
||||||
InscriptionID: src.InscriptionId.String(),
|
InscriptionID: src.InscriptionId.String(),
|
||||||
InscriptionNumber: int64(src.InscriptionNumber),
|
InscriptionNumber: src.InscriptionNumber,
|
||||||
Tick: src.Tick,
|
Tick: src.Tick,
|
||||||
OriginalTick: src.OriginalTick,
|
OriginalTick: src.OriginalTick,
|
||||||
TxHash: src.TxHash.String(),
|
TxHash: src.TxHash.String(),
|
||||||
@@ -412,7 +422,7 @@ func mapEventMintModelToType(src gen.Brc20EventMint) (entity.EventMint, error) {
|
|||||||
return entity.EventMint{
|
return entity.EventMint{
|
||||||
Id: uint64(src.Id),
|
Id: uint64(src.Id),
|
||||||
InscriptionId: inscriptionId,
|
InscriptionId: inscriptionId,
|
||||||
InscriptionNumber: uint64(src.InscriptionNumber),
|
InscriptionNumber: src.InscriptionNumber,
|
||||||
Tick: src.Tick,
|
Tick: src.Tick,
|
||||||
OriginalTick: src.OriginalTick,
|
OriginalTick: src.OriginalTick,
|
||||||
TxHash: *txHash,
|
TxHash: *txHash,
|
||||||
@@ -437,7 +447,7 @@ func mapEventMintTypeToParams(src entity.EventMint) (gen.CreateEventMintsParams,
|
|||||||
}
|
}
|
||||||
return gen.CreateEventMintsParams{
|
return gen.CreateEventMintsParams{
|
||||||
InscriptionID: src.InscriptionId.String(),
|
InscriptionID: src.InscriptionId.String(),
|
||||||
InscriptionNumber: int64(src.InscriptionNumber),
|
InscriptionNumber: src.InscriptionNumber,
|
||||||
Tick: src.Tick,
|
Tick: src.Tick,
|
||||||
OriginalTick: src.OriginalTick,
|
OriginalTick: src.OriginalTick,
|
||||||
TxHash: src.TxHash.String(),
|
TxHash: src.TxHash.String(),
|
||||||
@@ -471,7 +481,7 @@ func mapEventInscribeTransferModelToType(src gen.Brc20EventInscribeTransfer) (en
|
|||||||
return entity.EventInscribeTransfer{
|
return entity.EventInscribeTransfer{
|
||||||
Id: uint64(src.Id),
|
Id: uint64(src.Id),
|
||||||
InscriptionId: inscriptionId,
|
InscriptionId: inscriptionId,
|
||||||
InscriptionNumber: uint64(src.InscriptionNumber),
|
InscriptionNumber: src.InscriptionNumber,
|
||||||
Tick: src.Tick,
|
Tick: src.Tick,
|
||||||
OriginalTick: src.OriginalTick,
|
OriginalTick: src.OriginalTick,
|
||||||
TxHash: *txHash,
|
TxHash: *txHash,
|
||||||
@@ -493,7 +503,7 @@ func mapEventInscribeTransferTypeToParams(src entity.EventInscribeTransfer) (gen
|
|||||||
}
|
}
|
||||||
return gen.CreateEventInscribeTransfersParams{
|
return gen.CreateEventInscribeTransfersParams{
|
||||||
InscriptionID: src.InscriptionId.String(),
|
InscriptionID: src.InscriptionId.String(),
|
||||||
InscriptionNumber: int64(src.InscriptionNumber),
|
InscriptionNumber: src.InscriptionNumber,
|
||||||
Tick: src.Tick,
|
Tick: src.Tick,
|
||||||
OriginalTick: src.OriginalTick,
|
OriginalTick: src.OriginalTick,
|
||||||
TxHash: src.TxHash.String(),
|
TxHash: src.TxHash.String(),
|
||||||
@@ -536,7 +546,7 @@ func mapEventTransferTransferModelToType(src gen.Brc20EventTransferTransfer) (en
|
|||||||
return entity.EventTransferTransfer{
|
return entity.EventTransferTransfer{
|
||||||
Id: uint64(src.Id),
|
Id: uint64(src.Id),
|
||||||
InscriptionId: inscriptionId,
|
InscriptionId: inscriptionId,
|
||||||
InscriptionNumber: uint64(src.InscriptionNumber),
|
InscriptionNumber: src.InscriptionNumber,
|
||||||
Tick: src.Tick,
|
Tick: src.Tick,
|
||||||
OriginalTick: src.OriginalTick,
|
OriginalTick: src.OriginalTick,
|
||||||
TxHash: *txHash,
|
TxHash: *txHash,
|
||||||
@@ -549,6 +559,7 @@ func mapEventTransferTransferModelToType(src gen.Brc20EventTransferTransfer) (en
|
|||||||
ToPkScript: toPkScript,
|
ToPkScript: toPkScript,
|
||||||
ToSatPoint: toSatPoint,
|
ToSatPoint: toSatPoint,
|
||||||
ToOutputIndex: uint32(src.ToOutputIndex),
|
ToOutputIndex: uint32(src.ToOutputIndex),
|
||||||
|
SpentAsFee: src.SpentAsFee,
|
||||||
Amount: decimalFromNumeric(src.Amount).Decimal,
|
Amount: decimalFromNumeric(src.Amount).Decimal,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@@ -560,7 +571,7 @@ func mapEventTransferTransferTypeToParams(src entity.EventTransferTransfer) (gen
|
|||||||
}
|
}
|
||||||
return gen.CreateEventTransferTransfersParams{
|
return gen.CreateEventTransferTransfersParams{
|
||||||
InscriptionID: src.InscriptionId.String(),
|
InscriptionID: src.InscriptionId.String(),
|
||||||
InscriptionNumber: int64(src.InscriptionNumber),
|
InscriptionNumber: src.InscriptionNumber,
|
||||||
Tick: src.Tick,
|
Tick: src.Tick,
|
||||||
OriginalTick: src.OriginalTick,
|
OriginalTick: src.OriginalTick,
|
||||||
TxHash: src.TxHash.String(),
|
TxHash: src.TxHash.String(),
|
||||||
@@ -573,6 +584,21 @@ func mapEventTransferTransferTypeToParams(src entity.EventTransferTransfer) (gen
|
|||||||
ToPkscript: hex.EncodeToString(src.ToPkScript),
|
ToPkscript: hex.EncodeToString(src.ToPkScript),
|
||||||
ToSatpoint: src.ToSatPoint.String(),
|
ToSatpoint: src.ToSatPoint.String(),
|
||||||
ToOutputIndex: int32(src.ToOutputIndex),
|
ToOutputIndex: int32(src.ToOutputIndex),
|
||||||
|
SpentAsFee: src.SpentAsFee,
|
||||||
Amount: numericFromDecimal(src.Amount),
|
Amount: numericFromDecimal(src.Amount),
|
||||||
}, nil
|
}, 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
|
// cache
|
||||||
outPointValueCache *lru.Cache[wire.OutPoint, uint64]
|
outPointValueCache *lru.Cache[wire.OutPoint, uint64]
|
||||||
|
|
||||||
// flush buffers
|
// flush buffers - inscription states
|
||||||
newInscriptionTransfers []*entity.InscriptionTransfer
|
newInscriptionTransfers []*entity.InscriptionTransfer
|
||||||
newInscriptionEntries map[ordinals.InscriptionId]*ordinals.InscriptionEntry
|
newInscriptionEntries map[ordinals.InscriptionId]*ordinals.InscriptionEntry
|
||||||
newInscriptionEntryStates 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
|
// TODO: move this to config
|
||||||
@@ -73,6 +81,14 @@ func NewProcessor(brc20Dg datagateway.BRC20DataGateway, indexerInfoDg datagatewa
|
|||||||
newInscriptionTransfers: make([]*entity.InscriptionTransfer, 0),
|
newInscriptionTransfers: make([]*entity.InscriptionTransfer, 0),
|
||||||
newInscriptionEntries: make(map[ordinals.InscriptionId]*ordinals.InscriptionEntry),
|
newInscriptionEntries: make(map[ordinals.InscriptionId]*ordinals.InscriptionEntry),
|
||||||
newInscriptionEntryStates: 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
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
package brc20
|
package brc20
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cockroachdb/errors"
|
"github.com/cockroachdb/errors"
|
||||||
"github.com/gaze-network/indexer-network/core/types"
|
"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/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/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"
|
||||||
"github.com/gaze-network/indexer-network/pkg/logger/slogx"
|
"github.com/gaze-network/indexer-network/pkg/logger/slogx"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
@@ -25,26 +29,93 @@ func (p *Processor) processBRC20States(ctx context.Context, transfers []*entity.
|
|||||||
payloads = append(payloads, payload)
|
payloads = append(payloads, payload)
|
||||||
ticks[payload.Tick] = struct{}{}
|
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 {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to get inscription entries by ids")
|
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)
|
newTickEntries := make(map[string]*entity.TickEntry)
|
||||||
newTickEntryStates := make(map[string]*entity.TickEntry)
|
newTickEntryStates := make(map[string]*entity.TickEntry)
|
||||||
// newDeployEvents := make([]*entity.EventDeploy, 0)
|
newEventDeploys := make([]*entity.EventDeploy, 0)
|
||||||
// newMintEvents := make([]*entity.EventMint, 0)
|
newEventMints := make([]*entity.EventMint, 0)
|
||||||
// newTransferEvents := make([]*entity.EventTransfer, 0)
|
newEventInscribeTransfers := make([]*entity.EventInscribeTransfer, 0)
|
||||||
|
newEventTransferTransfers := make([]*entity.EventTransferTransfer, 0)
|
||||||
|
newBalances := make(map[string]map[string]*entity.Balance)
|
||||||
|
|
||||||
for _, payload := range payloads {
|
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 {
|
switch payload.Op {
|
||||||
case brc20.OperationDeploy:
|
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...",
|
logger.DebugContext(ctx, "found deploy inscription but tick already exists, skipping...",
|
||||||
slogx.String("tick", payload.Tick),
|
slogx.String("tick", payload.Tick),
|
||||||
slogx.Stringer("entryInscriptionId", entry.DeployInscriptionId),
|
slogx.Stringer("entryInscriptionId", tickEntry.DeployInscriptionId),
|
||||||
slogx.Stringer("currentInscriptionId", payload.Transfer.InscriptionId),
|
slogx.Stringer("currentInscriptionId", payload.Transfer.InscriptionId),
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
@@ -58,7 +129,7 @@ func (p *Processor) processBRC20States(ctx context.Context, transfers []*entity.
|
|||||||
IsSelfMint: payload.SelfMint,
|
IsSelfMint: payload.SelfMint,
|
||||||
DeployInscriptionId: payload.Transfer.InscriptionId,
|
DeployInscriptionId: payload.Transfer.InscriptionId,
|
||||||
DeployedAt: blockHeader.Timestamp,
|
DeployedAt: blockHeader.Timestamp,
|
||||||
DeployedAtHeight: uint64(blockHeader.Height),
|
DeployedAtHeight: payload.Transfer.BlockHeight,
|
||||||
MintedAmount: decimal.Zero,
|
MintedAmount: decimal.Zero,
|
||||||
BurnedAmount: decimal.Zero,
|
BurnedAmount: decimal.Zero,
|
||||||
CompletedAt: time.Time{},
|
CompletedAt: time.Time{},
|
||||||
@@ -67,57 +138,335 @@ func (p *Processor) processBRC20States(ctx context.Context, transfers []*entity.
|
|||||||
newTickEntries[payload.Tick] = tickEntry
|
newTickEntries[payload.Tick] = tickEntry
|
||||||
newTickEntryStates[payload.Tick] = tickEntry
|
newTickEntryStates[payload.Tick] = tickEntry
|
||||||
// update entries for other operations in same block
|
// 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:
|
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...",
|
logger.DebugContext(ctx, "found mint inscription but tick does not exist, skipping...",
|
||||||
slogx.String("tick", payload.Tick),
|
slogx.String("tick", payload.Tick),
|
||||||
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
||||||
)
|
)
|
||||||
continue
|
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...",
|
logger.DebugContext(ctx, "found mint inscription but amount has invalid decimals, skipping...",
|
||||||
slogx.String("tick", payload.Tick),
|
slogx.String("tick", payload.Tick),
|
||||||
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
||||||
slogx.Stringer("amount", payload.Amt),
|
slogx.Stringer("amount", payload.Amt),
|
||||||
slogx.Uint16("entryDecimals", entry.Decimals),
|
slogx.Uint16("entryDecimals", tickEntry.Decimals),
|
||||||
slogx.Int32("payloadDecimals", -payload.Amt.Exponent()),
|
slogx.Int32("payloadDecimals", -payload.Amt.Exponent()),
|
||||||
)
|
)
|
||||||
continue
|
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:
|
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...",
|
logger.DebugContext(ctx, "found transfer inscription but tick does not exist, skipping...",
|
||||||
slogx.String("tick", payload.Tick),
|
slogx.String("tick", payload.Tick),
|
||||||
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
||||||
)
|
)
|
||||||
continue
|
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...",
|
logger.DebugContext(ctx, "found transfer inscription but amount has invalid decimals, skipping...",
|
||||||
slogx.String("tick", payload.Tick),
|
slogx.String("tick", payload.Tick),
|
||||||
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
slogx.Stringer("inscriptionId", payload.Transfer.InscriptionId),
|
||||||
slogx.Stringer("amount", payload.Amt),
|
slogx.Stringer("amount", payload.Amt),
|
||||||
slogx.Uint16("entryDecimals", entry.Decimals),
|
slogx.Uint16("entryDecimals", tickEntry.Decimals),
|
||||||
slogx.Int32("payloadDecimals", -payload.Amt.Exponent()),
|
slogx.Int32("payloadDecimals", -payload.Amt.Exponent()),
|
||||||
)
|
)
|
||||||
continue
|
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
|
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{
|
OriginOld: &entity.OriginOld{
|
||||||
OldSatPoint: satPoint,
|
OldSatPoint: satPoint,
|
||||||
Content: transfer.Content,
|
Content: transfer.Content,
|
||||||
|
InputIndex: uint32(i),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if _, ok := inscribeOffsets[offset]; !ok {
|
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 {
|
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]
|
txOut := tx.TxOut[newSatPoint.OutPoint.Index]
|
||||||
if flotsam.OriginOld != nil {
|
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)
|
entry, err := p.getInscriptionEntryById(ctx, flotsam.InscriptionId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// skip inscriptions without entry (likely non-brc20 inscriptions)
|
// 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")
|
return errors.Wrap(err, "failed to get inscription entry")
|
||||||
}
|
}
|
||||||
entry.TransferCount++
|
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)
|
// track transfers even if transfer count exceeds 2 (because we need to check for reinscriptions)
|
||||||
p.newInscriptionTransfers = append(p.newInscriptionTransfers, transfer)
|
p.newInscriptionTransfers = append(p.newInscriptionTransfers, transfer)
|
||||||
@@ -337,12 +341,15 @@ func (p *Processor) updateInscriptionLocation(ctx context.Context, newSatPoint o
|
|||||||
InscriptionId: flotsam.InscriptionId,
|
InscriptionId: flotsam.InscriptionId,
|
||||||
BlockHeight: uint64(flotsam.Tx.BlockHeight), // use flotsam's tx to track tx that initiated the transfer
|
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
|
TxIndex: flotsam.Tx.Index, // use flotsam's tx to track tx that initiated the transfer
|
||||||
|
TxHash: flotsam.Tx.TxHash,
|
||||||
Content: origin.Inscription.Content,
|
Content: origin.Inscription.Content,
|
||||||
|
FromInputIndex: 0, // unused
|
||||||
OldSatPoint: ordinals.SatPoint{},
|
OldSatPoint: ordinals.SatPoint{},
|
||||||
NewSatPoint: newSatPoint,
|
NewSatPoint: newSatPoint,
|
||||||
NewPkScript: txOut.PkScript,
|
NewPkScript: txOut.PkScript,
|
||||||
NewOutputValue: uint64(txOut.Value),
|
NewOutputValue: uint64(txOut.Value),
|
||||||
SentAsFee: sentAsFee,
|
SentAsFee: sentAsFee,
|
||||||
|
TransferCount: 1, // count inscription as first transfer
|
||||||
}
|
}
|
||||||
entry := &ordinals.InscriptionEntry{
|
entry := &ordinals.InscriptionEntry{
|
||||||
Id: flotsam.InscriptionId,
|
Id: flotsam.InscriptionId,
|
||||||
@@ -510,6 +517,58 @@ func (p *Processor) getInscriptionEntriesByIds(ctx context.Context, ids []ordina
|
|||||||
return result, nil
|
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 {
|
func (p *Processor) getBlockSubsidy(blockHeight uint64) uint64 {
|
||||||
return uint64(blockchain.CalcBlockSubsidy(int32(blockHeight), p.network.ChainParams()))
|
return uint64(blockchain.CalcBlockSubsidy(int32(blockHeight), p.network.ChainParams()))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user