Skip to content

Commit

Permalink
feat: implement query field resolvers to list the address's assets/ba…
Browse files Browse the repository at this point in the history
…lances (#168)

Merge pull request #168 from utxostack/145-feat-a-query-interface-to-list-the-coins-held-by-an-address
  • Loading branch information
Flouse authored Sep 19, 2024
2 parents 28a2629 + b6cae53 commit 9ef448f
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 23 deletions.
3 changes: 2 additions & 1 deletion backend/src/modules/rgbpp/address/address.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { CkbRpcModule } from 'src/core/ckb-rpc/ckb-rpc.module';
import { RgbppModule } from '../rgbpp.module';
import { CkbTransactionModule } from 'src/modules/ckb/transaction/transaction.module';
import { BullModule } from '@nestjs/bullmq';
import { RgbppAddressService } from './address.service';

@Module({
imports: [
Expand All @@ -22,6 +23,6 @@ import { BullModule } from '@nestjs/bullmq';
},
}),
],
providers: [RgbppAddressResolver],
providers: [RgbppAddressResolver, RgbppAddressService],
})
export class RgbppAddressModule {}
30 changes: 10 additions & 20 deletions backend/src/modules/rgbpp/address/address.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ import { RgbppAddress } from './address.model';
import { ParentField } from 'src/decorators/parent-field.decorator';
import { RgbppAsset } from '../asset/asset.model';
import { CkbXUDTInfo } from 'src/modules/ckb/cell/cell.model';
import { Loader } from 'src/common/dataloader';
import {
CkbExplorerTransactionLoader,
CkbExplorerTransactionLoaderType,
} from 'src/modules/ckb/transaction/transaction.dataloader';
import { RgbppAddressService } from './address.service';

@Resolver(() => RgbppAddress)
export class RgbppAddressResolver {
constructor(private ckbExplorerService: CkbExplorerService) { }
constructor(
private ckbExplorerService: CkbExplorerService,
private rgbppAddressService: RgbppAddressService,
) {}

@Query(() => RgbppAddress, { name: 'rgbppAddress', nullable: true })
public async getBtcAddress(@Args('address') address: string): Promise<RgbppAddress> {
Expand All @@ -27,24 +26,15 @@ export class RgbppAddressResolver {
return cells.meta.total;
}

@ResolveField(() => Float)
public async cellsCount(@ParentField('address') address: string): Promise<number> {
// TODO: implement this
return 0;
}

@ResolveField(() => [RgbppAsset])
public async assets(@ParentField('address') address: string): Promise<RgbppAsset[]> {
// TODO: implement this
return [];
const assets = await this.rgbppAddressService.getAddressAssets(address);
return assets;
}

@ResolveField(() => [CkbXUDTInfo])
public async balances(
@ParentField('address') address: string,
@Loader(CkbExplorerTransactionLoader) explorerTxLoader: CkbExplorerTransactionLoaderType,
): Promise<(CkbXUDTInfo | null)[]> {
// TODO: implement this
return [];
public async balances(@ParentField('address') address: string): Promise<(CkbXUDTInfo | null)[]> {
const balances = await this.rgbppAddressService.getAddressBalances(address);
return balances;
}
}
83 changes: 83 additions & 0 deletions backend/src/modules/rgbpp/address/address.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { BI } from '@ckb-lumos/bi';
import { Injectable } from '@nestjs/common';
import { CkbExplorerService } from 'src/core/ckb-explorer/ckb-explorer.service';
import { PrismaService } from 'src/core/database/prisma/prisma.service';
import { CkbCell, CkbXUDTInfo } from 'src/modules/ckb/cell/cell.model';
import { RgbppAsset } from '../asset/asset.model';
import { CkbRpcWebsocketService } from 'src/core/ckb-rpc/ckb-rpc-websocket.service';
import { CKB_CHAIN_ID } from 'src/constants';

@Injectable()
export class RgbppAddressService {
constructor(
private prismaService: PrismaService,
private ckbExplorerService: CkbExplorerService,
private ckbRpcService: CkbRpcWebsocketService,
) { }

public async getAddressAssets(address: string) {
const lockScript = await this.prismaService.lockScript.findMany({
where: {
ownerAddress: address,
chainId: CKB_CHAIN_ID,
},
});
if (lockScript.length === 0) {
return [];
}
const results = await this.prismaService.asset.findMany({
where: {
lockScriptHash: {
in: lockScript.map((script) => script.scriptHash),
},
isLive: true,
},
});
if (results.length === 0) {
return [];
}
const outputMap = results.reduce(
(map, { txHash, index }) => {
if (map[txHash] === undefined) {
map[txHash] = [];
}
map[txHash].push(index);
return map;
},
{} as Record<string, string[]>,
);
const assets = await Promise.all(
Object.keys(outputMap).map(async (txHash) => {
const tx = await this.ckbRpcService.getTransaction(txHash);
return outputMap[txHash].map((index) =>
RgbppAsset.fromTransaction(address, tx.transaction, BI.from(index).toNumber()),
);
}),
);
return assets.flat();
}

public async getAddressBalances(address: string): Promise<CkbXUDTInfo[]> {
const result = await this.prismaService.holder.findMany({
where: {
address,
},
orderBy: {
assetAmount: 'desc',
},
});
const balances = await Promise.all(
result.map(async ({ typeScriptHash, assetAmount }) => {
const info = await this.ckbExplorerService.getXUDT(typeScriptHash);
const xudtInfo: CkbXUDTInfo = {
symbol: info.data.attributes.symbol,
decimal: BI.from(info.data.attributes.decimal).toNumber(),
typeHash: typeScriptHash,
amount: assetAmount.toHex(),
};
return xudtInfo;
}),
);
return balances;
}
}
13 changes: 12 additions & 1 deletion backend/src/modules/rgbpp/asset/asset.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,21 @@ export class RgbppAsset {
@Field(() => CkbCell)
cell: CkbCell;

public static from(address: string, cell: CkbRpc.Cell): RgbppAsset {
public static fromCell(address: string, cell: CkbRpc.Cell): RgbppAsset {
return {
owner: address,
cell: CkbCell.fromCell(cell),
};
}

public static fromTransaction(
address: string,
tx: CkbRpc.Transaction,
index: number,
): RgbppAsset {
return {
owner: address,
cell: CkbCell.fromTransaction(tx, index),
};
}
}
1 change: 0 additions & 1 deletion backend/src/schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,6 @@ type BitcoinTransaction {
type RgbppAddress {
address: String!
utxosCount: Float!
cellsCount: Float!
assets: [RgbppAsset!]!
balances: [CkbXUDTInfo!]!
}
Expand Down

0 comments on commit 9ef448f

Please sign in to comment.