Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"license": "ISC",
"homepage": "https://unicitynetwork.github.io/state-transition-sdk/",
"dependencies": {
"@unicitylabs/commons": "2.4.0-rc.d7fa010"
"@unicitylabs/commons": "2.4.0-rc.24d6a7c"
},
"devDependencies": {
"@babel/preset-env": "7.27.2",
Expand Down
4 changes: 2 additions & 2 deletions src/StateTransitionClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export class StateTransitionClient {
{ requestId, transactionData }: Commitment<T>,
inclusionProof: InclusionProof,
): Promise<Transaction<T>> {
const status = await inclusionProof.verify(requestId.toBigInt());
const status = await inclusionProof.verify(requestId);
if (status != InclusionProofVerificationStatus.OK) {
throw new Error('Inclusion proof verification failed.');
}
Expand Down Expand Up @@ -180,7 +180,7 @@ export class StateTransitionClient {
const requestId = await RequestId.create(publicKey, token.state.hash);
const inclusionProof = await this.client.getInclusionProof(requestId);
// TODO: Check ownership?
return inclusionProof.verify(requestId.toBigInt());
return inclusionProof.verify(requestId);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/predicate/DefaultPredicate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ export abstract class DefaultPredicate implements IPredicate {

// Verify inclusion proof path.
const requestId = await RequestId.create(this.publicKey, transaction.data.sourceState.hash);
const status = await transaction.inclusionProof.verify(requestId.toBigInt());
const status = await transaction.inclusionProof.verify(requestId);
return status === InclusionProofVerificationStatus.OK;
}

Expand Down
4 changes: 2 additions & 2 deletions src/token/TokenFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export class TokenFactory {
return false;
}

const coinPathResult = await proof.coinTreePath.verify(transaction.data.tokenId.toBigInt());
const coinPathResult = await proof.coinTreePath.verify(transaction.data.tokenId.toBitString().toBigInt());
if (!coinPathResult.result) {
return false;
}
Expand All @@ -139,7 +139,7 @@ export class TokenFactory {

// Verify inclusion proof path.
const requestId = await RequestId.create(signingService.publicKey, transaction.data.sourceState.hash);
const status = await transaction.inclusionProof.verify(requestId.toBigInt());
const status = await transaction.inclusionProof.verify(requestId);
return status === InclusionProofVerificationStatus.OK;
}
}
7 changes: 4 additions & 3 deletions src/token/TokenId.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { CborEncoder } from '@unicitylabs/commons/lib/cbor/CborEncoder.js';
import { BitString } from '@unicitylabs/commons/lib/util/BitString.js';
import { HexConverter } from '@unicitylabs/commons/lib/util/HexConverter.js';

/**
Expand Down Expand Up @@ -37,9 +38,9 @@ export class TokenId {
}

/**
* Converts the TokenId to a BigInt representation.
* Converts the TokenId to a bitstring representation.
*/
public toBigInt(): bigint {
return BigInt(`0x01${HexConverter.encode(this.toCBOR())}`);
public toBitString(): BitString {
return new BitString(this.toCBOR());
}
}
10 changes: 6 additions & 4 deletions src/token/fungible/CoinId.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { CborDecoder } from '@unicitylabs/commons/lib/cbor/CborDecoder.js';
import { CborEncoder } from '@unicitylabs/commons/lib/cbor/CborEncoder.js';
import { BigintConverter } from '@unicitylabs/commons/lib/util/BigintConverter.js';
import { BitString } from '@unicitylabs/commons/lib/util/BitString.js';
import { HexConverter } from '@unicitylabs/commons/lib/util/HexConverter.js';

/** Identifier for a fungible coin type. */
Expand Down Expand Up @@ -32,7 +34,7 @@ export class CoinId {
* @param value bigint represantation of coin id
*/
public static fromBigInt(value: bigint): CoinId {
Comment thread
MastaP marked this conversation as resolved.
Outdated
return CoinId.fromCBOR(HexConverter.decode(value.toString(16).slice(1)));
return CoinId.fromCBOR(BigintConverter.encode(value).slice(1));
}

/** Hex string representation. */
Expand All @@ -46,9 +48,9 @@ export class CoinId {
}

/**
* Converts the CoinId to a BigInt representation.
* Converts the CoinId to a bitstring representation.
*/
public toBigInt(): bigint {
return BigInt(`0x01${HexConverter.encode(this.toCBOR())}`);
public toBitString(): BitString {
return new BitString(this.toCBOR());
}
}
37 changes: 16 additions & 21 deletions src/token/fungible/TokenCoinData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ export class TokenCoinData implements ISerializable {
private readonly _coins: Map<bigint, bigint>;

/**
* @param coins Array of coin id and balance pairs
* @param coins Array of coin id serialized to bigint and balance pairs
*/
public constructor(coins: [bigint, bigint][]) {
private constructor(coins: [bigint, bigint][]) {
this._coins = new Map(coins);
}

Expand All @@ -31,8 +31,12 @@ export class TokenCoinData implements ISerializable {
return new Map(Array.from(this._coins.entries()).map(([key, value]) => [CoinId.fromBigInt(key), value]));
}

/**
* Create a new coin data object from an array of coin id and balance pairs.
* @param coins Array of tuples of CoinId and bigint.
*/
public static create(coins: [CoinId, bigint][]): TokenCoinData {
return new TokenCoinData(coins.map(([key, value]) => [key.toBigInt(), value]));
return new TokenCoinData(coins.map(([key, value]) => [key.toBitString().toBigInt(), value]));
}

/** Create a coin data object from CBOR. */
Expand All @@ -52,37 +56,28 @@ export class TokenCoinData implements ISerializable {

/** Parse from a JSON representation. */
public static fromJSON(data: unknown): TokenCoinData {
if (!Array.isArray(data)) {
if (
!Array.isArray(data) ||
!data.every(
(value) =>
Array.isArray(value) && value.length === 2 && typeof value[0] === 'string' && typeof value[1] === 'string',
)
) {
throw new Error('Invalid coin data JSON format');
}

const coins: [bigint, bigint][] = [];

// Helper function to safely parse values that might have been corrupted by JSON.stringify()
const parseValue = (v: unknown): bigint => {
if (typeof v === 'bigint') return v;
if (typeof v === 'string' || typeof v === 'number') return BigInt(v);
if (v === null) {
throw new Error(`Cannot convert null to BigInt. This indicates a JSON serialization issue with BigInt values.`);
}
if (typeof v === 'object') {
throw new Error(
`Cannot convert object to BigInt. This indicates a JSON serialization issue with BigInt values. Received: ${JSON.stringify(v)}`,
);
}
throw new Error(`Unsupported type for BigInt conversion: ${typeof v}. Expected string, number, or bigint.`);
};

for (const [key, value] of data) {
coins.push([parseValue(key), parseValue(value)]);
coins.push([BigInt(key), BigInt(value)]);
}

return new TokenCoinData(coins);
}

/** Get the balance of a specific coin. */
public get(coinId: CoinId): bigint | undefined {
return this._coins.get(coinId.toBigInt());
return this._coins.get(coinId.toBitString().toBigInt());
}

/** Get the balance of a coin by its internal map key. */
Expand Down
27 changes: 0 additions & 27 deletions src/transaction/OfflineTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { TokenJsonDeserializer } from '../serializer/token/TokenJsonDeserializer
import { ITokenJson, Token } from '../token/Token.js';
import { TokenFactory } from '../token/TokenFactory.js';
import { TokenState } from '../token/TokenState.js';
import { JsonUtils } from '../utils/JsonUtils.js';

/** JSON representation of an {@link OfflineTransaction}. */
export interface IOfflineTransactionJson {
Expand Down Expand Up @@ -80,18 +79,6 @@ export class OfflineTransaction implements ISerializable {
return new OfflineTransaction(offlineCommitment, token);
}

/**
* Create OfflineTransaction from JSON string.
* This method can handle JSON strings that were created with toJSONString().
*
* @param jsonString JSON string representation
* @returns Promise<OfflineTransaction>
*/
public static fromJSONString(jsonString: string): Promise<OfflineTransaction> {
const parsed = JsonUtils.parse(jsonString);
return OfflineTransaction.fromJSON(parsed);
}

/**
* Type guard to check if data is valid OfflineTransaction JSON.
* @param data Data to validate
Expand Down Expand Up @@ -130,18 +117,4 @@ export class OfflineTransaction implements ISerializable {
token: this.token.toJSON(),
};
}

/**
* Serialize to JSON string with BigInt support.
* This method handles potential BigInt values that might exist in the object graph
* and converts them to strings to prevent JSON serialization errors.
*
* Use this method when you need to serialize for actual transfer (e.g., NFC, file, etc.).
*
* @param space Optional spacing for formatting
* @returns JSON string with BigInt values safely converted
*/
public toJSONString(space?: string | number): string {
return JsonUtils.safeStringify(this, space);
}
}
12 changes: 6 additions & 6 deletions src/transaction/TokenSplitBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class SplitToken {
throw new Error('Amount must be greater than zero');
}

this._coins.set(coinId.toBigInt(), amount);
this._coins.set(coinId.toBitString().toBigInt(), amount);
return this;
}
}
Expand Down Expand Up @@ -80,7 +80,7 @@ class TokenSplitData {

const transactions: MintTransactionData<SplitMintReason>[] = [];
for (const [tokenId, splitToken] of this.tokens.entries()) {
const coinData: [bigint, bigint][] = [];
const coinData: [CoinId, bigint][] = [];
const proofs = new Map<bigint, SplitMintReasonProof>();
for (const [coinId, amount] of splitToken.coins.entries()) {
proofs.set(
Expand All @@ -90,15 +90,15 @@ class TokenSplitData {
this._coinTrees.get(coinId)?.getPath(tokenId) as MerkleSumTreePath,
),
);
coinData.push([coinId, amount]);
coinData.push([CoinId.fromBigInt(coinId), amount]);
}

transactions.push(
await MintTransactionData.create(
splitToken.tokenId,
splitToken.tokenType,
splitToken.data,
new TokenCoinData(coinData),
TokenCoinData.create(coinData),
splitToken.recipient,
splitToken.salt,
splitToken.dataHash,
Expand All @@ -122,12 +122,12 @@ export class TokenSplitBuilder {
dataHash: DataHash,
salt: Uint8Array,
): SplitToken {
if (this.tokens.has(id.toBigInt())) {
if (this.tokens.has(id.toBitString().toBigInt())) {
throw new Error('Token already exists in split request');
}

const builder = new SplitToken(id, type, data, recipient, dataHash, salt);
this.tokens.set(id.toBigInt(), builder);
this.tokens.set(id.toBitString().toBigInt(), builder);
return builder;
}

Expand Down
2 changes: 1 addition & 1 deletion src/utils/InclusionProofUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export async function waitInclusionProof(
while (true) {
try {
const inclusionProof = await client.getInclusionProof(commitment);
if ((await inclusionProof.verify(commitment.requestId.toBigInt())) === InclusionProofVerificationStatus.OK) {
if ((await inclusionProof.verify(commitment.requestId)) === InclusionProofVerificationStatus.OK) {
return inclusionProof;
}
} catch (err) {
Expand Down
56 changes: 0 additions & 56 deletions src/utils/JsonUtils.ts

This file was deleted.

Loading
Loading