@cheqd/studio 3.17.0 → 3.18.0-develop.1
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/README.md +10 -7
- package/dist/controllers/api/account.d.ts +8 -3
- package/dist/controllers/api/account.d.ts.map +1 -1
- package/dist/controllers/api/account.js +100 -32
- package/dist/controllers/api/account.js.map +1 -1
- package/dist/database/entities/faucet-request.entity.d.ts +15 -0
- package/dist/database/entities/faucet-request.entity.d.ts.map +1 -0
- package/dist/database/entities/faucet-request.entity.js +65 -0
- package/dist/database/entities/faucet-request.entity.js.map +1 -0
- package/dist/database/migrations/1791500000000-studio-migrations.d.ts +7 -0
- package/dist/database/migrations/1791500000000-studio-migrations.d.ts.map +1 -0
- package/dist/database/migrations/1791500000000-studio-migrations.js +14 -0
- package/dist/database/migrations/1791500000000-studio-migrations.js.map +1 -0
- package/dist/database/types/types.d.ts.map +1 -1
- package/dist/database/types/types.js +5 -0
- package/dist/database/types/types.js.map +1 -1
- package/dist/helpers/faucet-quota.d.ts +66 -0
- package/dist/helpers/faucet-quota.d.ts.map +1 -0
- package/dist/helpers/faucet-quota.js +62 -0
- package/dist/helpers/faucet-quota.js.map +1 -0
- package/dist/helpers/faucet.d.ts +3 -1
- package/dist/helpers/faucet.d.ts.map +1 -1
- package/dist/helpers/faucet.js +9 -2
- package/dist/helpers/faucet.js.map +1 -1
- package/dist/services/api/faucet-request.d.ts +22 -0
- package/dist/services/api/faucet-request.d.ts.map +1 -0
- package/dist/services/api/faucet-request.js +52 -0
- package/dist/services/api/faucet-request.js.map +1 -0
- package/dist/static/swagger-api.json +65 -3
- package/dist/types/account.d.ts +16 -0
- package/dist/types/account.d.ts.map +1 -1
- package/dist/types/constants.d.ts +9 -1
- package/dist/types/constants.d.ts.map +1 -1
- package/dist/types/constants.js +22 -5
- package/dist/types/constants.js.map +1 -1
- package/dist/types/swagger-api-types.d.ts +39 -0
- package/dist/types/swagger-api-types.d.ts.map +1 -1
- package/dist/types/swagger-api-types.js +39 -0
- package/dist/types/swagger-api-types.js.map +1 -1
- package/example.env +7 -1
- package/package.json +1 -1
|
@@ -18,6 +18,7 @@ import { CredentialProviderEntity } from '../entities/credential-provider.entity
|
|
|
18
18
|
import { ProviderConfigurationEntity } from '../entities/provider-configuration.entity.js';
|
|
19
19
|
import { IssuedCredentialEntity } from '../entities/issued-credential.entity.js';
|
|
20
20
|
import { StatusRegistryEntity } from '../entities/status-registry.entity.js';
|
|
21
|
+
import { FaucetRequestEntity } from '../entities/faucet-request.entity.js';
|
|
21
22
|
import { CreatePaymentTable1695740345977 } from '../migrations/archive/CreatePaymentTable.js';
|
|
22
23
|
import { CreateOperationTable1695740345977 } from '../migrations/archive/CreateOperationTable.js';
|
|
23
24
|
import { CreateCustomersTable1683723285946 } from '../migrations/archive/CreateCustomersTable.js';
|
|
@@ -53,6 +54,7 @@ import { StudioMigrations1761834657128 } from '../migrations/1761834657128-studi
|
|
|
53
54
|
import { MigrationsStatusLists1762775396083 } from '../migrations/1762775396083-MigrateStatusLists.js';
|
|
54
55
|
import { UpdateWriteCursors1762775500000 } from '../migrations/1762775500000-UpdateWriteCursors.js';
|
|
55
56
|
import { StudioMigrations1766408271347 } from '../migrations/1766408271347-studio-migrations.js';
|
|
57
|
+
import { StudioMigrations1791500000000 } from '../migrations/1791500000000-studio-migrations.js';
|
|
56
58
|
dotenv.config();
|
|
57
59
|
const { EXTERNAL_DB_CONNECTION_URL, EXTERNAL_DB_CERT } = process.env;
|
|
58
60
|
export class Memory {
|
|
@@ -143,6 +145,8 @@ export class Postgres {
|
|
|
143
145
|
MigrationsStatusLists1762775396083,
|
|
144
146
|
UpdateWriteCursors1762775500000,
|
|
145
147
|
StudioMigrations1766408271347,
|
|
148
|
+
// Add faucetRequest table for the monthly faucet quota
|
|
149
|
+
StudioMigrations1791500000000,
|
|
146
150
|
],
|
|
147
151
|
entities: [
|
|
148
152
|
...Entities,
|
|
@@ -162,6 +166,7 @@ export class Postgres {
|
|
|
162
166
|
ProviderConfigurationEntity,
|
|
163
167
|
IssuedCredentialEntity,
|
|
164
168
|
StatusRegistryEntity,
|
|
169
|
+
FaucetRequestEntity,
|
|
165
170
|
],
|
|
166
171
|
logging: ['error', 'info', 'warn'],
|
|
167
172
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/database/types/types.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,sBAAsB,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,EAAE,wBAAwB,EAAE,MAAM,2CAA2C,CAAC;AACrF,OAAO,EAAE,2BAA2B,EAAE,MAAM,8CAA8C,CAAC;AAC3F,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/database/types/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { CustomerEntity } from '../database/entities/customer.entity.js';
|
|
2
|
+
import type { FaucetQuotaSummary } from '../types/account.js';
|
|
3
|
+
/**
|
|
4
|
+
* Helpers for the per-customer monthly faucet quota.
|
|
5
|
+
* The quota window is the current calendar month in UTC.
|
|
6
|
+
*/
|
|
7
|
+
export interface FaucetQuotaWindow {
|
|
8
|
+
start: Date;
|
|
9
|
+
resetsAt: Date;
|
|
10
|
+
}
|
|
11
|
+
/** Calendar-month (UTC) window containing `now`. */
|
|
12
|
+
export declare function getFaucetQuotaWindow(now?: Date): FaucetQuotaWindow;
|
|
13
|
+
/** Seconds until the quota window resets, rounded up and never below 1. */
|
|
14
|
+
export declare function secondsUntilReset(window: FaucetQuotaWindow, now?: Date): number;
|
|
15
|
+
/** True if `requestedNcheq` fits in what is left of `limitNcheq` after `usedNcheq`. */
|
|
16
|
+
export declare function fitsInQuota(usedNcheq: bigint, requestedNcheq: bigint, limitNcheq: bigint): boolean;
|
|
17
|
+
/** Most that can be requested now: the lower of the room under the address cap and the quota left, never negative. */
|
|
18
|
+
export declare function maxRequestableNcheq(roomUnderCapNcheq: bigint, quotaRemainingNcheq: bigint): bigint;
|
|
19
|
+
/** Remaining quota, never negative. */
|
|
20
|
+
export declare function remainingQuota(usedNcheq: bigint, limitNcheq: bigint): bigint;
|
|
21
|
+
export declare function buildFaucetQuotaSummary(usedNcheq: bigint, limitNcheq: bigint, window: FaucetQuotaWindow): FaucetQuotaSummary;
|
|
22
|
+
export type FaucetReservation = {
|
|
23
|
+
reserved: true;
|
|
24
|
+
faucetRequestId: string;
|
|
25
|
+
usedNcheq: bigint;
|
|
26
|
+
window: FaucetQuotaWindow;
|
|
27
|
+
} | {
|
|
28
|
+
reserved: false;
|
|
29
|
+
usedNcheq: bigint;
|
|
30
|
+
window: FaucetQuotaWindow;
|
|
31
|
+
};
|
|
32
|
+
/** Storage for quota reservations; implemented by `FaucetRequestService` and faked in tests. */
|
|
33
|
+
export interface FaucetQuotaLedger {
|
|
34
|
+
reserve(customer: CustomerEntity, address: string, amountNcheq: bigint, limitNcheq: bigint): Promise<FaucetReservation>;
|
|
35
|
+
release(faucetRequestId: string): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
export type FaucetCreditResult = {
|
|
38
|
+
outcome: 'quota_exceeded';
|
|
39
|
+
usedNcheq: bigint;
|
|
40
|
+
window: FaucetQuotaWindow;
|
|
41
|
+
} | {
|
|
42
|
+
outcome: 'credited';
|
|
43
|
+
usedNcheq: bigint;
|
|
44
|
+
window: FaucetQuotaWindow;
|
|
45
|
+
} | {
|
|
46
|
+
outcome: 'faucet_failed';
|
|
47
|
+
status: number;
|
|
48
|
+
error: string;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Reserves quota, calls the faucet, and settles the reservation.
|
|
52
|
+
* - Quota does not fit: the faucet is not called.
|
|
53
|
+
* - Faucet answers with an error status: it definitely did not credit the account, so the quota is released.
|
|
54
|
+
* - Faucet call throws (e.g. a timeout): the outcome is unknown and tokens may have been sent, so the
|
|
55
|
+
* reservation is kept (over-counting is safer than refunding quota for tokens that were credited).
|
|
56
|
+
*/
|
|
57
|
+
export declare function creditWithinQuota(ledger: FaucetQuotaLedger, delegate: () => Promise<{
|
|
58
|
+
status: number;
|
|
59
|
+
error: string;
|
|
60
|
+
}>, params: {
|
|
61
|
+
customer: CustomerEntity;
|
|
62
|
+
address: string;
|
|
63
|
+
amountNcheq: bigint;
|
|
64
|
+
limitNcheq: bigint;
|
|
65
|
+
}): Promise<FaucetCreditResult>;
|
|
66
|
+
//# sourceMappingURL=faucet-quota.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"faucet-quota.d.ts","sourceRoot":"","sources":["../../src/helpers/faucet-quota.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AAC9E,OAAO,KAAK,EAAuB,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAGnF;;;GAGG;AAEH,MAAM,WAAW,iBAAiB;IACjC,KAAK,EAAE,IAAI,CAAC;IACZ,QAAQ,EAAE,IAAI,CAAC;CACf;AAED,oDAAoD;AACpD,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,IAAiB,GAAG,iBAAiB,CAO9E;AAED,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,EAAE,GAAG,GAAE,IAAiB,GAAG,MAAM,CAE3F;AAED,uFAAuF;AACvF,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAElG;AAED,sHAAsH;AACtH,wBAAgB,mBAAmB,CAAC,iBAAiB,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,GAAG,MAAM,CAGlG;AAED,uCAAuC;AACvC,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAE5E;AAED,wBAAgB,uBAAuB,CACtC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,iBAAiB,GACvB,kBAAkB,CAUpB;AAED,MAAM,MAAM,iBAAiB,GAC1B;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,GACzF;IAAE,QAAQ,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,CAAC;AAErE,gGAAgG;AAChG,MAAM,WAAW,iBAAiB;IACjC,OAAO,CACN,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GAChB,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC9B,OAAO,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAED,MAAM,MAAM,kBAAkB,GAC3B;IAAE,OAAO,EAAE,gBAAgB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,GAE3E;IAAE,OAAO,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,GACrE;IAAE,OAAO,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/D;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACtC,MAAM,EAAE,iBAAiB,EACzB,QAAQ,EAAE,MAAM,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,EAC1D,MAAM,EAAE;IAAE,QAAQ,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC5F,OAAO,CAAC,kBAAkB,CAAC,CAgB7B"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { ncheqToCheq } from './denom.js';
|
|
2
|
+
/** Calendar-month (UTC) window containing `now`. */
|
|
3
|
+
export function getFaucetQuotaWindow(now = new Date()) {
|
|
4
|
+
const year = now.getUTCFullYear();
|
|
5
|
+
const month = now.getUTCMonth();
|
|
6
|
+
return {
|
|
7
|
+
start: new Date(Date.UTC(year, month, 1)),
|
|
8
|
+
resetsAt: new Date(Date.UTC(year, month + 1, 1)),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
/** Seconds until the quota window resets, rounded up and never below 1. */
|
|
12
|
+
export function secondsUntilReset(window, now = new Date()) {
|
|
13
|
+
return Math.max(1, Math.ceil((window.resetsAt.getTime() - now.getTime()) / 1000));
|
|
14
|
+
}
|
|
15
|
+
/** True if `requestedNcheq` fits in what is left of `limitNcheq` after `usedNcheq`. */
|
|
16
|
+
export function fitsInQuota(usedNcheq, requestedNcheq, limitNcheq) {
|
|
17
|
+
return usedNcheq + requestedNcheq <= limitNcheq;
|
|
18
|
+
}
|
|
19
|
+
/** Most that can be requested now: the lower of the room under the address cap and the quota left, never negative. */
|
|
20
|
+
export function maxRequestableNcheq(roomUnderCapNcheq, quotaRemainingNcheq) {
|
|
21
|
+
const lowest = roomUnderCapNcheq < quotaRemainingNcheq ? roomUnderCapNcheq : quotaRemainingNcheq;
|
|
22
|
+
return lowest > 0n ? lowest : 0n;
|
|
23
|
+
}
|
|
24
|
+
/** Remaining quota, never negative. */
|
|
25
|
+
export function remainingQuota(usedNcheq, limitNcheq) {
|
|
26
|
+
return usedNcheq >= limitNcheq ? 0n : limitNcheq - usedNcheq;
|
|
27
|
+
}
|
|
28
|
+
export function buildFaucetQuotaSummary(usedNcheq, limitNcheq, window) {
|
|
29
|
+
const remainingNcheq = remainingQuota(usedNcheq, limitNcheq);
|
|
30
|
+
const amount = (ncheq) => ({ cheq: ncheqToCheq(ncheq), ncheq: ncheq.toString() });
|
|
31
|
+
return {
|
|
32
|
+
period: 'month',
|
|
33
|
+
limit: amount(limitNcheq),
|
|
34
|
+
used: amount(usedNcheq),
|
|
35
|
+
remaining: amount(remainingNcheq),
|
|
36
|
+
resetsAt: window.resetsAt.toISOString(),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Reserves quota, calls the faucet, and settles the reservation.
|
|
41
|
+
* - Quota does not fit: the faucet is not called.
|
|
42
|
+
* - Faucet answers with an error status: it definitely did not credit the account, so the quota is released.
|
|
43
|
+
* - Faucet call throws (e.g. a timeout): the outcome is unknown and tokens may have been sent, so the
|
|
44
|
+
* reservation is kept (over-counting is safer than refunding quota for tokens that were credited).
|
|
45
|
+
*/
|
|
46
|
+
export async function creditWithinQuota(ledger, delegate, params) {
|
|
47
|
+
const reservation = await ledger.reserve(params.customer, params.address, params.amountNcheq, params.limitNcheq);
|
|
48
|
+
if (!reservation.reserved) {
|
|
49
|
+
return { outcome: 'quota_exceeded', usedNcheq: reservation.usedNcheq, window: reservation.window };
|
|
50
|
+
}
|
|
51
|
+
const faucet = await delegate();
|
|
52
|
+
if (faucet.status !== 200) {
|
|
53
|
+
await ledger.release(reservation.faucetRequestId);
|
|
54
|
+
return { outcome: 'faucet_failed', status: faucet.status, error: faucet.error };
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
outcome: 'credited',
|
|
58
|
+
usedNcheq: reservation.usedNcheq + params.amountNcheq,
|
|
59
|
+
window: reservation.window,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=faucet-quota.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"faucet-quota.js","sourceRoot":"","sources":["../../src/helpers/faucet-quota.ts"],"names":[],"mappings":"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"}
|
package/dist/helpers/faucet.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { ICommonErrorResponse } from '../types/authentication.js';
|
|
2
|
+
/** True if the error is the faucet call timing out or being aborted, as opposed to the faucet answering. */
|
|
3
|
+
export declare function isFaucetTimeout(error: unknown): boolean;
|
|
2
4
|
export declare class FaucetHelper {
|
|
3
|
-
static delegateTokens(address: string, firstName: string, lastName: string, email: string, amount?: number): Promise<ICommonErrorResponse>;
|
|
5
|
+
static delegateTokens(address: string, firstName: string, lastName: string, email: string, amount?: number, timeoutMs?: number): Promise<ICommonErrorResponse>;
|
|
4
6
|
}
|
|
5
7
|
//# sourceMappingURL=faucet.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"faucet.d.ts","sourceRoot":"","sources":["../../src/helpers/faucet.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"faucet.d.ts","sourceRoot":"","sources":["../../src/helpers/faucet.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAWvE,4GAA4G;AAC5G,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAGvD;AAED,qBAAa,YAAY;WAEX,cAAc,CAC1B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,MAAM,SAAgB,EACtB,SAAS,SAAwC,GAC/C,OAAO,CAAC,oBAAoB,CAAC;CA+BhC"}
|
package/dist/helpers/faucet.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import { MINIMAL_DENOM, FAUCET_URI, FAUCET_AMOUNT, FAUCET_API_KEY, FAUCET_ACCESS_CLIENT_ID, FAUCET_ACCESS_CLIENT_SECRET, } from '../types/constants.js';
|
|
1
|
+
import { MINIMAL_DENOM, FAUCET_URI, FAUCET_AMOUNT, FAUCET_API_KEY, FAUCET_ACCESS_CLIENT_ID, FAUCET_ACCESS_CLIENT_SECRET, FAUCET_REQUEST_TIMEOUT_SECONDS, } from '../types/constants.js';
|
|
2
|
+
/** True if the error is the faucet call timing out or being aborted, as opposed to the faucet answering. */
|
|
3
|
+
export function isFaucetTimeout(error) {
|
|
4
|
+
const name = error?.name;
|
|
5
|
+
return name === 'TimeoutError' || name === 'AbortError';
|
|
6
|
+
}
|
|
2
7
|
export class FaucetHelper {
|
|
3
8
|
// ...
|
|
4
|
-
static async delegateTokens(address, firstName, lastName, email, amount = FAUCET_AMOUNT) {
|
|
9
|
+
static async delegateTokens(address, firstName, lastName, email, amount = FAUCET_AMOUNT, timeoutMs = FAUCET_REQUEST_TIMEOUT_SECONDS * 1000) {
|
|
5
10
|
const faucetURI = FAUCET_URI;
|
|
6
11
|
const faucetBody = {
|
|
7
12
|
denom: MINIMAL_DENOM,
|
|
@@ -22,6 +27,8 @@ export class FaucetHelper {
|
|
|
22
27
|
},
|
|
23
28
|
body: JSON.stringify(faucetBody),
|
|
24
29
|
method: 'POST',
|
|
30
|
+
// Covers waiting for the response and reading its body. On expiry fetch rejects with a TimeoutError.
|
|
31
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
25
32
|
});
|
|
26
33
|
return {
|
|
27
34
|
status: response.status,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"faucet.js","sourceRoot":"","sources":["../../src/helpers/faucet.ts"],"names":[],"mappings":"AACA,OAAO,EACN,aAAa,EACb,UAAU,EACV,aAAa,EACb,cAAc,EACd,uBAAuB,EACvB,2BAA2B,
|
|
1
|
+
{"version":3,"file":"faucet.js","sourceRoot":"","sources":["../../src/helpers/faucet.ts"],"names":[],"mappings":"AACA,OAAO,EACN,aAAa,EACb,UAAU,EACV,aAAa,EACb,cAAc,EACd,uBAAuB,EACvB,2BAA2B,EAC3B,8BAA8B,GAC9B,MAAM,uBAAuB,CAAC;AAE/B,4GAA4G;AAC5G,MAAM,UAAU,eAAe,CAAC,KAAc;IAC7C,MAAM,IAAI,GAAI,KAAkC,EAAE,IAAI,CAAC;IACvD,OAAO,IAAI,KAAK,cAAc,IAAI,IAAI,KAAK,YAAY,CAAC;AACzD,CAAC;AAED,MAAM,OAAO,YAAY;IACxB,MAAM;IACN,MAAM,CAAC,KAAK,CAAC,cAAc,CAC1B,OAAe,EACf,SAAiB,EACjB,QAAgB,EAChB,KAAa,EACb,MAAM,GAAG,aAAa,EACtB,SAAS,GAAG,8BAA8B,GAAG,IAAI;QAEjD,MAAM,SAAS,GAAG,UAAU,CAAC;QAC7B,MAAM,UAAU,GAAG;YAClB,KAAK,EAAE,aAAa;YACpB,OAAO,EAAE,OAAO;YAChB,KAAK,EAAE,KAAK;YACZ,UAAU,EAAE,SAAS;YACrB,SAAS,EAAE,QAAQ;YACnB,OAAO,EAAE,4BAA4B;YACrC,MAAM;YACN,eAAe,EAAE,KAAK;SACtB,CAAC;QACF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,SAAS,EAAE;YACvC,OAAO,EAAE;gBACR,cAAc,EAAE,kBAAkB;gBAClC,WAAW,EAAE,cAAc;gBAC3B,qBAAqB,EAAE,uBAAuB;gBAC9C,yBAAyB,EAAE,2BAA2B;aACtD;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;YAChC,MAAM,EAAE,MAAM;YACd,qGAAqG;YACrG,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC;SACtC,CAAC,CAAC;QACH,OAAO;YACN,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,KAAK,EAAE,MAAM,QAAQ,CAAC,IAAI,EAAE;YAC5B,IAAI,EAAE,EAAE;SACR,CAAC;IACH,CAAC;CAED"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Repository } from 'typeorm';
|
|
2
|
+
import type { CustomerEntity } from '../../database/entities/customer.entity.js';
|
|
3
|
+
import { FaucetRequestEntity } from '../../database/entities/faucet-request.entity.js';
|
|
4
|
+
import { type FaucetQuotaLedger, type FaucetReservation } from '../../helpers/faucet-quota.js';
|
|
5
|
+
export declare class FaucetRequestService implements FaucetQuotaLedger {
|
|
6
|
+
faucetRequestRepository: Repository<FaucetRequestEntity>;
|
|
7
|
+
static instance: FaucetRequestService;
|
|
8
|
+
constructor(repository?: Repository<FaucetRequestEntity>);
|
|
9
|
+
/** Total ncheq requested by the customer since `since`, using the given manager (and so its transaction). */
|
|
10
|
+
private static sumRequestedNcheq;
|
|
11
|
+
/** Total ncheq requested by the customer in the current quota window. */
|
|
12
|
+
getUsedNcheq(customer: CustomerEntity, now?: Date): Promise<bigint>;
|
|
13
|
+
/**
|
|
14
|
+
* Atomically checks the customer's monthly quota and, if the amount fits, records it.
|
|
15
|
+
* A per-customer advisory lock serialises concurrent requests so they cannot overshoot the limit.
|
|
16
|
+
* Call `release` if the upstream faucet call then definitely failed.
|
|
17
|
+
*/
|
|
18
|
+
reserve(customer: CustomerEntity, address: string, amountNcheq: bigint, limitNcheq: bigint, now?: Date): Promise<FaucetReservation>;
|
|
19
|
+
/** Releases a reservation, e.g. when the upstream faucet reported that it did not credit the account. */
|
|
20
|
+
release(faucetRequestId: string): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=faucet-request.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"faucet-request.d.ts","sourceRoot":"","sources":["../../../src/services/api/faucet-request.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,UAAU,EAAE,MAAM,SAAS,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4CAA4C,CAAC;AACjF,OAAO,EAAE,mBAAmB,EAAE,MAAM,kDAAkD,CAAC;AAEvF,OAAO,EAGN,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,MAAM,+BAA+B,CAAC;AAEvC,qBAAa,oBAAqB,YAAW,iBAAiB;IACtD,uBAAuB,EAAE,UAAU,CAAC,mBAAmB,CAAC,CAAC;IAEhE,OAAc,QAAQ,uBAA8B;gBAExC,UAAU,CAAC,EAAE,UAAU,CAAC,mBAAmB,CAAC;IAKxD,6GAA6G;mBACxF,iBAAiB;IAUtC,yEAAyE;IAC5D,YAAY,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,GAAE,IAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;IAK5F;;;;OAIG;IACU,OAAO,CACnB,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,GAAG,GAAE,IAAiB,GACpB,OAAO,CAAC,iBAAiB,CAAC;IAmB7B,yGAAyG;IAC5F,OAAO,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG5D"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { FaucetRequestEntity } from '../../database/entities/faucet-request.entity.js';
|
|
2
|
+
import { Connection } from '../../database/connection/connection.js';
|
|
3
|
+
import { fitsInQuota, getFaucetQuotaWindow, } from '../../helpers/faucet-quota.js';
|
|
4
|
+
export class FaucetRequestService {
|
|
5
|
+
faucetRequestRepository;
|
|
6
|
+
static instance = new FaucetRequestService();
|
|
7
|
+
constructor(repository) {
|
|
8
|
+
this.faucetRequestRepository =
|
|
9
|
+
repository ?? Connection.instance.dbConnection.getRepository(FaucetRequestEntity);
|
|
10
|
+
}
|
|
11
|
+
/** Total ncheq requested by the customer since `since`, using the given manager (and so its transaction). */
|
|
12
|
+
static async sumRequestedNcheq(manager, customerId, since) {
|
|
13
|
+
const row = await manager
|
|
14
|
+
.createQueryBuilder(FaucetRequestEntity, 'request')
|
|
15
|
+
.select('COALESCE(SUM(request.amountNcheq), 0)', 'total')
|
|
16
|
+
.where('request.customerId = :customerId', { customerId })
|
|
17
|
+
.andWhere('request.createdAt >= :since', { since })
|
|
18
|
+
.getRawOne();
|
|
19
|
+
return BigInt(row?.total ?? '0');
|
|
20
|
+
}
|
|
21
|
+
/** Total ncheq requested by the customer in the current quota window. */
|
|
22
|
+
async getUsedNcheq(customer, now = new Date()) {
|
|
23
|
+
const { start } = getFaucetQuotaWindow(now);
|
|
24
|
+
return FaucetRequestService.sumRequestedNcheq(this.faucetRequestRepository.manager, customer.customerId, start);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Atomically checks the customer's monthly quota and, if the amount fits, records it.
|
|
28
|
+
* A per-customer advisory lock serialises concurrent requests so they cannot overshoot the limit.
|
|
29
|
+
* Call `release` if the upstream faucet call then definitely failed.
|
|
30
|
+
*/
|
|
31
|
+
async reserve(customer, address, amountNcheq, limitNcheq, now = new Date()) {
|
|
32
|
+
const window = getFaucetQuotaWindow(now);
|
|
33
|
+
return this.faucetRequestRepository.manager.transaction(async (manager) => {
|
|
34
|
+
if (manager.connection.options.type === 'postgres') {
|
|
35
|
+
await manager.query('SELECT pg_advisory_xact_lock(hashtext($1))', [
|
|
36
|
+
`faucet-quota:${customer.customerId}`,
|
|
37
|
+
]);
|
|
38
|
+
}
|
|
39
|
+
const usedNcheq = await FaucetRequestService.sumRequestedNcheq(manager, customer.customerId, window.start);
|
|
40
|
+
if (!fitsInQuota(usedNcheq, amountNcheq, limitNcheq)) {
|
|
41
|
+
return { reserved: false, usedNcheq, window };
|
|
42
|
+
}
|
|
43
|
+
const entity = await manager.save(new FaucetRequestEntity(customer, address, amountNcheq));
|
|
44
|
+
return { reserved: true, faucetRequestId: entity.faucetRequestId, usedNcheq, window };
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/** Releases a reservation, e.g. when the upstream faucet reported that it did not credit the account. */
|
|
48
|
+
async release(faucetRequestId) {
|
|
49
|
+
await this.faucetRequestRepository.delete({ faucetRequestId });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=faucet-request.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"faucet-request.js","sourceRoot":"","sources":["../../../src/services/api/faucet-request.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,kDAAkD,CAAC;AACvF,OAAO,EAAE,UAAU,EAAE,MAAM,yCAAyC,CAAC;AACrE,OAAO,EACN,WAAW,EACX,oBAAoB,GAGpB,MAAM,+BAA+B,CAAC;AAEvC,MAAM,OAAO,oBAAoB;IACzB,uBAAuB,CAAkC;IAEzD,MAAM,CAAC,QAAQ,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAEpD,YAAY,UAA4C;QACvD,IAAI,CAAC,uBAAuB;YAC3B,UAAU,IAAI,UAAU,CAAC,QAAQ,CAAC,YAAY,CAAC,aAAa,CAAC,mBAAmB,CAAC,CAAC;IACpF,CAAC;IAED,6GAA6G;IACrG,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,OAAsB,EAAE,UAAkB,EAAE,KAAW;QAC7F,MAAM,GAAG,GAAG,MAAM,OAAO;aACvB,kBAAkB,CAAC,mBAAmB,EAAE,SAAS,CAAC;aAClD,MAAM,CAAC,uCAAuC,EAAE,OAAO,CAAC;aACxD,KAAK,CAAC,kCAAkC,EAAE,EAAE,UAAU,EAAE,CAAC;aACzD,QAAQ,CAAC,6BAA6B,EAAE,EAAE,KAAK,EAAE,CAAC;aAClD,SAAS,EAAqB,CAAC;QACjC,OAAO,MAAM,CAAC,GAAG,EAAE,KAAK,IAAI,GAAG,CAAC,CAAC;IAClC,CAAC;IAED,yEAAyE;IAClE,KAAK,CAAC,YAAY,CAAC,QAAwB,EAAE,MAAY,IAAI,IAAI,EAAE;QACzE,MAAM,EAAE,KAAK,EAAE,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;QAC5C,OAAO,oBAAoB,CAAC,iBAAiB,CAAC,IAAI,CAAC,uBAAuB,CAAC,OAAO,EAAE,QAAQ,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACjH,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,OAAO,CACnB,QAAwB,EACxB,OAAe,EACf,WAAmB,EACnB,UAAkB,EAClB,MAAY,IAAI,IAAI,EAAE;QAEtB,MAAM,MAAM,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;QACzC,OAAO,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YACzE,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBACpD,MAAM,OAAO,CAAC,KAAK,CAAC,4CAA4C,EAAE;oBACjE,gBAAgB,QAAQ,CAAC,UAAU,EAAE;iBACrC,CAAC,CAAC;YACJ,CAAC;YAED,MAAM,SAAS,GAAG,MAAM,oBAAoB,CAAC,iBAAiB,CAAC,OAAO,EAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YAC3G,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,WAAW,EAAE,UAAU,CAAC,EAAE,CAAC;gBACtD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAW,CAAC;YACxD,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,mBAAmB,CAAC,QAAQ,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;YAC3F,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,CAAC,eAAe,EAAE,SAAS,EAAE,MAAM,EAAW,CAAC;QAChG,CAAC,CAAC,CAAC;IACJ,CAAC;IAED,yGAAyG;IAClG,KAAK,CAAC,OAAO,CAAC,eAAuB;QAC3C,MAAM,IAAI,CAAC,uBAAuB,CAAC,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC;IAChE,CAAC"}
|
|
@@ -3182,6 +3182,19 @@
|
|
|
3182
3182
|
}
|
|
3183
3183
|
}
|
|
3184
3184
|
},
|
|
3185
|
+
"FaucetAmount": {
|
|
3186
|
+
"type": "object",
|
|
3187
|
+
"properties": {
|
|
3188
|
+
"cheq": {
|
|
3189
|
+
"type": "number",
|
|
3190
|
+
"example": 10000
|
|
3191
|
+
},
|
|
3192
|
+
"ncheq": {
|
|
3193
|
+
"type": "string",
|
|
3194
|
+
"example": "10000000000000"
|
|
3195
|
+
}
|
|
3196
|
+
}
|
|
3197
|
+
},
|
|
3185
3198
|
"AccountBalancesResponse": {
|
|
3186
3199
|
"type": "object",
|
|
3187
3200
|
"properties": {
|
|
@@ -3191,6 +3204,49 @@
|
|
|
3191
3204
|
"testnet": {
|
|
3192
3205
|
"$ref": "#/components/schemas/AccountNetworkBalance"
|
|
3193
3206
|
},
|
|
3207
|
+
"faucet": {
|
|
3208
|
+
"type": "object",
|
|
3209
|
+
"nullable": true,
|
|
3210
|
+
"description": "Testnet faucet cap and the customer's monthly faucet quota usage. `null` when there is no testnet account or it could not be read.",
|
|
3211
|
+
"properties": {
|
|
3212
|
+
"cap": {
|
|
3213
|
+
"type": "object",
|
|
3214
|
+
"description": "Most CHEQ a testnet address can hold before the faucet stops topping it up.",
|
|
3215
|
+
"properties": {
|
|
3216
|
+
"cheq": {
|
|
3217
|
+
"type": "number",
|
|
3218
|
+
"example": 100000
|
|
3219
|
+
},
|
|
3220
|
+
"ncheq": {
|
|
3221
|
+
"type": "string",
|
|
3222
|
+
"example": "100000000000000"
|
|
3223
|
+
}
|
|
3224
|
+
}
|
|
3225
|
+
},
|
|
3226
|
+
"quota": {
|
|
3227
|
+
"type": "object",
|
|
3228
|
+
"properties": {
|
|
3229
|
+
"period": {
|
|
3230
|
+
"type": "string",
|
|
3231
|
+
"example": "month"
|
|
3232
|
+
},
|
|
3233
|
+
"limit": {
|
|
3234
|
+
"$ref": "#/components/schemas/FaucetAmount"
|
|
3235
|
+
},
|
|
3236
|
+
"used": {
|
|
3237
|
+
"$ref": "#/components/schemas/FaucetAmount"
|
|
3238
|
+
},
|
|
3239
|
+
"remaining": {
|
|
3240
|
+
"$ref": "#/components/schemas/FaucetAmount"
|
|
3241
|
+
},
|
|
3242
|
+
"resetsAt": {
|
|
3243
|
+
"type": "string",
|
|
3244
|
+
"format": "date-time"
|
|
3245
|
+
}
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
}
|
|
3249
|
+
},
|
|
3194
3250
|
"rate": {
|
|
3195
3251
|
"type": "object",
|
|
3196
3252
|
"nullable": true,
|
|
@@ -3433,7 +3489,7 @@
|
|
|
3433
3489
|
"Account"
|
|
3434
3490
|
],
|
|
3435
3491
|
"summary": "Request cheqd testnet CHEQ tokens for a Studio payment account.",
|
|
3436
|
-
"description": "Funds an authenticated Studio user's owned testnet payment account up to the
|
|
3492
|
+
"description": "Funds an authenticated Studio user's owned testnet payment account. An address can hold at most FAUCET_ADDRESS_CAP_CHEQ, and a customer can request at most FAUCET_MONTHLY_LIMIT_CHEQ per calendar month (UTC) across all their addresses; both default to 100,000 CHEQ. Without an amount the address is topped up to the cap, or by the quota left if that is lower. Works with a Studio user session or an API key; the response includes the remaining quota.",
|
|
3437
3493
|
"requestBody": {
|
|
3438
3494
|
"content": {
|
|
3439
3495
|
"application/json": {
|
|
@@ -3446,7 +3502,7 @@
|
|
|
3446
3502
|
},
|
|
3447
3503
|
"amount": {
|
|
3448
3504
|
"type": "number",
|
|
3449
|
-
"description": "Optional amount in CHEQ. Defaults to the
|
|
3505
|
+
"description": "Optional amount in CHEQ. Defaults to the most that can be requested now (the lower of the room under the address cap and the monthly quota left)."
|
|
3450
3506
|
}
|
|
3451
3507
|
}
|
|
3452
3508
|
}
|
|
@@ -3469,6 +3525,9 @@
|
|
|
3469
3525
|
"404": {
|
|
3470
3526
|
"description": "No Studio testnet payment account was found for this customer."
|
|
3471
3527
|
},
|
|
3528
|
+
"429": {
|
|
3529
|
+
"description": "The customer's monthly faucet quota is exhausted. The Retry-After header gives the seconds until it resets, and the body includes the quota details."
|
|
3530
|
+
},
|
|
3472
3531
|
"500": {
|
|
3473
3532
|
"$ref": "#/components/schemas/InternalError"
|
|
3474
3533
|
},
|
|
@@ -3477,6 +3536,9 @@
|
|
|
3477
3536
|
},
|
|
3478
3537
|
"503": {
|
|
3479
3538
|
"description": "Stripe subscription checks are disabled."
|
|
3539
|
+
},
|
|
3540
|
+
"504": {
|
|
3541
|
+
"description": "The faucet did not respond within FAUCET_REQUEST_TIMEOUT_SECONDS. The request may or may not have been processed."
|
|
3480
3542
|
}
|
|
3481
3543
|
}
|
|
3482
3544
|
}
|
|
@@ -3531,7 +3593,7 @@
|
|
|
3531
3593
|
"Account"
|
|
3532
3594
|
],
|
|
3533
3595
|
"summary": "Fetch payment account balances.",
|
|
3534
|
-
"description": "Returns the on-chain balance of the authenticated customer's mainnet and testnet payment accounts, expressed in ncheq, CHEQ and USD. The CHEQ/USD rate is sourced from CoinGecko and cached; if it (or a network's RPC endpoint) is unavailable the response still returns 200 with the affected `usd`/`rate`/`balance` fields set to `null`.",
|
|
3596
|
+
"description": "Returns the on-chain balance of the authenticated customer's mainnet and testnet payment accounts, expressed in ncheq, CHEQ and USD. The CHEQ/USD rate is sourced from CoinGecko and cached; if it (or a network's RPC endpoint) is unavailable the response still returns 200 with the affected `usd`/`rate`/`balance` fields set to `null`. Also returns the testnet faucet cap and the customer's monthly faucet quota usage under `faucet`.",
|
|
3535
3597
|
"responses": {
|
|
3536
3598
|
"200": {
|
|
3537
3599
|
"description": "The request was successful.",
|
package/dist/types/account.d.ts
CHANGED
|
@@ -19,9 +19,25 @@ export interface AccountNetworkBalance {
|
|
|
19
19
|
} | null;
|
|
20
20
|
usd: number | null;
|
|
21
21
|
}
|
|
22
|
+
export interface FaucetAmountSummary {
|
|
23
|
+
cheq: number;
|
|
24
|
+
ncheq: string;
|
|
25
|
+
}
|
|
26
|
+
export interface FaucetQuotaSummary {
|
|
27
|
+
period: 'month';
|
|
28
|
+
limit: FaucetAmountSummary;
|
|
29
|
+
used: FaucetAmountSummary;
|
|
30
|
+
remaining: FaucetAmountSummary;
|
|
31
|
+
resetsAt: string;
|
|
32
|
+
}
|
|
33
|
+
export interface AccountFaucetInfo {
|
|
34
|
+
cap: FaucetAmountSummary;
|
|
35
|
+
quota: FaucetQuotaSummary;
|
|
36
|
+
}
|
|
22
37
|
export interface QueryAccountBalancesResponseBody {
|
|
23
38
|
mainnet: AccountNetworkBalance | null;
|
|
24
39
|
testnet: AccountNetworkBalance | null;
|
|
40
|
+
faucet: AccountFaucetInfo | null;
|
|
25
41
|
rate: {
|
|
26
42
|
cheqUsd: number;
|
|
27
43
|
source: 'coingecko';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account.d.ts","sourceRoot":"","sources":["../../src/types/account.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,wBAAwB;IACxC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,yBAAyB,EAAE,OAAO,CAAC;IACnC,yBAAyB,EAAE,OAAO,CAAC;IACnC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,MAAM,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,eAAO,MAAM,wBAAwB;kBAU9B,wBAAwB;CAE9B,CAAC;AAIF,MAAM,WAAW,qBAAqB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IAEd,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAEhD,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,gCAAgC;IAEhD,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACtC,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAEtC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,WAAW,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACpE"}
|
|
1
|
+
{"version":3,"file":"account.d.ts","sourceRoot":"","sources":["../../src/types/account.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,wBAAwB;IACxC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,yBAAyB,EAAE,OAAO,CAAC;IACnC,yBAAyB,EAAE,OAAO,CAAC;IACnC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,MAAM,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,eAAO,MAAM,wBAAwB;kBAU9B,wBAAwB;CAE9B,CAAC;AAIF,MAAM,WAAW,qBAAqB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IAEd,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAEhD,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IAClC,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,mBAAmB,CAAC;IAC3B,IAAI,EAAE,mBAAmB,CAAC;IAC1B,SAAS,EAAE,mBAAmB,CAAC;IAE/B,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAEjC,GAAG,EAAE,mBAAmB,CAAC;IACzB,KAAK,EAAE,kBAAkB,CAAC;CAC1B;AAED,MAAM,WAAW,gCAAgC;IAEhD,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACtC,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAEtC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAEjC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,WAAW,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACpE"}
|
|
@@ -22,12 +22,20 @@ export declare const configLogToExpress: {
|
|
|
22
22
|
getAccessToken: boolean;
|
|
23
23
|
fetchUserInfo: boolean;
|
|
24
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* Reads a positive number from an environment variable. An unset variable uses the fallback silently; a variable that
|
|
27
|
+
* is set but invalid also uses the fallback but says so loudly, so a typo in a limit is not mistaken for the default.
|
|
28
|
+
*/
|
|
29
|
+
export declare const parseNumberEnv: (value: string | undefined, fallback: number, name?: string) => number;
|
|
25
30
|
export declare const MINIMAL_DENOM = "ncheq";
|
|
26
31
|
export declare const FAUCET_URI: string;
|
|
27
32
|
export declare const FAUCET_API_KEY: string;
|
|
28
33
|
export declare const DEFAULT_DENOM_EXPONENT = 9;
|
|
29
34
|
export declare const TESTNET_MINIMUM_BALANCE: number;
|
|
30
|
-
export declare const
|
|
35
|
+
export declare const TESTNET_INITIAL_TOPUP_CHEQ: number;
|
|
36
|
+
export declare const FAUCET_MONTHLY_LIMIT_CHEQ: number;
|
|
37
|
+
export declare const FAUCET_ADDRESS_CAP_CHEQ: number;
|
|
38
|
+
export declare const FAUCET_REQUEST_TIMEOUT_SECONDS: number;
|
|
31
39
|
export declare const FAUCET_AMOUNT: number;
|
|
32
40
|
export declare const FAUCET_ACCESS_CLIENT_ID: string;
|
|
33
41
|
export declare const FAUCET_ACCESS_CLIENT_SECRET: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/types/constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAKrD,eAAO,MAAM,OAAO;;;;;;;CAGnB,CAAC;AAGF,eAAO,MAAM,oBAAoB,QAA8D,CAAC;AAChG,eAAO,MAAM,oBAAoB,KAA2D,CAAC;AAC7F,eAAO,MAAM,cAAc,SAAS,CAAC;AACrC,eAAO,MAAM,qBAAqB,KAAK,CAAC;AACxC,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC,eAAO,MAAM,SAAS,QAAkC,CAAC;AAKzD,eAAO,MAAM,oBAAoB,QAAsE,CAAC;AAExG,eAAO,MAAM,kBAAkB;;;;;;;CA0B9B,CAAC;
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/types/constants.ts"],"names":[],"mappings":"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"}
|
package/dist/types/constants.js
CHANGED
|
@@ -43,19 +43,36 @@ export const configLogToExpress = {
|
|
|
43
43
|
fetchUserInfo: true,
|
|
44
44
|
};
|
|
45
45
|
// Faucet constants
|
|
46
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Reads a positive number from an environment variable. An unset variable uses the fallback silently; a variable that
|
|
48
|
+
* is set but invalid also uses the fallback but says so loudly, so a typo in a limit is not mistaken for the default.
|
|
49
|
+
*/
|
|
50
|
+
export const parseNumberEnv = (value, fallback, name = 'environment variable') => {
|
|
47
51
|
if (!value?.trim())
|
|
48
52
|
return fallback;
|
|
49
53
|
const parsed = Number(value);
|
|
50
|
-
|
|
54
|
+
if (Number.isFinite(parsed) && parsed > 0)
|
|
55
|
+
return parsed;
|
|
56
|
+
console.warn(`Ignoring invalid ${name}="${value}": expected a positive number. Using the default, ${fallback}.`);
|
|
57
|
+
return fallback;
|
|
51
58
|
};
|
|
52
59
|
export const MINIMAL_DENOM = 'ncheq';
|
|
53
60
|
export const FAUCET_URI = process.env.FAUCET_URI || 'https://faucet-api.cheqd.network/credit';
|
|
54
61
|
export const FAUCET_API_KEY = process.env.FAUCET_API_KEY || 'default-api-key';
|
|
55
62
|
export const DEFAULT_DENOM_EXPONENT = 9;
|
|
56
|
-
export const TESTNET_MINIMUM_BALANCE = parseNumberEnv(process.env.TESTNET_MINIMUM_BALANCE, 10000);
|
|
57
|
-
|
|
58
|
-
|
|
63
|
+
export const TESTNET_MINIMUM_BALANCE = parseNumberEnv(process.env.TESTNET_MINIMUM_BALANCE, 10000, 'TESTNET_MINIMUM_BALANCE');
|
|
64
|
+
// Amount, in CHEQ, a new account's testnet address is topped up to when it is bootstrapped (ENABLE_ACCOUNT_TOPUP).
|
|
65
|
+
// TESTNET_FAUCET_UPPER_CAP_CHEQ is the previous name and is still honoured as a fallback.
|
|
66
|
+
export const TESTNET_INITIAL_TOPUP_CHEQ = parseNumberEnv(process.env.TESTNET_INITIAL_TOPUP_CHEQ || process.env.TESTNET_FAUCET_UPPER_CAP_CHEQ, TESTNET_MINIMUM_BALANCE, process.env.TESTNET_INITIAL_TOPUP_CHEQ ? 'TESTNET_INITIAL_TOPUP_CHEQ' : 'TESTNET_FAUCET_UPPER_CAP_CHEQ');
|
|
67
|
+
// Most CHEQ a customer can request through POST /account/faucet per calendar month (UTC)
|
|
68
|
+
export const FAUCET_MONTHLY_LIMIT_CHEQ = parseNumberEnv(process.env.FAUCET_MONTHLY_LIMIT_CHEQ, 100000, 'FAUCET_MONTHLY_LIMIT_CHEQ');
|
|
69
|
+
// Most CHEQ a single testnet address can hold before POST /account/faucet stops topping it up.
|
|
70
|
+
// Defaults to the monthly limit, so there is one figure unless this is set explicitly.
|
|
71
|
+
export const FAUCET_ADDRESS_CAP_CHEQ = parseNumberEnv(process.env.FAUCET_ADDRESS_CAP_CHEQ, FAUCET_MONTHLY_LIMIT_CHEQ, 'FAUCET_ADDRESS_CAP_CHEQ');
|
|
72
|
+
// How long, in seconds, to wait for the faucet service to answer before giving up. Without a limit a hung faucet
|
|
73
|
+
// holds the caller (and a quota reservation) for as long as Node's own default, several minutes.
|
|
74
|
+
export const FAUCET_REQUEST_TIMEOUT_SECONDS = parseNumberEnv(process.env.FAUCET_REQUEST_TIMEOUT_SECONDS, 30, 'FAUCET_REQUEST_TIMEOUT_SECONDS');
|
|
75
|
+
export const FAUCET_AMOUNT = parseNumberEnv(process.env.FAUCET_AMOUNT, 100000000000000, 'FAUCET_AMOUNT');
|
|
59
76
|
export const FAUCET_ACCESS_CLIENT_ID = process.env.FAUCET_ACCESS_CLIENT_ID || '';
|
|
60
77
|
export const FAUCET_ACCESS_CLIENT_SECRET = process.env.FAUCET_ACCESS_CLIENT_SECRET || '';
|
|
61
78
|
// CHEQ market data (CoinGecko), used by GET /account/balances for CHEQ to USD conversion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/types/constants.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,MAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,mBAAmB;AACnB,MAAM,CAAC,MAAM,OAAO,GAAG;IACtB,IAAI,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;IAC5C,IAAI,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE;CACtC,CAAC;AAEF,wBAAwB;AACxB,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,uBAAuB,CAAC;AAChG,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,oBAAoB,CAAC;AAC7F,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC;AACrC,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,CAAC;AACxC,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,CAAC;AACrC,wDAAwD;AACxD,MAAM,CAAC,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM,CAAC;AAEzD,iBAAiB;AACjB,MAAM,EAAE,cAAc,EAAE,YAAY,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC;AAE9F,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,+BAA+B,CAAC;AAExG,MAAM,CAAC,MAAM,kBAAkB,GAAG;IACjC,QAAQ,EACP,cAAc;QACd,CAAC;YACA,IAAI,qBAAqB,KAAK,MAAM;gBAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;YACvF,OAAO,EAAE,CAAC;QACX,CAAC,CAAC,EAAE;IACL,KAAK,EACJ,YAAY;QACZ,CAAC;YACA,IAAI,qBAAqB,KAAK,MAAM;gBAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;YACrF,OAAO,EAAE,CAAC;QACX,CAAC,CAAC,EAAE;IACL,SAAS,EACR,gBAAgB;QAChB,CAAC;YACA,IAAI,qBAAqB,KAAK,MAAM;gBAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;YACzF,OAAO,EAAE,CAAC;QACX,CAAC,CAAC,EAAE;IACL,OAAO,EACN,oBAAoB;QACpB,CAAC;YACA,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACxD,CAAC,CAAC,EAAE;IACL,cAAc,EAAE,KAAK;IACrB,aAAa,EAAE,IAAI;CACnB,CAAC;AAEF,mBAAmB;AACnB,MAAM,cAAc,GAAG,CAAC,KAAyB,EAAE,QAAgB,EAAU,EAAE;
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/types/constants.ts"],"names":[],"mappings":"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"}
|