@ckb-ccc/core 1.9.1 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/dist/ckb/index.d.ts +1 -0
- package/dist/ckb/index.d.ts.map +1 -1
- package/dist/ckb/index.js +1 -0
- package/dist/ckb/script.d.ts +12 -0
- package/dist/ckb/script.d.ts.map +1 -1
- package/dist/ckb/script.js +17 -0
- package/dist/ckb/transaction.d.ts +147 -14
- package/dist/ckb/transaction.d.ts.map +1 -1
- package/dist/ckb/transaction.js +165 -28
- package/dist/ckb/transactionErrors.d.ts +15 -0
- package/dist/ckb/transactionErrors.d.ts.map +1 -0
- package/dist/ckb/transactionErrors.js +21 -0
- package/dist/client/cache/cache.d.ts +7 -0
- package/dist/client/cache/cache.d.ts.map +1 -1
- package/dist/client/cache/cache.js +11 -0
- package/dist/client/cache/memory.advanced.d.ts +36 -3
- package/dist/client/cache/memory.advanced.d.ts.map +1 -1
- package/dist/client/cache/memory.advanced.js +53 -25
- package/dist/client/cache/memory.d.ts +10 -1
- package/dist/client/cache/memory.d.ts.map +1 -1
- package/dist/client/cache/memory.js +13 -2
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +6 -9
- package/dist/client/clientPublicMainnet.advanced.d.ts.map +1 -1
- package/dist/client/clientPublicMainnet.advanced.js +60 -0
- package/dist/client/clientPublicTestnet.advanced.d.ts +23 -0
- package/dist/client/clientPublicTestnet.advanced.d.ts.map +1 -1
- package/dist/client/clientPublicTestnet.advanced.js +144 -0
- package/dist/client/clientTypes.advanced.d.ts +0 -1
- package/dist/client/clientTypes.advanced.d.ts.map +1 -1
- package/dist/client/clientTypes.advanced.js +0 -1
- package/dist/client/knownScript.d.ts +3 -1
- package/dist/client/knownScript.d.ts.map +1 -1
- package/dist/client/knownScript.js +4 -0
- package/dist.commonjs/ckb/index.d.ts +1 -0
- package/dist.commonjs/ckb/index.d.ts.map +1 -1
- package/dist.commonjs/ckb/index.js +1 -0
- package/dist.commonjs/ckb/script.d.ts +12 -0
- package/dist.commonjs/ckb/script.d.ts.map +1 -1
- package/dist.commonjs/ckb/script.js +17 -0
- package/dist.commonjs/ckb/transaction.d.ts +147 -14
- package/dist.commonjs/ckb/transaction.d.ts.map +1 -1
- package/dist.commonjs/ckb/transaction.js +164 -27
- package/dist.commonjs/ckb/transactionErrors.d.ts +15 -0
- package/dist.commonjs/ckb/transactionErrors.d.ts.map +1 -0
- package/dist.commonjs/ckb/transactionErrors.js +26 -0
- package/dist.commonjs/client/cache/cache.d.ts +7 -0
- package/dist.commonjs/client/cache/cache.d.ts.map +1 -1
- package/dist.commonjs/client/cache/cache.js +11 -0
- package/dist.commonjs/client/cache/memory.advanced.d.ts +36 -3
- package/dist.commonjs/client/cache/memory.advanced.d.ts.map +1 -1
- package/dist.commonjs/client/cache/memory.advanced.js +54 -26
- package/dist.commonjs/client/cache/memory.d.ts +10 -1
- package/dist.commonjs/client/cache/memory.d.ts.map +1 -1
- package/dist.commonjs/client/cache/memory.js +12 -1
- package/dist.commonjs/client/client.d.ts.map +1 -1
- package/dist.commonjs/client/client.js +5 -8
- package/dist.commonjs/client/clientPublicMainnet.advanced.d.ts.map +1 -1
- package/dist.commonjs/client/clientPublicMainnet.advanced.js +60 -0
- package/dist.commonjs/client/clientPublicTestnet.advanced.d.ts +23 -0
- package/dist.commonjs/client/clientPublicTestnet.advanced.d.ts.map +1 -1
- package/dist.commonjs/client/clientPublicTestnet.advanced.js +145 -1
- package/dist.commonjs/client/clientTypes.advanced.d.ts +0 -1
- package/dist.commonjs/client/clientTypes.advanced.d.ts.map +1 -1
- package/dist.commonjs/client/clientTypes.advanced.js +1 -2
- package/dist.commonjs/client/knownScript.d.ts +3 -1
- package/dist.commonjs/client/knownScript.d.ts.map +1 -1
- package/dist.commonjs/client/knownScript.js +4 -0
- package/package.json +1 -1
- package/src/ckb/index.ts +1 -0
- package/src/ckb/script.ts +20 -0
- package/src/ckb/transaction.ts +210 -33
- package/src/ckb/transactionErrors.ts +36 -0
- package/src/client/cache/cache.ts +14 -1
- package/src/client/cache/memory.advanced.ts +57 -30
- package/src/client/cache/memory.ts +18 -1
- package/src/client/client.ts +5 -10
- package/src/client/clientPublicMainnet.advanced.ts +68 -0
- package/src/client/clientPublicTestnet.advanced.ts +163 -0
- package/src/client/clientTypes.advanced.ts +0 -1
- package/src/client/knownScript.ts +5 -0
package/src/ckb/transaction.ts
CHANGED
|
@@ -7,11 +7,7 @@ import {
|
|
|
7
7
|
type ClientBlockHeaderLike,
|
|
8
8
|
} from "../client/index.js";
|
|
9
9
|
import { KnownScript } from "../client/knownScript.js";
|
|
10
|
-
import {
|
|
11
|
-
Zero,
|
|
12
|
-
fixedPointFrom,
|
|
13
|
-
fixedPointToString,
|
|
14
|
-
} from "../fixedPoint/index.js";
|
|
10
|
+
import { Zero, fixedPointFrom } from "../fixedPoint/index.js";
|
|
15
11
|
import { Hasher, HasherCkb, hashCkb } from "../hasher/index.js";
|
|
16
12
|
import { Hex, HexLike, hexFrom } from "../hex/index.js";
|
|
17
13
|
import { mol } from "../molecule/index.js";
|
|
@@ -27,6 +23,10 @@ import type { Signer } from "../signer/index.js";
|
|
|
27
23
|
import { apply, reduceAsync } from "../utils/index.js";
|
|
28
24
|
import { Script, ScriptLike, ScriptOpt } from "./script.js";
|
|
29
25
|
import { DEP_TYPE_TO_NUM, NUM_TO_DEP_TYPE } from "./transaction.advanced.js";
|
|
26
|
+
import {
|
|
27
|
+
ErrorTransactionInsufficientCapacity,
|
|
28
|
+
ErrorTransactionInsufficientCoin,
|
|
29
|
+
} from "./transactionErrors.js";
|
|
30
30
|
import type { LumosTransactionSkeletonType } from "./transactionLumos.js";
|
|
31
31
|
|
|
32
32
|
export const DepTypeCodec: mol.Codec<DepTypeLike, DepType> = mol.Codec.from({
|
|
@@ -162,6 +162,36 @@ export class OutPoint extends mol.Entity.Base<OutPointLike, OutPoint>() {
|
|
|
162
162
|
}
|
|
163
163
|
return new OutPoint(hexFrom(outPoint.txHash), numFrom(outPoint.index));
|
|
164
164
|
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Clone a OutPoint.
|
|
168
|
+
*
|
|
169
|
+
* @returns A cloned OutPoint instance.
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```typescript
|
|
173
|
+
* const outPoint1 = outPoint0.clone();
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
clone(): OutPoint {
|
|
177
|
+
return new OutPoint(this.txHash, this.index);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Check if the OutPoint is equal to another OutPoint.
|
|
182
|
+
* @public
|
|
183
|
+
* @param other - The other OutPoint to compare with
|
|
184
|
+
* @returns True if the OutPoints are equal, false otherwise
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* ```typescript
|
|
188
|
+
* const isEqual = outPoint0.eq(outPoint1);
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
eq(other: OutPointLike): boolean {
|
|
192
|
+
other = OutPoint.from(other);
|
|
193
|
+
return this.txHash === other.txHash && this.index === other.index;
|
|
194
|
+
}
|
|
165
195
|
}
|
|
166
196
|
|
|
167
197
|
/**
|
|
@@ -229,6 +259,20 @@ export class CellOutput extends mol.Entity.Base<CellOutputLike, CellOutput>() {
|
|
|
229
259
|
apply(Script.from, cellOutput.type),
|
|
230
260
|
);
|
|
231
261
|
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Clone a CellOutput.
|
|
265
|
+
*
|
|
266
|
+
* @returns A cloned CellOutput instance.
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* ```typescript
|
|
270
|
+
* const cellOutput1 = cellOutput0.clone();
|
|
271
|
+
* ```
|
|
272
|
+
*/
|
|
273
|
+
clone(): CellOutput {
|
|
274
|
+
return new CellOutput(this.capacity, this.lock.clone(), this.type?.clone());
|
|
275
|
+
}
|
|
232
276
|
}
|
|
233
277
|
export const CellOutputVec = mol.vector(CellOutput);
|
|
234
278
|
|
|
@@ -700,12 +744,23 @@ export class CellInput extends mol.Entity.Base<CellInputLike, CellInput>() {
|
|
|
700
744
|
return (await this.getCell(client)).getDaoProfit(client);
|
|
701
745
|
}
|
|
702
746
|
|
|
747
|
+
/**
|
|
748
|
+
* Clone a CellInput.
|
|
749
|
+
*
|
|
750
|
+
* @returns A cloned CellInput instance.
|
|
751
|
+
*
|
|
752
|
+
* @example
|
|
753
|
+
* ```typescript
|
|
754
|
+
* const cellInput1 = cellInput0.clone();
|
|
755
|
+
* ```
|
|
756
|
+
*/
|
|
703
757
|
clone(): CellInput {
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
758
|
+
return new CellInput(
|
|
759
|
+
this.previousOutput.clone(),
|
|
760
|
+
this.since,
|
|
761
|
+
this.cellOutput?.clone(),
|
|
762
|
+
this.outputData,
|
|
763
|
+
);
|
|
709
764
|
}
|
|
710
765
|
}
|
|
711
766
|
export const CellInputVec = mol.vector(CellInput);
|
|
@@ -741,21 +796,6 @@ export class CellDep extends mol.Entity.Base<CellDepLike, CellDep>() {
|
|
|
741
796
|
super();
|
|
742
797
|
}
|
|
743
798
|
|
|
744
|
-
/**
|
|
745
|
-
* Clone a CellDep.
|
|
746
|
-
*
|
|
747
|
-
* @returns A cloned CellDep instance.
|
|
748
|
-
*
|
|
749
|
-
* @example
|
|
750
|
-
* ```typescript
|
|
751
|
-
* const cellDep1 = cellDep0.clone();
|
|
752
|
-
* ```
|
|
753
|
-
*/
|
|
754
|
-
|
|
755
|
-
clone(): CellDep {
|
|
756
|
-
return new CellDep(this.outPoint.clone(), this.depType);
|
|
757
|
-
}
|
|
758
|
-
|
|
759
799
|
/**
|
|
760
800
|
* Creates a CellDep instance from a CellDepLike object.
|
|
761
801
|
*
|
|
@@ -781,6 +821,20 @@ export class CellDep extends mol.Entity.Base<CellDepLike, CellDep>() {
|
|
|
781
821
|
depTypeFrom(cellDep.depType),
|
|
782
822
|
);
|
|
783
823
|
}
|
|
824
|
+
|
|
825
|
+
/**
|
|
826
|
+
* Clone a CellDep.
|
|
827
|
+
*
|
|
828
|
+
* @returns A cloned CellDep instance.
|
|
829
|
+
*
|
|
830
|
+
* @example
|
|
831
|
+
* ```typescript
|
|
832
|
+
* const cellDep1 = cellDep0.clone();
|
|
833
|
+
* ```
|
|
834
|
+
*/
|
|
835
|
+
clone(): CellDep {
|
|
836
|
+
return new CellDep(this.outPoint.clone(), this.depType);
|
|
837
|
+
}
|
|
784
838
|
}
|
|
785
839
|
export const CellDepVec = mol.vector(CellDep);
|
|
786
840
|
|
|
@@ -964,6 +1018,55 @@ export class Transaction extends mol.Entity.Base<
|
|
|
964
1018
|
this.witnesses = tx.witnesses;
|
|
965
1019
|
}
|
|
966
1020
|
|
|
1021
|
+
/**
|
|
1022
|
+
* Creates a deep copy of the transaction.
|
|
1023
|
+
* This method creates a new Transaction instance with all nested objects cloned,
|
|
1024
|
+
* ensuring that modifications to the cloned transaction do not affect the original.
|
|
1025
|
+
*
|
|
1026
|
+
* @returns A new Transaction instance that is a deep copy of the current transaction.
|
|
1027
|
+
*
|
|
1028
|
+
* @example
|
|
1029
|
+
* ```typescript
|
|
1030
|
+
* const originalTx = Transaction.from({
|
|
1031
|
+
* version: 0,
|
|
1032
|
+
* inputs: [{ previousOutput: { txHash: "0x...", index: 0 } }],
|
|
1033
|
+
* outputs: [{ capacity: 1000n, lock: lockScript }],
|
|
1034
|
+
* outputsData: ["0x"],
|
|
1035
|
+
* witnesses: ["0x"]
|
|
1036
|
+
* });
|
|
1037
|
+
*
|
|
1038
|
+
* const clonedTx = originalTx.clone();
|
|
1039
|
+
*
|
|
1040
|
+
* // Modifications to clonedTx won't affect originalTx
|
|
1041
|
+
* clonedTx.addOutput({ capacity: 2000n, lock: anotherLockScript });
|
|
1042
|
+
* console.log(originalTx.outputs.length); // Still 1
|
|
1043
|
+
* console.log(clonedTx.outputs.length); // Now 2
|
|
1044
|
+
* ```
|
|
1045
|
+
*
|
|
1046
|
+
* @remarks
|
|
1047
|
+
* The clone operation performs deep copying for:
|
|
1048
|
+
* - Cell dependencies (cellDeps) - each CellDep is cloned
|
|
1049
|
+
* - Inputs - each CellInput is cloned
|
|
1050
|
+
* - Outputs - each CellOutput is cloned
|
|
1051
|
+
*
|
|
1052
|
+
* The following are shallow copied (references to immutable data):
|
|
1053
|
+
* - Header dependencies (headerDeps) - Hex strings are immutable
|
|
1054
|
+
* - Output data (outputsData) - Hex strings are immutable
|
|
1055
|
+
* - Witnesses - Hex strings are immutable
|
|
1056
|
+
* - Version - bigint is immutable
|
|
1057
|
+
*/
|
|
1058
|
+
clone(): Transaction {
|
|
1059
|
+
return new Transaction(
|
|
1060
|
+
this.version,
|
|
1061
|
+
this.cellDeps.map((c) => c.clone()),
|
|
1062
|
+
this.headerDeps.map((h) => h),
|
|
1063
|
+
this.inputs.map((i) => i.clone()),
|
|
1064
|
+
this.outputs.map((o) => o.clone()),
|
|
1065
|
+
this.outputsData.map((o) => o),
|
|
1066
|
+
this.witnesses.map((w) => w),
|
|
1067
|
+
);
|
|
1068
|
+
}
|
|
1069
|
+
|
|
967
1070
|
/**
|
|
968
1071
|
* Creates a Transaction instance from a TransactionLike object.
|
|
969
1072
|
*
|
|
@@ -1697,8 +1800,8 @@ export class Transaction extends mol.Entity.Base<
|
|
|
1697
1800
|
return addedCount;
|
|
1698
1801
|
}
|
|
1699
1802
|
|
|
1700
|
-
throw new
|
|
1701
|
-
|
|
1803
|
+
throw new ErrorTransactionInsufficientCapacity(
|
|
1804
|
+
expectedCapacity - accumulated,
|
|
1702
1805
|
);
|
|
1703
1806
|
}
|
|
1704
1807
|
|
|
@@ -1782,8 +1885,9 @@ export class Transaction extends mol.Entity.Base<
|
|
|
1782
1885
|
return addedCount;
|
|
1783
1886
|
}
|
|
1784
1887
|
|
|
1785
|
-
throw new
|
|
1786
|
-
|
|
1888
|
+
throw new ErrorTransactionInsufficientCoin(
|
|
1889
|
+
expectedBalance - accumulated,
|
|
1890
|
+
type,
|
|
1787
1891
|
);
|
|
1788
1892
|
}
|
|
1789
1893
|
|
|
@@ -1836,12 +1940,54 @@ export class Transaction extends mol.Entity.Base<
|
|
|
1836
1940
|
return (numFrom(txSize) * numFrom(feeRate) + numFrom(999)) / numFrom(1000);
|
|
1837
1941
|
}
|
|
1838
1942
|
|
|
1943
|
+
/**
|
|
1944
|
+
* Completes the transaction fee by adding inputs and handling change outputs.
|
|
1945
|
+
* This method automatically calculates the required fee based on the transaction size and fee rate,
|
|
1946
|
+
* adds necessary inputs to cover the fee, and handles change outputs through the provided change function.
|
|
1947
|
+
*
|
|
1948
|
+
* @param from - The signer to complete inputs from and prepare the transaction.
|
|
1949
|
+
* @param change - A function that handles change capacity. It receives the transaction and excess capacity,
|
|
1950
|
+
* and should return the additional capacity needed (0 if change is handled successfully,
|
|
1951
|
+
* positive number if more capacity is needed for change cell creation).
|
|
1952
|
+
* @param expectedFeeRate - The expected fee rate in shannons per 1000 bytes. If not provided,
|
|
1953
|
+
* it will be fetched from the client.
|
|
1954
|
+
* @param filter - Optional filter for selecting cells when adding inputs.
|
|
1955
|
+
* @param options - Optional configuration object.
|
|
1956
|
+
* @param options.feeRateBlockRange - Block range for fee rate calculation when expectedFeeRate is not provided.
|
|
1957
|
+
* @param options.maxFeeRate - Maximum allowed fee rate.
|
|
1958
|
+
* @param options.shouldAddInputs - Whether to add inputs automatically. Defaults to true.
|
|
1959
|
+
* @returns A promise that resolves to a tuple containing:
|
|
1960
|
+
* - The number of inputs added during the process
|
|
1961
|
+
* - A boolean indicating whether change outputs were created (true) or fee was paid without change (false)
|
|
1962
|
+
*
|
|
1963
|
+
* @throws {ErrorTransactionInsufficientCapacity} When there's not enough capacity to cover the fee.
|
|
1964
|
+
* @throws {Error} When the change function doesn't properly handle the available capacity.
|
|
1965
|
+
*
|
|
1966
|
+
* @example
|
|
1967
|
+
* ```typescript
|
|
1968
|
+
* const [addedInputs, hasChange] = await tx.completeFee(
|
|
1969
|
+
* signer,
|
|
1970
|
+
* (tx, capacity) => {
|
|
1971
|
+
* if (capacity >= 61_00000000n) { // Minimum for a change cell
|
|
1972
|
+
* tx.addOutput({ capacity, lock: changeScript });
|
|
1973
|
+
* return 0;
|
|
1974
|
+
* }
|
|
1975
|
+
* return 61_00000000n; // Need more capacity for change cell
|
|
1976
|
+
* },
|
|
1977
|
+
* 1000n // 1000 shannons per 1000 bytes
|
|
1978
|
+
* );
|
|
1979
|
+
* ```
|
|
1980
|
+
*/
|
|
1839
1981
|
async completeFee(
|
|
1840
1982
|
from: Signer,
|
|
1841
1983
|
change: (tx: Transaction, capacity: Num) => Promise<NumLike> | NumLike,
|
|
1842
1984
|
expectedFeeRate?: NumLike,
|
|
1843
1985
|
filter?: ClientCollectableSearchKeyFilterLike,
|
|
1844
|
-
options?: {
|
|
1986
|
+
options?: {
|
|
1987
|
+
feeRateBlockRange?: NumLike;
|
|
1988
|
+
maxFeeRate?: NumLike;
|
|
1989
|
+
shouldAddInputs?: boolean;
|
|
1990
|
+
},
|
|
1845
1991
|
): Promise<[number, boolean]> {
|
|
1846
1992
|
const feeRate =
|
|
1847
1993
|
expectedFeeRate ??
|
|
@@ -1856,6 +2002,15 @@ export class Transaction extends mol.Entity.Base<
|
|
|
1856
2002
|
while (true) {
|
|
1857
2003
|
const tx = this.clone();
|
|
1858
2004
|
const collected = await (async () => {
|
|
2005
|
+
if (!(options?.shouldAddInputs ?? true)) {
|
|
2006
|
+
const fee =
|
|
2007
|
+
(await tx.getFee(from.client)) - leastFee - leastExtraCapacity;
|
|
2008
|
+
if (fee < Zero) {
|
|
2009
|
+
throw new ErrorTransactionInsufficientCapacity(-fee);
|
|
2010
|
+
}
|
|
2011
|
+
return 0;
|
|
2012
|
+
}
|
|
2013
|
+
|
|
1859
2014
|
try {
|
|
1860
2015
|
return await tx.completeInputsByCapacity(
|
|
1861
2016
|
from,
|
|
@@ -1863,8 +2018,13 @@ export class Transaction extends mol.Entity.Base<
|
|
|
1863
2018
|
filter,
|
|
1864
2019
|
);
|
|
1865
2020
|
} catch (err) {
|
|
1866
|
-
if (
|
|
1867
|
-
|
|
2021
|
+
if (
|
|
2022
|
+
err instanceof ErrorTransactionInsufficientCapacity &&
|
|
2023
|
+
leastExtraCapacity !== Zero
|
|
2024
|
+
) {
|
|
2025
|
+
throw new ErrorTransactionInsufficientCapacity(err.amount, {
|
|
2026
|
+
isForChange: true,
|
|
2027
|
+
});
|
|
1868
2028
|
}
|
|
1869
2029
|
|
|
1870
2030
|
throw err;
|
|
@@ -1918,6 +2078,11 @@ export class Transaction extends mol.Entity.Base<
|
|
|
1918
2078
|
change: ScriptLike,
|
|
1919
2079
|
feeRate?: NumLike,
|
|
1920
2080
|
filter?: ClientCollectableSearchKeyFilterLike,
|
|
2081
|
+
options?: {
|
|
2082
|
+
feeRateBlockRange?: NumLike;
|
|
2083
|
+
maxFeeRate?: NumLike;
|
|
2084
|
+
shouldAddInputs?: boolean;
|
|
2085
|
+
},
|
|
1921
2086
|
): Promise<[number, boolean]> {
|
|
1922
2087
|
const script = Script.from(change);
|
|
1923
2088
|
|
|
@@ -1935,6 +2100,7 @@ export class Transaction extends mol.Entity.Base<
|
|
|
1935
2100
|
},
|
|
1936
2101
|
feeRate,
|
|
1937
2102
|
filter,
|
|
2103
|
+
options,
|
|
1938
2104
|
);
|
|
1939
2105
|
}
|
|
1940
2106
|
|
|
@@ -1942,10 +2108,15 @@ export class Transaction extends mol.Entity.Base<
|
|
|
1942
2108
|
from: Signer,
|
|
1943
2109
|
feeRate?: NumLike,
|
|
1944
2110
|
filter?: ClientCollectableSearchKeyFilterLike,
|
|
2111
|
+
options?: {
|
|
2112
|
+
feeRateBlockRange?: NumLike;
|
|
2113
|
+
maxFeeRate?: NumLike;
|
|
2114
|
+
shouldAddInputs?: boolean;
|
|
2115
|
+
},
|
|
1945
2116
|
): Promise<[number, boolean]> {
|
|
1946
2117
|
const { script } = await from.getRecommendedAddressObj();
|
|
1947
2118
|
|
|
1948
|
-
return this.completeFeeChangeToLock(from, script, feeRate, filter);
|
|
2119
|
+
return this.completeFeeChangeToLock(from, script, feeRate, filter, options);
|
|
1949
2120
|
}
|
|
1950
2121
|
|
|
1951
2122
|
completeFeeChangeToOutput(
|
|
@@ -1953,6 +2124,11 @@ export class Transaction extends mol.Entity.Base<
|
|
|
1953
2124
|
index: NumLike,
|
|
1954
2125
|
feeRate?: NumLike,
|
|
1955
2126
|
filter?: ClientCollectableSearchKeyFilterLike,
|
|
2127
|
+
options?: {
|
|
2128
|
+
feeRateBlockRange?: NumLike;
|
|
2129
|
+
maxFeeRate?: NumLike;
|
|
2130
|
+
shouldAddInputs?: boolean;
|
|
2131
|
+
},
|
|
1956
2132
|
): Promise<[number, boolean]> {
|
|
1957
2133
|
const change = Number(numFrom(index));
|
|
1958
2134
|
if (!this.outputs[change]) {
|
|
@@ -1966,6 +2142,7 @@ export class Transaction extends mol.Entity.Base<
|
|
|
1966
2142
|
},
|
|
1967
2143
|
feeRate,
|
|
1968
2144
|
filter,
|
|
2145
|
+
options,
|
|
1969
2146
|
);
|
|
1970
2147
|
}
|
|
1971
2148
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { fixedPointToString } from "../fixedPoint/index.js";
|
|
2
|
+
import { Num, numFrom, NumLike } from "../num/index.js";
|
|
3
|
+
import { Script, ScriptLike } from "./script.js";
|
|
4
|
+
|
|
5
|
+
export class ErrorTransactionInsufficientCapacity extends Error {
|
|
6
|
+
public readonly amount: Num;
|
|
7
|
+
public readonly isForChange: boolean;
|
|
8
|
+
|
|
9
|
+
constructor(
|
|
10
|
+
amountLike: NumLike,
|
|
11
|
+
reason?: {
|
|
12
|
+
isForChange?: boolean;
|
|
13
|
+
},
|
|
14
|
+
) {
|
|
15
|
+
const amount = numFrom(amountLike);
|
|
16
|
+
const isForChange = reason?.isForChange ?? false;
|
|
17
|
+
super(
|
|
18
|
+
`Insufficient CKB, need ${fixedPointToString(amount)} extra CKB${isForChange ? " for the change cell" : ""}`,
|
|
19
|
+
);
|
|
20
|
+
this.amount = amount;
|
|
21
|
+
this.isForChange = isForChange;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class ErrorTransactionInsufficientCoin extends Error {
|
|
26
|
+
public readonly amount: Num;
|
|
27
|
+
public readonly type: Script;
|
|
28
|
+
|
|
29
|
+
constructor(amountLike: NumLike, typeLike: ScriptLike) {
|
|
30
|
+
const amount = numFrom(amountLike);
|
|
31
|
+
const type = Script.from(typeLike);
|
|
32
|
+
super(`Insufficient coin, need ${amount} extra coin`);
|
|
33
|
+
this.amount = amount;
|
|
34
|
+
this.type = type;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
TransactionLike,
|
|
7
7
|
} from "../../ckb/index.js";
|
|
8
8
|
import { HexLike } from "../../hex/index.js";
|
|
9
|
-
import { NumLike } from "../../num/index.js";
|
|
9
|
+
import { numFrom, NumLike } from "../../num/index.js";
|
|
10
10
|
import { ClientCollectableSearchKeyLike } from "../clientTypes.advanced.js";
|
|
11
11
|
import {
|
|
12
12
|
ClientBlock,
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
ClientTransactionResponse,
|
|
17
17
|
ClientTransactionResponseLike,
|
|
18
18
|
} from "../clientTypes.js";
|
|
19
|
+
import { DEFAULT_CONFIRMED_BLOCK_TIME } from "./memory.advanced.js";
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* @public
|
|
@@ -185,4 +186,16 @@ export abstract class ClientCache {
|
|
|
185
186
|
async getBlockByNumber(_number: NumLike): Promise<ClientBlock | undefined> {
|
|
186
187
|
return;
|
|
187
188
|
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Checks if a block header is considered confirmed.
|
|
192
|
+
* The default implementation compares the header's timestamp against the current time
|
|
193
|
+
* and a configured confirmation time. Override this method for custom confirmation logic.
|
|
194
|
+
* @param header
|
|
195
|
+
*/
|
|
196
|
+
hasHeaderConfirmed(header: ClientBlockHeader): boolean {
|
|
197
|
+
return (
|
|
198
|
+
numFrom(Date.now()) - header.timestamp >= DEFAULT_CONFIRMED_BLOCK_TIME
|
|
199
|
+
);
|
|
200
|
+
}
|
|
188
201
|
}
|
|
@@ -8,6 +8,8 @@ import {
|
|
|
8
8
|
} from "../clientTypes.advanced.js";
|
|
9
9
|
import { ClientIndexerSearchKey } from "../clientTypes.js";
|
|
10
10
|
|
|
11
|
+
export const DEFAULT_CONFIRMED_BLOCK_TIME = numFrom(1000 * 10 * 50); // 50 blocks * 10s
|
|
12
|
+
|
|
11
13
|
// [isLive, Cell | OutPoint]
|
|
12
14
|
export type CellRecord =
|
|
13
15
|
| [
|
|
@@ -142,49 +144,74 @@ export function filterCell(
|
|
|
142
144
|
return true;
|
|
143
145
|
}
|
|
144
146
|
|
|
147
|
+
/**
|
|
148
|
+
* A Least Recently Used (LRU) cache implemented using a Map.
|
|
149
|
+
*
|
|
150
|
+
* This class extends the built-in Map to provide an LRU cache with a fixed capacity.
|
|
151
|
+
* When the cache is full, the least recently used entry is automatically evicted.
|
|
152
|
+
*
|
|
153
|
+
* @template K The type of the keys in the cache.
|
|
154
|
+
* @template V The type of the values in the cache.
|
|
155
|
+
*/
|
|
145
156
|
export class MapLru<K, V> extends Map<K, V> {
|
|
146
|
-
|
|
147
|
-
|
|
157
|
+
/**
|
|
158
|
+
* Constructs a new MapLru instance.
|
|
159
|
+
*
|
|
160
|
+
* @param capacity The maximum number of entries the cache can hold. Must be a positive integer.
|
|
161
|
+
* @throws {Error} If the capacity is not a positive integer.
|
|
162
|
+
*/
|
|
148
163
|
constructor(private readonly capacity: number) {
|
|
149
164
|
super();
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
get(key: K) {
|
|
153
|
-
const val = super.get(key);
|
|
154
|
-
if (val === undefined) {
|
|
155
|
-
return;
|
|
165
|
+
if (!Number.isInteger(capacity) || capacity < 1) {
|
|
166
|
+
throw new Error("Capacity must be a positive integer");
|
|
156
167
|
}
|
|
168
|
+
}
|
|
157
169
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
170
|
+
/**
|
|
171
|
+
* Retrieves a value from the cache.
|
|
172
|
+
*
|
|
173
|
+
* If the key is present in the cache, the value is moved to the most-recently-used position.
|
|
174
|
+
*
|
|
175
|
+
* @param key The key of the value to retrieve.
|
|
176
|
+
* @returns The value associated with the key, or undefined if the key is not present.
|
|
177
|
+
*/
|
|
178
|
+
override get(key: K): V | undefined {
|
|
179
|
+
// Check if the key exists. If not, return undefined.
|
|
180
|
+
if (!super.has(key)) {
|
|
181
|
+
return undefined;
|
|
166
182
|
}
|
|
167
183
|
|
|
168
|
-
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
set(key: K, value: V) {
|
|
172
|
-
this.get(key);
|
|
184
|
+
const value = super.get(key) as V;
|
|
173
185
|
|
|
186
|
+
// Move to most-recently-used position
|
|
187
|
+
super.delete(key);
|
|
174
188
|
super.set(key, value);
|
|
175
|
-
|
|
189
|
+
|
|
190
|
+
return value;
|
|
176
191
|
}
|
|
177
192
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
193
|
+
/**
|
|
194
|
+
* Inserts a new value into the cache, or updates an existing value.
|
|
195
|
+
*
|
|
196
|
+
* If the key is already present in the cache, it is first deleted so that the re-insertion
|
|
197
|
+
* moves it to the most-recently-used position.
|
|
198
|
+
* If the cache is over capacity after the insertion, the least recently used entry is evicted.
|
|
199
|
+
*
|
|
200
|
+
* @param key The key of the value to insert or update.
|
|
201
|
+
* @param value The value to associate with the key.
|
|
202
|
+
* @returns This MapLru instance.
|
|
203
|
+
*/
|
|
204
|
+
override set(key: K, value: V): this {
|
|
205
|
+
// Delete and re-insert to move key to the end (most-recently-used)
|
|
206
|
+
super.delete(key);
|
|
207
|
+
super.set(key, value);
|
|
182
208
|
|
|
183
|
-
|
|
184
|
-
if (
|
|
185
|
-
|
|
209
|
+
// Evict oldest if over capacity
|
|
210
|
+
if (super.size > this.capacity) {
|
|
211
|
+
const oldestKey = super.keys().next().value!;
|
|
212
|
+
super.delete(oldestKey);
|
|
186
213
|
}
|
|
187
214
|
|
|
188
|
-
return
|
|
215
|
+
return this;
|
|
189
216
|
}
|
|
190
217
|
}
|
|
@@ -11,7 +11,12 @@ import {
|
|
|
11
11
|
ClientTransactionResponseLike,
|
|
12
12
|
} from "../clientTypes.js";
|
|
13
13
|
import { ClientCache } from "./cache.js";
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
CellRecord,
|
|
16
|
+
DEFAULT_CONFIRMED_BLOCK_TIME,
|
|
17
|
+
filterCell,
|
|
18
|
+
MapLru,
|
|
19
|
+
} from "./memory.advanced.js";
|
|
15
20
|
|
|
16
21
|
export class ClientCacheMemory extends ClientCache {
|
|
17
22
|
/**
|
|
@@ -37,10 +42,18 @@ export class ClientCacheMemory extends ClientCache {
|
|
|
37
42
|
Pick<ClientBlock, "header"> | ClientBlock
|
|
38
43
|
>;
|
|
39
44
|
|
|
45
|
+
/**
|
|
46
|
+
* @param maxCells - Maximum number of cells to store in the cache. Defaults to 512.
|
|
47
|
+
* @param maxTxs - Maximum number of transactions to store in the cache. Defaults to 256.
|
|
48
|
+
* @param maxBlocks - Maximum number of blocks to store in the cache. Defaults to 128.
|
|
49
|
+
* @param confirmedBlockTime - Time in milliseconds after which a block is considered confirmed.
|
|
50
|
+
* Defaults to DEFAULT_CONFIRMED_BLOCK_TIME (50 blocks * 10s).
|
|
51
|
+
*/
|
|
40
52
|
constructor(
|
|
41
53
|
private readonly maxCells = 512,
|
|
42
54
|
private readonly maxTxs = 256,
|
|
43
55
|
private readonly maxBlocks = 128,
|
|
56
|
+
private readonly confirmedBlockTime = DEFAULT_CONFIRMED_BLOCK_TIME,
|
|
44
57
|
) {
|
|
45
58
|
super();
|
|
46
59
|
|
|
@@ -216,4 +229,8 @@ export class ClientCacheMemory extends ClientCache {
|
|
|
216
229
|
}
|
|
217
230
|
return this.getBlockByHash(hash);
|
|
218
231
|
}
|
|
232
|
+
|
|
233
|
+
hasHeaderConfirmed(header: ClientBlockHeader): boolean {
|
|
234
|
+
return numFrom(Date.now()) - header.timestamp >= this.confirmedBlockTime;
|
|
235
|
+
}
|
|
219
236
|
}
|
package/src/client/client.ts
CHANGED
|
@@ -14,7 +14,6 @@ import { reduceAsync, sleep } from "../utils/index.js";
|
|
|
14
14
|
import { ClientCache } from "./cache/index.js";
|
|
15
15
|
import { ClientCacheMemory } from "./cache/memory.js";
|
|
16
16
|
import {
|
|
17
|
-
CONFIRMED_BLOCK_TIME,
|
|
18
17
|
ClientCollectableSearchKeyLike,
|
|
19
18
|
DEFAULT_MAX_FEE_RATE,
|
|
20
19
|
DEFAULT_MIN_FEE_RATE,
|
|
@@ -38,10 +37,6 @@ import {
|
|
|
38
37
|
} from "./clientTypes.js";
|
|
39
38
|
import { KnownScript } from "./knownScript.js";
|
|
40
39
|
|
|
41
|
-
function hasHeaderConfirmed(header: ClientBlockHeader): boolean {
|
|
42
|
-
return numFrom(Date.now()) - header.timestamp >= CONFIRMED_BLOCK_TIME;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
40
|
/**
|
|
46
41
|
* @public
|
|
47
42
|
*/
|
|
@@ -112,7 +107,7 @@ export abstract class Client {
|
|
|
112
107
|
verbosity,
|
|
113
108
|
withCycles,
|
|
114
109
|
);
|
|
115
|
-
if (res && hasHeaderConfirmed(res.header)) {
|
|
110
|
+
if (res && this.cache.hasHeaderConfirmed(res.header)) {
|
|
116
111
|
await this.cache.recordBlocks(res);
|
|
117
112
|
}
|
|
118
113
|
return res;
|
|
@@ -132,7 +127,7 @@ export abstract class Client {
|
|
|
132
127
|
verbosity,
|
|
133
128
|
withCycles,
|
|
134
129
|
);
|
|
135
|
-
if (res && hasHeaderConfirmed(res.header)) {
|
|
130
|
+
if (res && this.cache.hasHeaderConfirmed(res.header)) {
|
|
136
131
|
await this.cache.recordBlocks(res);
|
|
137
132
|
}
|
|
138
133
|
return res;
|
|
@@ -147,7 +142,7 @@ export abstract class Client {
|
|
|
147
142
|
}
|
|
148
143
|
|
|
149
144
|
const res = await this.getHeaderByNumberNoCache(blockNumber, verbosity);
|
|
150
|
-
if (res && hasHeaderConfirmed(res)) {
|
|
145
|
+
if (res && this.cache.hasHeaderConfirmed(res)) {
|
|
151
146
|
await this.cache.recordHeaders(res);
|
|
152
147
|
}
|
|
153
148
|
return res;
|
|
@@ -162,7 +157,7 @@ export abstract class Client {
|
|
|
162
157
|
}
|
|
163
158
|
|
|
164
159
|
const res = await this.getHeaderByHashNoCache(blockHash, verbosity);
|
|
165
|
-
if (res && hasHeaderConfirmed(res)) {
|
|
160
|
+
if (res && this.cache.hasHeaderConfirmed(res)) {
|
|
166
161
|
await this.cache.recordHeaders(res);
|
|
167
162
|
}
|
|
168
163
|
return res;
|
|
@@ -636,7 +631,7 @@ export abstract class Client {
|
|
|
636
631
|
const tx = await this.cache.getTransactionResponse(txHash);
|
|
637
632
|
if (tx?.blockHash) {
|
|
638
633
|
const header = await this.getHeaderByHash(tx.blockHash);
|
|
639
|
-
if (header && hasHeaderConfirmed(header)) {
|
|
634
|
+
if (header && this.cache.hasHeaderConfirmed(header)) {
|
|
640
635
|
return {
|
|
641
636
|
transaction: tx,
|
|
642
637
|
header,
|