Skip to content

Commit

Permalink
feat: support self minted 5-byte wide BRC-20 tokens (#338)
Browse files Browse the repository at this point in the history
* feat: first features

* test: invalid parent

* feat: unlimited supply self mint

* test: transfer for self mint token
  • Loading branch information
rafaelcr committed Mar 27, 2024
1 parent f2077ed commit 60f46d3
Show file tree
Hide file tree
Showing 8 changed files with 757 additions and 83 deletions.
19 changes: 19 additions & 0 deletions migrations/1711465842961_brc20-deploy-self-mint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { MigrationBuilder, ColumnDefinitions } from 'node-pg-migrate';

export const shorthands: ColumnDefinitions | undefined = undefined;

export function up(pgm: MigrationBuilder): void {
pgm.addColumn('brc20_deploys', {
self_mint: {
type: 'boolean',
default: 'false',
},
});
pgm.sql(`UPDATE brc20_deploys SET self_mint = false`);
pgm.alterColumn('brc20_deploys', 'self_mint', { notNull: true });
}

export function down(pgm: MigrationBuilder): void {
pgm.dropColumn('brc20_deploys', ['self_mint']);
}
1 change: 1 addition & 0 deletions src/api/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,7 @@ export const Brc20TokenResponseSchema = Type.Object(
deploy_timestamp: Type.Integer({ examples: [1677733170000] }),
minted_supply: Type.String({ examples: ['1000000'] }),
tx_count: Type.Integer({ examples: [300000] }),
self_mint: Type.Boolean(),
},
{ title: 'BRC-20 Token Response' }
);
Expand Down
1 change: 1 addition & 0 deletions src/api/util/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export function parseBrc20Tokens(items: DbBrc20Token[]): Brc20TokenResponse[] {
deploy_timestamp: i.timestamp.valueOf(),
minted_supply: decimals(i.minted_supply, i.decimals),
tx_count: parseInt(i.tx_count),
self_mint: i.self_mint,
}));
}

Expand Down
22 changes: 15 additions & 7 deletions src/pg/brc20/brc20-pg-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
DbPaginatedResult,
InscriptionEventData,
LocationData,
InscriptionRevealData,
} from '../types';
import {
BRC20_DEPLOYS_COLUMNS,
Expand All @@ -25,7 +26,7 @@ import {
DbBrc20TokenWithSupply,
DbBrc20TransferEvent,
} from './types';
import { Brc20Deploy, Brc20Mint, Brc20Transfer, brc20FromInscription } from './helpers';
import { Brc20Deploy, Brc20Mint, Brc20Transfer, UINT64_MAX, brc20FromInscription } from './helpers';
import { Brc20TokenOrderBy } from '../../api/schemas';
import { objRemoveUndefinedValues } from '../helpers';

Expand Down Expand Up @@ -198,7 +199,7 @@ export class Brc20PgStore extends BasePgStoreModule {

private async insertDeploy(deploy: {
brc20: Brc20Deploy;
reveal: InscriptionEventData;
reveal: InscriptionRevealData;
pointer: DbLocationPointerInsert;
}): Promise<void> {
if (deploy.reveal.location.transfer_type != DbLocationTransferType.transferred) return;
Expand All @@ -208,10 +209,11 @@ export class Brc20PgStore extends BasePgStoreModule {
tx_id: deploy.reveal.location.tx_id,
address: deploy.pointer.address as string,
ticker: deploy.brc20.tick,
max: deploy.brc20.max,
max: deploy.brc20.max === '0' ? UINT64_MAX.toString() : deploy.brc20.max,
limit: deploy.brc20.lim ?? null,
decimals: deploy.brc20.dec ?? '18',
tx_count: 1,
self_mint: deploy.brc20.self_mint === 'true',
};
const deployRes = await this.sql`
WITH deploy_insert AS (
Expand Down Expand Up @@ -248,19 +250,21 @@ export class Brc20PgStore extends BasePgStoreModule {

private async insertMint(mint: {
brc20: Brc20Mint;
reveal: InscriptionEventData;
reveal: InscriptionRevealData;
pointer: DbLocationPointerInsert;
}): Promise<void> {
if (mint.reveal.location.transfer_type != DbLocationTransferType.transferred) return;
// Check the following conditions:
// * Is the mint amount within the allowed token limits?
// * Is this a self_mint with the correct parent inscription?
// * Is the number of decimals correct?
// * Does the mint amount exceed remaining supply?
const mintRes = await this.sql`
WITH mint_data AS (
SELECT id, decimals, "limit", max, minted_supply
FROM brc20_deploys
WHERE ticker_lower = LOWER(${mint.brc20.tick}) AND minted_supply < max
SELECT d.id, d.decimals, d."limit", d.max, d.minted_supply, d.self_mint, i.genesis_id
FROM brc20_deploys d
INNER JOIN inscriptions i ON i.id = d.inscription_id
WHERE d.ticker_lower = LOWER(${mint.brc20.tick}) AND d.minted_supply < d.max
),
validated_mint AS (
SELECT
Expand All @@ -269,6 +273,10 @@ export class Brc20PgStore extends BasePgStoreModule {
FROM mint_data
WHERE ("limit" IS NULL OR ${mint.brc20.amt}::numeric <= "limit")
AND (SCALE(${mint.brc20.amt}::numeric) <= decimals)
AND (
self_mint = FALSE OR
(self_mint = TRUE AND genesis_id = ${mint.reveal.inscription.parent})
)
),
mint_insert AS (
INSERT INTO brc20_mints (inscription_id, brc20_deploy_id, block_height, tx_id, address, amount) (
Expand Down
23 changes: 20 additions & 3 deletions src/pg/brc20/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const Brc20DeploySchema = Type.Object(
max: Brc20NumberSchema,
lim: Type.Optional(Brc20NumberSchema),
dec: Type.Optional(Type.RegEx(/^\d+$/)),
self_mint: Type.Optional(Type.Literal('true')),
},
{ additionalProperties: true }
);
Expand Down Expand Up @@ -46,10 +47,16 @@ const Brc20Schema = Type.Union([Brc20DeploySchema, Brc20MintSchema, Brc20Transfe
const Brc20C = TypeCompiler.Compile(Brc20Schema);
export type Brc20 = Static<typeof Brc20Schema>;

const UINT64_MAX = BigNumber('18446744073709551615'); // 20 digits
export const UINT64_MAX = BigNumber('18446744073709551615'); // 20 digits
// Only compare against `UINT64_MAX` if the number is at least the same number of digits.
const numExceedsMax = (num: string) => num.length >= 20 && UINT64_MAX.isLessThan(num);

/**
* Activation block height for
* https://l1f.discourse.group/t/brc-20-proposal-for-issuance-and-burn-enhancements-brc20-ip-1/621/1
*/
export const BRC20_SELF_MINT_ACTIVATION_BLOCK = 837090;

export function brc20FromInscription(reveal: InscriptionRevealData): Brc20 | undefined {
if (
reveal.inscription.classic_number < 0 ||
Expand All @@ -62,10 +69,20 @@ export function brc20FromInscription(reveal: InscriptionRevealData): Brc20 | und
const json = JSON.parse(hexToBuffer(reveal.inscription.content as string).toString('utf-8'));
if (Brc20C.Check(json)) {
// Check ticker byte length
if (Buffer.from(json.tick).length !== 4) return;
const tick = Buffer.from(json.tick);
if (json.op === 'deploy') {
if (
tick.length === 5 &&
(reveal.location.block_height < BRC20_SELF_MINT_ACTIVATION_BLOCK ||
json.self_mint !== 'true')
)
return;
}
if (tick.length < 4 || tick.length > 5) return;
// Check numeric values.
if (json.op === 'deploy') {
if (parseFloat(json.max) == 0 || numExceedsMax(json.max)) return;
if ((parseFloat(json.max) == 0 && json.self_mint !== 'true') || numExceedsMax(json.max))
return;
if (json.lim && (parseFloat(json.lim) == 0 || numExceedsMax(json.lim))) return;
if (json.dec && parseFloat(json.dec) > 18) return;
} else {
Expand Down
3 changes: 3 additions & 0 deletions src/pg/brc20/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export type DbBrc20DeployInsert = {
decimals: string;
limit: string | null;
tx_count: number;
self_mint: boolean;
};

export type DbBrc20MintInsert = {
Expand Down Expand Up @@ -78,6 +79,7 @@ export type DbBrc20Token = {
timestamp: number;
minted_supply: string;
tx_count: string;
self_mint: boolean;
};

export type DbBrc20TokenWithSupply = DbBrc20Token & {
Expand Down Expand Up @@ -188,6 +190,7 @@ export const BRC20_DEPLOYS_COLUMNS = [
'limit',
'minted_supply',
'tx_count',
'self_mint',
];

export const BRC20_TRANSFERS_COLUMNS = [
Expand Down
Loading

0 comments on commit 60f46d3

Please sign in to comment.