Skip to content

Commit

Permalink
refactor: calculate XUDT amount separately in AssetSummarizer with de…
Browse files Browse the repository at this point in the history
…tailed XUDT related fields (#275)
  • Loading branch information
ShookLyngs authored Aug 13, 2024
1 parent 215dd98 commit 2d1c834
Show file tree
Hide file tree
Showing 6 changed files with 433 additions and 101 deletions.
5 changes: 5 additions & 0 deletions .changeset/hot-needles-chew.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'rgbpp': patch
---

Calculate XUDT amount separately in AssetSummarizer
81 changes: 51 additions & 30 deletions packages/rgbpp/src/rgbpp/summary/asset-summarizer.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { Cell } from '@ckb-lumos/base';
import { Utxo, encodeUtxoId } from '@rgbpp-sdk/btc';
import { leToU128, encodeCellId } from '@rgbpp-sdk/ckb';
import { leToU128, encodeCellId, isUDTTypeSupported } from '@rgbpp-sdk/ckb';

export interface AssetSummary {
export interface AssetGroup {
utxo: Utxo;
cells: Cell[];
}

export interface XudtAssetSummary {
amount: bigint;
utxoCount: number;
cellCount: number;
Expand All @@ -11,55 +16,68 @@ export interface AssetSummary {
export interface AssetGroupSummary {
utxoId: string;
cellIds: string[];
// The key of the assets record is the `xudtTypeArgs` (the unique identifier for the asset type)
assets: Record<string, AssetSummary>; // Record<xudtTypeAgs, AssetSummary>
xudtCellIds: string[];
xudtAssets: Record<string, XudtAssetSummary>; // Record<xudtTypeArgs, AssetSummary>
}

export interface TransactionGroupSummary {
utxoCount: number;
cellCount: number;
xudtCellCount: number;
utxoIds: string[];
cellIds: string[];
assets: Record<string, AssetSummary>;
xudtCellIds: string[];
xudtAssets: Record<string, XudtAssetSummary>; // Record<xudtTypeArgs, AssetSummary>
}

export class AssetSummarizer {
groups: AssetGroupSummary[] = [];

constructor() {}
constructor(public isMainnet: boolean) {}

addGroup(utxo: Utxo, cells: Cell[]): AssetGroupSummary {
const utxoId = encodeUtxoId(utxo.txid, utxo.vout);
const assets: Record<string, AssetSummary> = {};
const cellIds: string[] = [];

const cellIds: string[] = [];
const xudtCellIds: string[] = [];
const xudtAssets: Record<string, XudtAssetSummary> = {};
for (const cell of cells) {
cellIds.push(encodeCellId(cell.outPoint!.txHash, cell.outPoint!.index));
const xudtTypeArgs = cell.cellOutput.type?.args ?? 'empty';
const amount = leToU128(cell.data.substring(0, 34));
if (assets[xudtTypeArgs] === undefined) {
assets[xudtTypeArgs] = {
utxoCount: 1,
cellCount: 0,
amount: 0n,
};
}
const cellId = encodeCellId(cell.outPoint!.txHash, cell.outPoint!.index);
cellIds.push(cellId);

const isXudt = !!cell.cellOutput.type && isUDTTypeSupported(cell.cellOutput.type, this.isMainnet);
if (isXudt) {
// If the cell type is a supported xUDT type, record its asset information
const xudtTypeArgs = cell.cellOutput.type?.args ?? 'empty';
const amount = leToU128(cell.data.substring(0, 34));
if (xudtAssets[xudtTypeArgs] === undefined) {
xudtAssets[xudtTypeArgs] = {
utxoCount: 1,
cellCount: 0,
amount: 0n,
};
}

assets[xudtTypeArgs]!.cellCount += 1;
assets[xudtTypeArgs]!.amount += amount;
xudtCellIds.push(cellId);
xudtAssets[xudtTypeArgs]!.cellCount += 1;
xudtAssets[xudtTypeArgs]!.amount += amount;
} else {
// TODO: if the cell type is empty or is not xUDT, how to handle/record its info?
}
}

const result: AssetGroupSummary = {
utxoId,
cellIds,
assets,
xudtCellIds,
xudtAssets,
};

this.groups.push(result);
return result;
}

addGroups(groups: { utxo: Utxo; cells: Cell[] }[]): TransactionGroupSummary {
addGroups(groups: AssetGroup[]): TransactionGroupSummary {
const groupResults = groups.map((group) => this.addGroup(group.utxo, group.cells));
return this.summarizeGroups(groupResults);
}
Expand All @@ -76,32 +94,35 @@ export class AssetSummarizer {
const targetGroups = groups ?? this.groups;
const utxoIds = targetGroups.map((summary) => summary.utxoId);
const cellIds = targetGroups.flatMap((summary) => summary.cellIds);
const assets = targetGroups.reduce(
const xudtCellIds = targetGroups.flatMap((summary) => summary.xudtCellIds);
const xudtAssets = targetGroups.reduce(
(result, summary) => {
for (const xudtTypeArgs in summary.assets) {
if (result[xudtTypeArgs] === undefined) {
for (const xudtTypeArgs in summary.xudtAssets) {
if (!result[xudtTypeArgs]) {
result[xudtTypeArgs] = {
utxoCount: 0,
cellCount: 0,
amount: 0n,
};
}

result[xudtTypeArgs]!.utxoCount += summary.assets[xudtTypeArgs]!.utxoCount;
result[xudtTypeArgs]!.cellCount += summary.assets[xudtTypeArgs]!.cellCount;
result[xudtTypeArgs]!.amount += summary.assets[xudtTypeArgs]!.amount;
result[xudtTypeArgs]!.utxoCount += summary.xudtAssets[xudtTypeArgs]!.utxoCount;
result[xudtTypeArgs]!.cellCount += summary.xudtAssets[xudtTypeArgs]!.cellCount;
result[xudtTypeArgs]!.amount += summary.xudtAssets[xudtTypeArgs]!.amount;
}
return result;
},
{} as Record<string, AssetSummary>,
{} as Record<string, XudtAssetSummary>,
);

return {
utxoCount: utxoIds.length,
cellCount: cellIds.length,
xudtCellCount: xudtCellIds.length,
utxoIds,
cellIds,
assets,
xudtCellIds,
xudtAssets,
};
}
}
6 changes: 3 additions & 3 deletions packages/rgbpp/src/rgbpp/xudt/btc-transfer-all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export async function buildRgbppTransferAllTxs(params: RgbppTransferAllTxsParams
const groupedAssetGroups = mapGroupsByIndices(groupedByInputs.indices, (index) => rgbppGroups[index]!);

// Construct transaction groups
const summarizer = new AssetSummarizer();
const summarizer = new AssetSummarizer(isMainnet);
const usedBtcUtxos: BaseOutput[] = [];
const transactionGroups: RgbppTransferAllTxGroup[] = [];
for (const assetGroups of groupedAssetGroups) {
Expand All @@ -138,7 +138,7 @@ export async function buildRgbppTransferAllTxs(params: RgbppTransferAllTxsParams
);

// Props for constructing CKB_VTX
const xudtAmount = groupSummary.assets[params.ckb.xudtTypeArgs]!.amount;
const xudtAmount = groupSummary.xudtAssets[params.ckb.xudtTypeArgs]!.amount;
const lockArgsList = groupSummary.utxoIds.map((utxoId) => {
const output = decodeUtxoId(utxoId)!;
return buildRgbppLockArgs(output.vout, output.txid);
Expand Down Expand Up @@ -221,7 +221,7 @@ export async function buildRgbppTransferAllTxs(params: RgbppTransferAllTxsParams
}

// Generate result
const excludedSummarizer = new AssetSummarizer();
const excludedSummarizer = new AssetSummarizer(isMainnet);
excludedSummarizer.addGroups(
[...invalidUtxoIds].map((utxoId) => ({
utxo: utxoMap.get(utxoId)!,
Expand Down
16 changes: 8 additions & 8 deletions packages/rgbpp/tests/RgbppXudt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,16 +98,16 @@ describe('RgbppXudt', () => {
});

console.log('result.transactions.length', result.transactions.length);
console.log('result.summary.included.assets', result.summary.included.assets);
console.log('result.summary.excluded.assets', result.summary.excluded.assets);
console.log('result.summary.included.assets', result.summary.included.xudtAssets);
console.log('result.summary.excluded.assets', result.summary.excluded.xudtAssets);

expect(result.summary.included.assets).toHaveProperty(xudtTypeArgs);
expect(result.summary.included.assets[xudtTypeArgs].cellCount).toEqual(50);
expect(result.summary.included.assets[xudtTypeArgs].utxoCount).toEqual(50);
expect(result.summary.included.xudtAssets).toHaveProperty(xudtTypeArgs);
expect(result.summary.included.xudtAssets[xudtTypeArgs].cellCount).toEqual(50);
expect(result.summary.included.xudtAssets[xudtTypeArgs].utxoCount).toEqual(50);

expect(result.summary.excluded.assets).toHaveProperty(xudtTypeArgs);
expect(result.summary.excluded.assets[xudtTypeArgs].cellCount).toEqual(41);
expect(result.summary.excluded.assets[xudtTypeArgs].utxoCount).toEqual(1);
expect(result.summary.excluded.xudtAssets).toHaveProperty(xudtTypeArgs);
expect(result.summary.excluded.xudtAssets[xudtTypeArgs].cellCount).toEqual(41);
expect(result.summary.excluded.xudtAssets[xudtTypeArgs].utxoCount).toEqual(1);

expect(result.transactions).toHaveLength(2);
expect(result).toMatchSnapshot();
Expand Down
Loading

1 comment on commit 2d1c834

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New snapshot version of the rgbpp-sdk packages have been released:

Name Version
@rgbpp-sdk/btc 0.0.0-snap-20240813014620
@rgbpp-sdk/ckb 0.0.0-snap-20240813014620
rgbpp 0.0.0-snap-20240813014620
@rgbpp-sdk/service 0.0.0-snap-20240813014620

Please sign in to comment.