Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Inscription] Demo subscribe inscriptions #2883

Open
wants to merge 1 commit into
base: subwallet-dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions packages/extension-base/src/koni/api/nft/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
import { _ChainAsset, _ChainInfo } from '@subwallet/chain-list/types';
import { NftCollection, NftItem } from '@subwallet/extension-base/background/KoniTypes';
import { AcalaNftApi } from '@subwallet/extension-base/koni/api/nft/acala_nft';
// import { AcalaNftApi } from '@subwallet/extension-base/koni/api/nft/acala_nft';
import { BitCountryNftApi } from '@subwallet/extension-base/koni/api/nft/bit.country';
import { EvmNftApi } from '@subwallet/extension-base/koni/api/nft/evm_nft';
import { InscriptionApi } from '@subwallet/extension-base/koni/api/nft/inscription';
import { KaruraNftApi } from '@subwallet/extension-base/koni/api/nft/karura_nft';
import { BaseNftApi } from '@subwallet/extension-base/koni/api/nft/nft';
import OrdinalNftApi from '@subwallet/extension-base/koni/api/nft/ordinal_nft';
import { RmrkNftApi } from '@subwallet/extension-base/koni/api/nft/rmrk_nft';
import StatemineNftApi from '@subwallet/extension-base/koni/api/nft/statemine_nft';
import { UniqueNftApi } from '@subwallet/extension-base/koni/api/nft/unique_network_nft';
// import UniqueNftApi from '@subwallet/extension-base/koni/api/nft/unique_nft';
import { VaraNftApi } from '@subwallet/extension-base/koni/api/nft/vara_nft';
import { WasmNftApi } from '@subwallet/extension-base/koni/api/nft/wasm_nft';
Expand All @@ -36,7 +37,9 @@ function createSubstrateNftApi (chain: string, substrateApi: _SubstrateApi | nul
} else if (_NFT_CHAIN_GROUP.statemint.includes(chain)) {
return new StatemintNftApi(substrateApi, substrateAddresses, chain);
} else if (_NFT_CHAIN_GROUP.unique_network.includes(chain)) {
return new UniqueNftApi(chain, substrateAddresses);
return new InscriptionApi(chain, substrateAddresses);
// todo: fake to demo inscription
// return new UniqueNftApi(chain, substrateAddresses);
} else if (_NFT_CHAIN_GROUP.bitcountry.includes(chain)) {
return new BitCountryNftApi(substrateApi, substrateAddresses, chain);
} else if (_NFT_CHAIN_GROUP.vara.includes(chain)) {
Expand Down
32 changes: 32 additions & 0 deletions packages/extension-base/src/koni/api/nft/inscription/constant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2019-2022 @subwallet/extension-koni authors & contributors
// SPDX-License-Identifier: Apache-2.0

export const HIRO_API = {
api_status: 'https://api.hiro.so/ordinals/v1/',

list_of_incriptions: 'https://api.hiro.so/ordinals/v1/inscriptions',
transfers_per_block: 'https://api.hiro.so/ordinals/v1/inscriptions/transfers',
specific_inscription: 'https://api.hiro.so/ordinals/v1/inscriptions/:id',
inscription_content: 'https://api.hiro.so/ordinals/v1/inscriptions/:id/content',
inscription_transfers: 'https://api.hiro.so/ordinals/v1/inscriptions/:id/transfers',

satoshi_ordinal: 'https://api.hiro.so/ordinals/v1/sats/:ordinal',
satoshi_inscriptions: 'https://api.hiro.so/ordinals/v1/sats/:ordinal/inscriptions',

inscription_count_per_block: 'https://api.hiro.so/ordinals/v1/stats/inscriptions',

brc20_tokens: 'https://api.hiro.so/ordinals/v1/brc-20/tokens',
brc20_token_details: 'https://api.hiro.so/ordinals/v1/brc-20/tokens/:ticker',
brc20_token_holders: 'https://api.hiro.so/ordinals/v1/brc-20/tokens/:ticker/holders',
brc20_balances: 'https://api.hiro.so/ordinals/v1/brc-20/balances/:address',
brc20_activity: 'https://api.hiro.so/ordinals/v1/brc-20/activity'
};

export const ORD_IO_URL = {
url: 'https://www.ord.io/'
};

export const SUPPORT_SRC_VIEWER = {
inscription_info_url: 'https://ordinals.hiro.so/inscription/:id',
frame_preview_url: 'https://ordinals.com/preview/:id'
};
200 changes: 200 additions & 0 deletions packages/extension-base/src/koni/api/nft/inscription/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
// Copyright 2019-2022 @subwallet/extension-koni authors & contributors
// SPDX-License-Identifier: Apache-2.0

// eslint-disable-next-line camelcase
import { NftCollection, NftItem } from '@subwallet/extension-base/background/KoniTypes';
// eslint-disable-next-line camelcase
import { HIRO_API } from '@subwallet/extension-base/koni/api/nft/inscription/constant';
import { BaseNftApi, HandleNftParams } from '@subwallet/extension-base/koni/api/nft/nft';
import axios from 'axios';

// const TEST_ADDRESS = 'bc1psu0gqjuyzc5dtcrqu6ewkfe9y94cnm3pjn4vhgem9nr0hzl6w3hqj24zq9';
// const TEST_ADDRESS = 'bc1q8cpn3zl6lz5xrxdqgx7j68ggcpjm7ctzyds82c';
const TEST_ADDRESS = 'bc1p5zy5mrjfz00lr7nvy3vzvusdws85ldxzrqxacgajqwurc70wqsqsdx5ye6';

export class InscriptionApi extends BaseNftApi {
constructor (chain: string, addresses: string[]) {
super(chain, undefined, addresses);
}

private createInscriptionInfoUrl (id: string) {
return `https://ordinals.hiro.so/inscription/${id}`;
}

private createIframePreviewUrl (id: string) {
return `https://ordinals.com/preview/${id}`;
}

private parseInsUrl (id: string, type: string) {
if (type.startsWith('audio/') || type.startsWith('text/html') || type.startsWith('image/svg') || type.startsWith('video/') || type.startsWith('model/gltf')) {
return this.createIframePreviewUrl(id);
}

if (type.startsWith('text/')) {
return this.createInscriptionInfoUrl(id);
}

if (type.startsWith('image/')) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions,camelcase
return `${HIRO_API.list_of_incriptions}/${id}/content`;
}

return undefined;
}

private async getBalances (address: string) {
const pageSize = 50;
let offset = 0;
const ordinalsFullList: Array<any> = []; // todo: replace type InscriptionResponseItem[]

const configListOrdinals = {
method: 'get',
maxBodyLength: Infinity,
// eslint-disable-next-line camelcase
url: HIRO_API.list_of_incriptions + `?address=${address}&limit=${pageSize}&offset=${offset}`,
headers: {
Accept: 'application/json'
}
};

try {
while (true) {
const response = await axios.request(configListOrdinals);

// check if response is a null array
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if (response.data.results.length !== 0) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unsafe-member-access
ordinalsFullList.push(...response.data.results);
offset += pageSize;
// eslint-disable-next-line camelcase
configListOrdinals.url = HIRO_API.list_of_incriptions + `?address=${address}&limit=${pageSize}&offset=${offset}`;
} else {
break;
}
}

// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return ordinalsFullList;
} catch (error) {
console.error(`Failed to get ${address} balances`, error);
throw error;
}
}

// private async getOrdinalContent (id: string) {
// const configContent = {
// method: 'get',
// maxBodyLength: Infinity,
// // eslint-disable-next-line camelcase
// url: HIRO_API.inscription_content.replace(':id', id),
// headers: {
// Accept: 'application/json'
// }
// };
//
// try {
// const response = await axios.request(configContent);
//
// // eslint-disable-next-line @typescript-eslint/no-unsafe-return
// return response.data;
// } catch (error) {
// console.error(`Failed to get content of ordinal with id: ${id}`, error);
// }
// }

public async handleNfts (params: HandleNftParams) {
try {
const balances = await this.getBalances(TEST_ADDRESS);

console.log('balances', balances);

// @ts-ignore
if (balances.length > 0) {
const collectionMap: Record <string, NftCollection> = {};

// @ts-ignore
for (const ins of balances) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
if (ins.content_type.startsWith('text/plain')) {
continue;
}

const parsedNft: NftItem = {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access
id: ins.id,
chain: this.chain,
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access
owner: '5CUoqFyU2b9dN1JZtPk3qRFVjKu2tQGcf91ZMcMNeH5y35Vb',
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access
name: ins.number,
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unsafe-member-access
image: this.parseInsUrl(ins.id, ins.content_type),
// description: ins.collection_description,
collectionId: '1'
};

console.log('parsedNft', parsedNft);

params.updateItem(this.chain, parsedNft, '5CUoqFyU2b9dN1JZtPk3qRFVjKu2tQGcf91ZMcMNeH5y35Vb');

if (!collectionMap['1']) {
const parsedCollection: NftCollection = {
collectionId: '1',
chain: this.chain,
collectionName: 'DEDMINE',
image: 'https://ipfs.unique.network/ipfs/Qmdz4bBw8HjK4iWevx8bz46t2dzdSspdcFaiFvHDaCmD9g'
};

collectionMap['1'] = parsedCollection;
params.updateCollection(this.chain, parsedCollection);
console.log('parsedCollection', parsedCollection);
}
}

// const ordinalPromises: Promise<Inscription | undefined>[] = balances.map(async (ordinal: { id: string; number: any; address: any; genesis_block_height: string; genesis_block_hash: any; genesis_timestamp: any; genesis_tx_id: any; location: any; output: any; value: string; genesis_fee: string; sat_ordinal: string; sat_rarity: any; content_type: any; content_length: any; }) => {
// if (ordinal.content_type === 'text/plain') { // todo: this inscription is usually used for the minting, transfering, ... for BRC20. Need recheck.
// return undefined;
// }
//
// const content = await this.getOrdinalContent(ordinal.id);
//
// return {
// id: ordinal.id,
// number: ordinal.number,
// address: ordinal.address,
// block: parseInt(ordinal.genesis_block_height),
// block_hash: ordinal.genesis_block_hash,
// timestamp: ordinal.genesis_timestamp,
// tx_id: ordinal.genesis_tx_id,
// location: ordinal.location,
// output: ordinal.output,
// value: parseInt(ordinal.value),
// fee: parseInt(ordinal.genesis_fee),
// sat_ordinal: parseInt(ordinal.sat_ordinal),
// sat_rarity: ordinal.sat_rarity,
// content_type: ordinal.content_type,
// content_length: ordinal.content_length,
// content: content
// };
// });
// const ordinal_list = (await Promise.all(ordinalPromises)).filter(Boolean) as Inscription[];
// const filePath = 'test/output_text/output.json';
//
// fs.writeFileSync(filePath, JSON.stringify(ordinal_list, null, 2), 'utf-8');
}
} catch (error) {
console.error('Failed to fetch ordinals', error);
}
}

public async fetchNfts (params: HandleNftParams): Promise<number> {
try {
await this.handleNfts(params);
} catch (e) {
return 0;
}

return 1;
}
}
49 changes: 49 additions & 0 deletions packages/extension-base/src/koni/api/nft/inscription/interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright 2019-2022 @subwallet/extension-koni authors & contributors
// SPDX-License-Identifier: Apache-2.0

export interface Inscription {
id: string;
number: number;
address: string;
block: number;
block_hash: string;
timestamp: number;
tx_id: string;
location: string;
output: string;
value: number;
fee: number;
sat_ordinal: number;
sat_rarity: string;
content_type: string;
content_length: number;
content: any;
}

// all metadata return from Hiro
export interface InscriptionResponseItem {
address: string;
content_length: number;
content_type: string;
curse_type: string | null;
genesis_address: string;
genesis_block_hash: string;
genesis_block_height: number;
genesis_fee: string;
genesis_timestamp: number;
genesis_tx_id: string;
id: string;
location: string;
mime_type: string;
number: number;
offset: string;
output: string;
recursive: boolean;
recursion_refs: string | null;
sat_coinbase_height: number;
sat_ordinal: string;
sat_rarity: string;
timestamp: number;
tx_id: string;
value: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ export class UniqueNftApi extends BaseNftApi {
};

params.updateItem(this.chain, parsedNft, address);
console.log('parsedNft', parsedNft);

// Update Collection information
if (!collectionMap[nft.collection_id.toString()]) {
Expand All @@ -168,6 +169,7 @@ export class UniqueNftApi extends BaseNftApi {

collectionMap[nft.collection_id.toString()] = parsedCollection;
params.updateCollection(this.chain, parsedCollection);
console.log('parsedCollection', parsedCollection);
}
}
}
Expand Down
10 changes: 8 additions & 2 deletions packages/extension-base/src/koni/background/subscription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,14 @@ export class KoniSubscription {

nftHandler.handleNfts(
smartContractNfts,
(...args) => this.state.updateNftData(...args),
(...args) => this.state.setNftCollection(...args)
(...args) => {
this.state.updateNftData(...args);
console.log('updateNftData', args);
},
(...args) => {
this.state.setNftCollection(...args);
console.log('setNftCollection', args);
}
).catch(this.logger.log);
}

Expand Down
Loading