@chipi-stack/backend 14.15.0 → 14.16.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/dist/index.d.mts +163 -10
- package/dist/index.d.ts +163 -10
- package/dist/index.js +292 -29
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +283 -30
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1958,9 +1958,9 @@ var ChipiTransactions = class {
|
|
|
1958
1958
|
/**
|
|
1959
1959
|
* Get on-chain transaction status
|
|
1960
1960
|
*/
|
|
1961
|
-
async getTransactionStatus(
|
|
1961
|
+
async getTransactionStatus(hash13, bearerToken) {
|
|
1962
1962
|
return this.client.get({
|
|
1963
|
-
endpoint: `${shared.API_ENDPOINTS.TRANSACTIONS}/${
|
|
1963
|
+
endpoint: `${shared.API_ENDPOINTS.TRANSACTIONS}/${hash13}/status`,
|
|
1964
1964
|
bearerToken
|
|
1965
1965
|
});
|
|
1966
1966
|
}
|
|
@@ -3315,9 +3315,13 @@ var ChipiAi = class {
|
|
|
3315
3315
|
* session key: a USDC `transfer` to the offer's `payTo`, then the same call
|
|
3316
3316
|
* again with `X-PAYMENT`. The price must be at most `maxAmount`, `model`
|
|
3317
3317
|
* must be payable and the input within `maxPromptBytes`, all checked before
|
|
3318
|
-
* paying. The
|
|
3319
|
-
*
|
|
3320
|
-
*
|
|
3318
|
+
* paying. The wallet must be a wallet of the organization that owns the
|
|
3319
|
+
* `sk_`: the first request names it in `X-PAYER`, and when the API answers
|
|
3320
|
+
* that a payment from it would be refused, nothing is paid
|
|
3321
|
+
* (`X402_PAYER_NOT_IN_ORG`). The session must whitelist `transfer` and cap
|
|
3322
|
+
* USDC. A payment that was made but not served is reported in
|
|
3323
|
+
* `error.details.xPayment`; pass it back as `options.xPayment` to retry
|
|
3324
|
+
* without paying again.
|
|
3321
3325
|
*
|
|
3322
3326
|
* @example
|
|
3323
3327
|
* ```typescript
|
|
@@ -3329,20 +3333,32 @@ var ChipiAi = class {
|
|
|
3329
3333
|
* ```
|
|
3330
3334
|
*/
|
|
3331
3335
|
async think(params, options = {}) {
|
|
3336
|
+
let payer;
|
|
3337
|
+
if (options.payWithSession && !options.xPayment) {
|
|
3338
|
+
try {
|
|
3339
|
+
payer = padFelt(options.payWithSession.wallet.publicKey);
|
|
3340
|
+
} catch {
|
|
3341
|
+
payer = void 0;
|
|
3342
|
+
}
|
|
3343
|
+
}
|
|
3332
3344
|
try {
|
|
3333
|
-
return await this.postThink(params, options.xPayment);
|
|
3345
|
+
return await this.postThink(params, options.xPayment, payer);
|
|
3334
3346
|
} catch (err) {
|
|
3335
3347
|
const offer = options.payWithSession ? sessionTransferOffer(err) : void 0;
|
|
3336
3348
|
if (!offer || !options.payWithSession) throw err;
|
|
3337
3349
|
return this.payAndThink(params, offer, options.payWithSession);
|
|
3338
3350
|
}
|
|
3339
3351
|
}
|
|
3340
|
-
postThink(params, xPayment) {
|
|
3352
|
+
postThink(params, xPayment, payer) {
|
|
3353
|
+
const headers = {
|
|
3354
|
+
...xPayment ? { "X-PAYMENT": xPayment } : {},
|
|
3355
|
+
...payer ? { "X-PAYER": payer } : {}
|
|
3356
|
+
};
|
|
3341
3357
|
return this.client.post({
|
|
3342
3358
|
endpoint: `${AI_BASE}/think`,
|
|
3343
3359
|
bearerToken: this.secret(),
|
|
3344
3360
|
body: params,
|
|
3345
|
-
...
|
|
3361
|
+
...Object.keys(headers).length > 0 ? { headers } : {}
|
|
3346
3362
|
});
|
|
3347
3363
|
}
|
|
3348
3364
|
/**
|
|
@@ -3395,6 +3411,15 @@ var ChipiAi = class {
|
|
|
3395
3411
|
{ x402: { accepts: [offer] } }
|
|
3396
3412
|
);
|
|
3397
3413
|
}
|
|
3414
|
+
const payerCheck = offer.extra?.payer;
|
|
3415
|
+
if (payerCheck?.accepted === false && typeof payerCheck.address === "string" && sameFelt(payerCheck.address, pay.wallet.publicKey)) {
|
|
3416
|
+
throw new shared.ChipiApiError(
|
|
3417
|
+
`Wallet ${pay.wallet.publicKey} is not a wallet of the organization that owns this API key, so the API would refuse its payment; nothing was paid. Pay from a wallet of this organization.`,
|
|
3418
|
+
"X402_PAYER_NOT_IN_ORG",
|
|
3419
|
+
402,
|
|
3420
|
+
{ x402: { accepts: [offer] } }
|
|
3421
|
+
);
|
|
3422
|
+
}
|
|
3398
3423
|
const payer = pay.wallet.publicKey;
|
|
3399
3424
|
const mask = (1n << 128n) - 1n;
|
|
3400
3425
|
const transactionHash = await this.sessions.executeTransactionWithSession(
|
|
@@ -3522,6 +3547,122 @@ var ChipiAi = class {
|
|
|
3522
3547
|
});
|
|
3523
3548
|
}
|
|
3524
3549
|
};
|
|
3550
|
+
var STARKNET_SIGNATURE_VALID = "0x56414c4944";
|
|
3551
|
+
function toFeltHex(value) {
|
|
3552
|
+
return starknet.num.toHex(BigInt(value));
|
|
3553
|
+
}
|
|
3554
|
+
function normalizeStarknetAddress(address) {
|
|
3555
|
+
return `0x${BigInt(address).toString(16).padStart(64, "0")}`;
|
|
3556
|
+
}
|
|
3557
|
+
function isContractNotFound(err) {
|
|
3558
|
+
const e = err;
|
|
3559
|
+
if (e?.baseError?.code === 20 || e?.code === 20) return true;
|
|
3560
|
+
return /contract not found/i.test(e?.message ?? String(err));
|
|
3561
|
+
}
|
|
3562
|
+
async function isValidStarknetSignature(provider, accountAddress, messageHash, signature) {
|
|
3563
|
+
try {
|
|
3564
|
+
const sig = signature.map(toFeltHex);
|
|
3565
|
+
const result = await provider.callContract({
|
|
3566
|
+
contractAddress: normalizeStarknetAddress(accountAddress),
|
|
3567
|
+
entrypoint: "is_valid_signature",
|
|
3568
|
+
calldata: [toFeltHex(messageHash), toFeltHex(sig.length), ...sig]
|
|
3569
|
+
});
|
|
3570
|
+
const first = result?.[0];
|
|
3571
|
+
if (first !== void 0 && BigInt(first) === BigInt(STARKNET_SIGNATURE_VALID)) {
|
|
3572
|
+
return { valid: true };
|
|
3573
|
+
}
|
|
3574
|
+
return { valid: false, reason: "INVALID_SIGNATURE" };
|
|
3575
|
+
} catch (err) {
|
|
3576
|
+
if (isContractNotFound(err)) return { valid: false, reason: "ACCOUNT_NOT_DEPLOYED" };
|
|
3577
|
+
return {
|
|
3578
|
+
valid: false,
|
|
3579
|
+
reason: "INVALID_SIGNATURE",
|
|
3580
|
+
detail: err instanceof Error ? err.message : String(err)
|
|
3581
|
+
};
|
|
3582
|
+
}
|
|
3583
|
+
}
|
|
3584
|
+
var COUNTERFACTUAL_ACCOUNT_CLASSES = {
|
|
3585
|
+
/** OpenZeppelin AccountUpgradeable 3.0 (Bramble's default account). */
|
|
3586
|
+
OPENZEPPELIN_V3: "0x01d1777db36cdd06dd62cfde77b1b6ae06412af95d57a13dc40ac77b8a702381",
|
|
3587
|
+
/** Argent X / Ready 0.4 (`WALLET_CLASS_HASHES.READY`). */
|
|
3588
|
+
ARGENT_V0_4: "0x036078334509b514626504edc9fb252328d1a240e4e948bef8d0c08dff45927f"
|
|
3589
|
+
};
|
|
3590
|
+
function starkVerify(r, s, messageHash, publicKey) {
|
|
3591
|
+
const x = BigInt(publicKey).toString(16).padStart(64, "0");
|
|
3592
|
+
const sig = new starknet.ec.starkCurve.Signature(BigInt(r), BigInt(s));
|
|
3593
|
+
for (const prefix of ["02", "03"]) {
|
|
3594
|
+
try {
|
|
3595
|
+
if (starknet.ec.starkCurve.verify(sig, toFeltHex(messageHash), prefix + x)) return true;
|
|
3596
|
+
} catch {
|
|
3597
|
+
}
|
|
3598
|
+
}
|
|
3599
|
+
return false;
|
|
3600
|
+
}
|
|
3601
|
+
function verifyUndeployedStarknetSignature(deployment, messageHash, signature) {
|
|
3602
|
+
const classHash = normalizeStarknetAddress(deployment.class_hash);
|
|
3603
|
+
const calldata = deployment.calldata.map(toFeltHex);
|
|
3604
|
+
const sig = signature.map(toFeltHex);
|
|
3605
|
+
let publicKey;
|
|
3606
|
+
let r;
|
|
3607
|
+
let s;
|
|
3608
|
+
if (classHash === COUNTERFACTUAL_ACCOUNT_CLASSES.OPENZEPPELIN_V3) {
|
|
3609
|
+
if (calldata.length !== 1 || sig.length !== 2) {
|
|
3610
|
+
return { valid: false, reason: "INVALID_SIGNATURE" };
|
|
3611
|
+
}
|
|
3612
|
+
[publicKey] = calldata;
|
|
3613
|
+
[r, s] = sig;
|
|
3614
|
+
} else if (classHash === COUNTERFACTUAL_ACCOUNT_CLASSES.ARGENT_V0_4) {
|
|
3615
|
+
if (calldata.length !== 3 || BigInt(calldata[0]) !== 0n || BigInt(calldata[2]) !== 1n) {
|
|
3616
|
+
return { valid: false, reason: "UNSUPPORTED_ACCOUNT_CLASS" };
|
|
3617
|
+
}
|
|
3618
|
+
if (sig.length !== 5 || BigInt(sig[0]) !== 1n || BigInt(sig[1]) !== 0n) {
|
|
3619
|
+
return { valid: false, reason: "INVALID_SIGNATURE" };
|
|
3620
|
+
}
|
|
3621
|
+
if (BigInt(sig[2]) !== BigInt(calldata[1])) {
|
|
3622
|
+
return { valid: false, reason: "INVALID_SIGNATURE" };
|
|
3623
|
+
}
|
|
3624
|
+
publicKey = calldata[1];
|
|
3625
|
+
[, , , r, s] = sig;
|
|
3626
|
+
} else {
|
|
3627
|
+
return { valid: false, reason: "UNSUPPORTED_ACCOUNT_CLASS" };
|
|
3628
|
+
}
|
|
3629
|
+
const expected = starknet.hash.calculateContractAddressFromHash(
|
|
3630
|
+
toFeltHex(deployment.salt),
|
|
3631
|
+
classHash,
|
|
3632
|
+
calldata,
|
|
3633
|
+
0
|
|
3634
|
+
);
|
|
3635
|
+
if (normalizeStarknetAddress(expected) !== normalizeStarknetAddress(deployment.address)) {
|
|
3636
|
+
return { valid: false, reason: "ADDRESS_MISMATCH" };
|
|
3637
|
+
}
|
|
3638
|
+
return starkVerify(r, s, messageHash, publicKey) ? { valid: true } : { valid: false, reason: "INVALID_SIGNATURE" };
|
|
3639
|
+
}
|
|
3640
|
+
|
|
3641
|
+
// src/x402/facilitator.ts
|
|
3642
|
+
var TRANSFER_SELECTOR2 = BigInt(starknet.hash.getSelectorFromName("transfer"));
|
|
3643
|
+
function shhhTransferMatches(oeCalldata, payload) {
|
|
3644
|
+
try {
|
|
3645
|
+
const felts = oeCalldata.map((v) => BigInt(v));
|
|
3646
|
+
const [, , , executeBefore, callsLen] = felts;
|
|
3647
|
+
if (callsLen !== 1n) return { ok: false, reason: "SHHH payment must be exactly one transfer" };
|
|
3648
|
+
const [to, selector, len, recipient, low, high] = felts.slice(5, 11);
|
|
3649
|
+
if (to !== BigInt(payload.asset) || selector !== TRANSFER_SELECTOR2 || len !== 3n) {
|
|
3650
|
+
return { ok: false, reason: "SHHH payment call is not a transfer of the payment asset" };
|
|
3651
|
+
}
|
|
3652
|
+
if (recipient !== BigInt(payload.toAddress)) {
|
|
3653
|
+
return { ok: false, reason: "SHHH payment pays a different recipient" };
|
|
3654
|
+
}
|
|
3655
|
+
if (low + (high << 128n) !== BigInt(payload.amount)) {
|
|
3656
|
+
return { ok: false, reason: "SHHH payment amount differs from the declared amount" };
|
|
3657
|
+
}
|
|
3658
|
+
if (executeBefore <= BigInt(Math.floor(Date.now() / 1e3))) {
|
|
3659
|
+
return { ok: false, reason: "SHHH payment has expired (execute_before in the past)" };
|
|
3660
|
+
}
|
|
3661
|
+
return { ok: true };
|
|
3662
|
+
} catch {
|
|
3663
|
+
return { ok: false, reason: "Malformed SHHH oeCalldata" };
|
|
3664
|
+
}
|
|
3665
|
+
}
|
|
3525
3666
|
var InMemoryNonceStore = class {
|
|
3526
3667
|
constructor() {
|
|
3527
3668
|
this.used = /* @__PURE__ */ new Set();
|
|
@@ -3564,11 +3705,18 @@ var X402Facilitator = class _X402Facilitator {
|
|
|
3564
3705
|
* Verify a payment signature is valid (doesn't execute the transfer).
|
|
3565
3706
|
*
|
|
3566
3707
|
* Checks:
|
|
3567
|
-
* 1.
|
|
3568
|
-
* 2.
|
|
3569
|
-
* 3.
|
|
3570
|
-
* 4.
|
|
3571
|
-
* 5.
|
|
3708
|
+
* 1. x402 version is 1
|
|
3709
|
+
* 2. Network is starknet-mainnet
|
|
3710
|
+
* 3. Nonce has not been used (replay protection)
|
|
3711
|
+
* 4. Payment has not expired (validUntil > now)
|
|
3712
|
+
* 5. Asset is USDC mainnet
|
|
3713
|
+
* 6. Amount is positive
|
|
3714
|
+
* 7. Addresses are non-empty
|
|
3715
|
+
* 8. Signature: with a `provider`, the payer account's `is_valid_signature`
|
|
3716
|
+
* must return 'VALID'. Without one, only its presence is checked (not a
|
|
3717
|
+
* cryptographic check). SHHH payloads must sign exactly one transfer
|
|
3718
|
+
* of `amount` of `asset` to `toAddress`; their signature is checked
|
|
3719
|
+
* on-chain at settle.
|
|
3572
3720
|
*/
|
|
3573
3721
|
async verify(payment) {
|
|
3574
3722
|
const { payload } = payment;
|
|
@@ -3624,6 +3772,8 @@ var X402Facilitator = class _X402Facilitator {
|
|
|
3624
3772
|
if (!Array.isArray(oeCalldata) || oeCalldata.length === 0) {
|
|
3625
3773
|
return { valid: false, reason: "Missing SHHH oeCalldata" };
|
|
3626
3774
|
}
|
|
3775
|
+
const bound = shhhTransferMatches(oeCalldata, payment.payload);
|
|
3776
|
+
if (!bound.ok) return { valid: false, reason: bound.reason };
|
|
3627
3777
|
return { valid: true };
|
|
3628
3778
|
}
|
|
3629
3779
|
if (!this.provider) {
|
|
@@ -3644,22 +3794,25 @@ var X402Facilitator = class _X402Facilitator {
|
|
|
3644
3794
|
valid_until: String(payload.validUntil),
|
|
3645
3795
|
nonce: payload.nonce
|
|
3646
3796
|
});
|
|
3647
|
-
|
|
3797
|
+
let msgHash;
|
|
3648
3798
|
try {
|
|
3649
|
-
|
|
3650
|
-
contractAddress: payload.fromAddress,
|
|
3651
|
-
entrypoint: "is_valid_signature",
|
|
3652
|
-
calldata: [msgHash, "2", payload.signature.r, payload.signature.s]
|
|
3653
|
-
});
|
|
3654
|
-
const VALID = "0x56414c4944";
|
|
3655
|
-
if (result[0] === VALID || result[0] === BigInt(VALID).toString()) {
|
|
3656
|
-
return { valid: true };
|
|
3657
|
-
}
|
|
3658
|
-
return { valid: false, reason: "Invalid SNIP-12 signature" };
|
|
3799
|
+
msgHash = starknet.typedData.getMessageHash(paymentTypedData, payload.fromAddress);
|
|
3659
3800
|
} catch (err) {
|
|
3660
3801
|
const message = err instanceof Error ? err.message : String(err);
|
|
3661
|
-
return { valid: false, reason: `
|
|
3802
|
+
return { valid: false, reason: `Malformed payment: ${message}` };
|
|
3662
3803
|
}
|
|
3804
|
+
const check = await isValidStarknetSignature(this.provider, payload.fromAddress, msgHash, [
|
|
3805
|
+
payload.signature.r,
|
|
3806
|
+
payload.signature.s
|
|
3807
|
+
]);
|
|
3808
|
+
if (check.valid) return { valid: true };
|
|
3809
|
+
if (check.reason === "ACCOUNT_NOT_DEPLOYED") {
|
|
3810
|
+
return { valid: false, reason: "Payer account is not deployed" };
|
|
3811
|
+
}
|
|
3812
|
+
return {
|
|
3813
|
+
valid: false,
|
|
3814
|
+
reason: check.detail ? `Signature verification failed: ${check.detail}` : "Invalid SNIP-12 signature"
|
|
3815
|
+
};
|
|
3663
3816
|
}
|
|
3664
3817
|
/**
|
|
3665
3818
|
* Settle a verified payment by executing the USDC transfer via paymaster.
|
|
@@ -3788,7 +3941,7 @@ var signTypedData = async ({
|
|
|
3788
3941
|
throw error;
|
|
3789
3942
|
}
|
|
3790
3943
|
};
|
|
3791
|
-
function
|
|
3944
|
+
function toFeltHex2(x) {
|
|
3792
3945
|
return "0x" + x.toString(16).padStart(64, "0");
|
|
3793
3946
|
}
|
|
3794
3947
|
var signTypedDataArray = async ({
|
|
@@ -3818,7 +3971,7 @@ var signTypedDataArray = async ({
|
|
|
3818
3971
|
messageHash,
|
|
3819
3972
|
ownerIndex: 0n
|
|
3820
3973
|
});
|
|
3821
|
-
return envelope.map(
|
|
3974
|
+
return envelope.map(toFeltHex2);
|
|
3822
3975
|
}
|
|
3823
3976
|
const provider = new starknet.RpcProvider({ nodeUrl: shared.WALLET_RPC_ENDPOINTS[walletType] });
|
|
3824
3977
|
const account = new starknet.Account({ provider, address: wallet.publicKey, signer: privateKeyDecrypted });
|
|
@@ -4103,8 +4256,8 @@ var ChipiSDK = class {
|
|
|
4103
4256
|
/**
|
|
4104
4257
|
* Get on-chain transaction status (supports polling for confirmation)
|
|
4105
4258
|
*/
|
|
4106
|
-
async getTransactionStatus(
|
|
4107
|
-
return this.transactions.getTransactionStatus(
|
|
4259
|
+
async getTransactionStatus(hash13, bearerToken) {
|
|
4260
|
+
return this.transactions.getTransactionStatus(hash13, this.resolveBearerToken(bearerToken));
|
|
4108
4261
|
}
|
|
4109
4262
|
/**
|
|
4110
4263
|
* Prepare a wallet upgrade (e.g., READY → CHIPI or CHIPI v29 → v33).
|
|
@@ -4476,6 +4629,106 @@ function x402Middleware(config) {
|
|
|
4476
4629
|
next();
|
|
4477
4630
|
};
|
|
4478
4631
|
}
|
|
4632
|
+
var SIWS_DOMAIN_NAME = "Sign in with Starknet";
|
|
4633
|
+
var SIWS_DOMAIN_VERSION = "1";
|
|
4634
|
+
var SIWS_CHAIN_ID = "SN_MAIN";
|
|
4635
|
+
var DEFAULT_STATEMENT = "Sign in. This request costs nothing and moves no funds.";
|
|
4636
|
+
function assertPrintableAscii(field, value) {
|
|
4637
|
+
if (!/^[\x20-\x7e]*$/.test(value)) {
|
|
4638
|
+
throw new Error(`SIWS ${field} must be single-line printable ASCII`);
|
|
4639
|
+
}
|
|
4640
|
+
}
|
|
4641
|
+
function createStarknetSignInTypedData(params) {
|
|
4642
|
+
const message = {
|
|
4643
|
+
domain: params.domain,
|
|
4644
|
+
address: normalizeStarknetAddress(params.address),
|
|
4645
|
+
statement: params.statement ?? DEFAULT_STATEMENT,
|
|
4646
|
+
uri: params.uri,
|
|
4647
|
+
nonce: params.nonce,
|
|
4648
|
+
issuedAt: params.issuedAt ?? Math.floor(Date.now() / 1e3),
|
|
4649
|
+
expirationTime: params.expirationTime
|
|
4650
|
+
};
|
|
4651
|
+
for (const field of ["domain", "statement", "uri", "nonce"]) {
|
|
4652
|
+
assertPrintableAscii(field, message[field]);
|
|
4653
|
+
}
|
|
4654
|
+
if (!/^[A-Za-z0-9]{8,}$/.test(message.nonce)) {
|
|
4655
|
+
throw new Error("SIWS nonce must be at least 8 letters or digits");
|
|
4656
|
+
}
|
|
4657
|
+
if (!Number.isInteger(message.issuedAt) || !Number.isInteger(message.expirationTime)) {
|
|
4658
|
+
throw new Error("SIWS times must be whole unix seconds");
|
|
4659
|
+
}
|
|
4660
|
+
if (message.expirationTime <= message.issuedAt) {
|
|
4661
|
+
throw new Error("SIWS expirationTime must be after issuedAt");
|
|
4662
|
+
}
|
|
4663
|
+
return {
|
|
4664
|
+
types: {
|
|
4665
|
+
StarknetDomain: [
|
|
4666
|
+
{ name: "name", type: "shortstring" },
|
|
4667
|
+
{ name: "version", type: "shortstring" },
|
|
4668
|
+
{ name: "chainId", type: "shortstring" },
|
|
4669
|
+
{ name: "revision", type: "shortstring" }
|
|
4670
|
+
],
|
|
4671
|
+
SignIn: [
|
|
4672
|
+
{ name: "domain", type: "string" },
|
|
4673
|
+
{ name: "address", type: "ContractAddress" },
|
|
4674
|
+
{ name: "statement", type: "string" },
|
|
4675
|
+
{ name: "uri", type: "string" },
|
|
4676
|
+
{ name: "nonce", type: "string" },
|
|
4677
|
+
{ name: "issuedAt", type: "timestamp" },
|
|
4678
|
+
{ name: "expirationTime", type: "timestamp" }
|
|
4679
|
+
]
|
|
4680
|
+
},
|
|
4681
|
+
primaryType: "SignIn",
|
|
4682
|
+
domain: {
|
|
4683
|
+
name: SIWS_DOMAIN_NAME,
|
|
4684
|
+
version: SIWS_DOMAIN_VERSION,
|
|
4685
|
+
chainId: SIWS_CHAIN_ID,
|
|
4686
|
+
revision: "1"
|
|
4687
|
+
},
|
|
4688
|
+
message: { ...message }
|
|
4689
|
+
};
|
|
4690
|
+
}
|
|
4691
|
+
var MAX_SKEW_SECONDS = 60;
|
|
4692
|
+
async function verifyStarknetSignIn(params) {
|
|
4693
|
+
const { typedData: typedData2, signature, provider, expected, deploymentData } = params;
|
|
4694
|
+
const raw = typedData2?.message;
|
|
4695
|
+
if (!raw || !Array.isArray(signature) || signature.length === 0) {
|
|
4696
|
+
return { ok: false, reason: "MALFORMED" };
|
|
4697
|
+
}
|
|
4698
|
+
if (typedData2.domain?.chainId !== SIWS_CHAIN_ID) return { ok: false, reason: "WRONG_CHAIN" };
|
|
4699
|
+
let canonical;
|
|
4700
|
+
let message;
|
|
4701
|
+
try {
|
|
4702
|
+
canonical = createStarknetSignInTypedData({
|
|
4703
|
+
domain: String(raw.domain),
|
|
4704
|
+
uri: String(raw.uri),
|
|
4705
|
+
address: String(raw.address),
|
|
4706
|
+
nonce: String(raw.nonce),
|
|
4707
|
+
statement: String(raw.statement),
|
|
4708
|
+
issuedAt: Number(raw.issuedAt),
|
|
4709
|
+
expirationTime: Number(raw.expirationTime)
|
|
4710
|
+
});
|
|
4711
|
+
message = canonical.message;
|
|
4712
|
+
} catch {
|
|
4713
|
+
return { ok: false, reason: "MALFORMED" };
|
|
4714
|
+
}
|
|
4715
|
+
if (message.domain !== expected.domain) return { ok: false, reason: "WRONG_DOMAIN" };
|
|
4716
|
+
if (message.uri !== expected.uri) return { ok: false, reason: "WRONG_URI" };
|
|
4717
|
+
if (message.nonce !== expected.nonce) return { ok: false, reason: "WRONG_NONCE" };
|
|
4718
|
+
const now = expected.now ?? Math.floor(Date.now() / 1e3);
|
|
4719
|
+
if (now >= message.expirationTime) return { ok: false, reason: "EXPIRED" };
|
|
4720
|
+
if (message.issuedAt > now + MAX_SKEW_SECONDS) return { ok: false, reason: "NOT_YET_VALID" };
|
|
4721
|
+
const messageHash = starknet.typedData.getMessageHash(canonical, message.address);
|
|
4722
|
+
const onChain = await isValidStarknetSignature(provider, message.address, messageHash, signature);
|
|
4723
|
+
if (onChain.valid) return { ok: true, address: message.address, message };
|
|
4724
|
+
if (onChain.reason !== "ACCOUNT_NOT_DEPLOYED") return { ok: false, reason: "INVALID_SIGNATURE" };
|
|
4725
|
+
if (!deploymentData) return { ok: false, reason: "ACCOUNT_NOT_DEPLOYED" };
|
|
4726
|
+
if (normalizeStarknetAddress(deploymentData.address) !== message.address) {
|
|
4727
|
+
return { ok: false, reason: "ADDRESS_MISMATCH" };
|
|
4728
|
+
}
|
|
4729
|
+
const offChain = verifyUndeployedStarknetSignature(deploymentData, messageHash, signature);
|
|
4730
|
+
return offChain.valid ? { ok: true, address: message.address, message } : { ok: false, reason: offChain.reason };
|
|
4731
|
+
}
|
|
4479
4732
|
|
|
4480
4733
|
// src/shhh/index.ts
|
|
4481
4734
|
init_snip12_hash();
|
|
@@ -5388,6 +5641,7 @@ Object.defineProperty(exports, "Currency", {
|
|
|
5388
5641
|
});
|
|
5389
5642
|
exports.APPLE_ISSUER = APPLE_ISSUER;
|
|
5390
5643
|
exports.BOOTSTRAP_DOMAIN_SEPARATOR = BOOTSTRAP_DOMAIN_SEPARATOR;
|
|
5644
|
+
exports.COUNTERFACTUAL_ACCOUNT_CLASSES = COUNTERFACTUAL_ACCOUNT_CLASSES;
|
|
5391
5645
|
exports.ChipiAi = ChipiAi;
|
|
5392
5646
|
exports.ChipiBrowserSDK = ChipiBrowserSDK;
|
|
5393
5647
|
exports.ChipiClient = ChipiClient;
|
|
@@ -5407,6 +5661,10 @@ exports.OP_ROTATE_OWNER = OP_ROTATE_OWNER;
|
|
|
5407
5661
|
exports.OP_SET_THRESHOLD = OP_SET_THRESHOLD;
|
|
5408
5662
|
exports.ROLE_GUARDIAN = ROLE_GUARDIAN;
|
|
5409
5663
|
exports.ROLE_OWNER = ROLE_OWNER;
|
|
5664
|
+
exports.SIWS_CHAIN_ID = SIWS_CHAIN_ID;
|
|
5665
|
+
exports.SIWS_DOMAIN_NAME = SIWS_DOMAIN_NAME;
|
|
5666
|
+
exports.SIWS_DOMAIN_VERSION = SIWS_DOMAIN_VERSION;
|
|
5667
|
+
exports.STARKNET_SIGNATURE_VALID = STARKNET_SIGNATURE_VALID;
|
|
5410
5668
|
exports.SessionTxVerifier = SessionTxVerifier;
|
|
5411
5669
|
exports.ShhhAccount = ShhhAccount;
|
|
5412
5670
|
exports.TIMELOCK_SECONDS = TIMELOCK_SECONDS;
|
|
@@ -5451,6 +5709,7 @@ exports.computeISignerId = computeISignerId;
|
|
|
5451
5709
|
exports.computeOeHash = computeOeHash;
|
|
5452
5710
|
exports.computeShhhAddress = computeShhhAddress;
|
|
5453
5711
|
exports.computeSnip12Hash = computeSnip12Hash;
|
|
5712
|
+
exports.createStarknetSignInTypedData = createStarknetSignInTypedData;
|
|
5454
5713
|
exports.ed25519OwnerId = ed25519OwnerId;
|
|
5455
5714
|
exports.ed25519OwnerPubkeyParam = ed25519OwnerPubkeyParam;
|
|
5456
5715
|
exports.ed25519PubkeyFelts = ed25519PubkeyFelts;
|
|
@@ -5466,6 +5725,7 @@ exports.hashOutsideExecutionStruct = hashOutsideExecutionStruct;
|
|
|
5466
5725
|
exports.hashStarknetDomain = hashStarknetDomain;
|
|
5467
5726
|
exports.isReadyToExecute = isReadyToExecute;
|
|
5468
5727
|
exports.isThinkDecision = isThinkDecision;
|
|
5728
|
+
exports.isValidStarknetSignature = isValidStarknetSignature;
|
|
5469
5729
|
exports.jwtAppleSubHash = jwtAppleSubHash;
|
|
5470
5730
|
exports.jwtAppleSubOwnerId = jwtAppleSubOwnerId;
|
|
5471
5731
|
exports.jwtAppleSubPubkeyFelts = jwtAppleSubPubkeyFelts;
|
|
@@ -5474,6 +5734,7 @@ exports.locateSubClaim = locateSubClaim;
|
|
|
5474
5734
|
exports.messageHashToNonceB64url = messageHashToNonceB64url;
|
|
5475
5735
|
exports.migrateChipiWalletToShhh = migrateChipiWalletToShhh;
|
|
5476
5736
|
exports.normalizeEntrypoints = normalizeEntrypoints;
|
|
5737
|
+
exports.normalizeStarknetAddress = normalizeStarknetAddress;
|
|
5477
5738
|
exports.ownerCommitment = ownerCommitment;
|
|
5478
5739
|
exports.parseAppleIdToken = parseAppleIdToken;
|
|
5479
5740
|
exports.parseDerEcdsaSignature = parseDerEcdsaSignature;
|
|
@@ -5490,6 +5751,8 @@ exports.starkOwnerId = starkOwnerId;
|
|
|
5490
5751
|
exports.starkPubkeyFelts = starkPubkeyFelts;
|
|
5491
5752
|
exports.submitViaAccount = submitViaAccount;
|
|
5492
5753
|
exports.validateSpendingPolicyConfig = validateSpendingPolicyConfig;
|
|
5754
|
+
exports.verifyStarknetSignIn = verifyStarknetSignIn;
|
|
5755
|
+
exports.verifyUndeployedStarknetSignature = verifyUndeployedStarknetSignature;
|
|
5493
5756
|
exports.waitForTransaction = waitForTransaction;
|
|
5494
5757
|
exports.webauthnOwnerId = webauthnOwnerId;
|
|
5495
5758
|
exports.webauthnOwnerPubkeyParam = webauthnOwnerPubkeyParam;
|