@zkproofport-app/sdk 0.5.0-beta.5 → 0.5.0-beta.6
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 +39 -16
- package/dist/ProofportSDK.d.ts +24 -1
- package/dist/constants.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.js +100 -15
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +102 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +100 -15
- package/dist/index.mjs.map +1 -1
- package/dist/offChainVerifier.d.ts +8 -1
- package/dist/types.d.ts +7 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -109,11 +109,15 @@ const CIRCUIT_METADATA = {
|
|
|
109
109
|
},
|
|
110
110
|
coinbase_country_attestation: {
|
|
111
111
|
name: 'Coinbase Country',
|
|
112
|
-
description: 'Prove Coinbase country verification',
|
|
113
|
-
//
|
|
114
|
-
//
|
|
115
|
-
|
|
116
|
-
|
|
112
|
+
description: 'Prove Coinbase country verification, optionally authorizing one EIP-712 action',
|
|
113
|
+
// Coinbase Country v2 (coinbase-country-attestation-v2/src/main.nr):
|
|
114
|
+
// signal_hash 0-31, domain_separator 32-63, action_hash 64-95,
|
|
115
|
+
// signer_list_merkle_root 96-127, country_list 128-147 (10 x 2 bytes),
|
|
116
|
+
// country_list_length 148, is_included 149, scope 150-181,
|
|
117
|
+
// nullifier 182-213, attested_at 214 = 215 fields. v1's 150 fields are
|
|
118
|
+
// refused on every verify path.
|
|
119
|
+
publicInputsCount: 215,
|
|
120
|
+
publicInputNames: ['signal_hash', 'domain_separator', 'action_hash', 'signer_list_merkle_root', 'country_list', 'country_list_length', 'is_included', 'scope', 'nullifier', 'attested_at'],
|
|
117
121
|
},
|
|
118
122
|
oidc_domain_attestation: {
|
|
119
123
|
name: 'OIDC Domain',
|
|
@@ -642,11 +646,9 @@ function validateProofRequest(request) {
|
|
|
642
646
|
if (inputs.userAddress && !/^0x[a-fA-F0-9]{40}$/.test(inputs.userAddress)) {
|
|
643
647
|
return { valid: false, error: 'Invalid userAddress format' };
|
|
644
648
|
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
if (!inputs.countryList.every(c => typeof c === 'string')) {
|
|
649
|
-
return { valid: false, error: 'countryList must contain only strings' };
|
|
649
|
+
const listError = core.countryListError(inputs.countryList);
|
|
650
|
+
if (listError) {
|
|
651
|
+
return { valid: false, error: listError };
|
|
650
652
|
}
|
|
651
653
|
if (typeof inputs.isIncluded !== 'boolean') {
|
|
652
654
|
return { valid: false, error: 'isIncluded is required and must be a boolean' };
|
|
@@ -1073,7 +1075,7 @@ async function verifyProofOffChain(circuit, proof, publicInputs, options = {}) {
|
|
|
1073
1075
|
// their trust anchor as a public input the prover chooses. For OIDC that is
|
|
1074
1076
|
// the RSA key -- see core's oidcProviderKeys. Checked here so a dApp that
|
|
1075
1077
|
// verifies off-chain gets the same answer as one that verifies on-chain.
|
|
1076
|
-
const issuer = await core.checkProofIssuer(circuit, publicInputs, { request: options.request });
|
|
1078
|
+
const issuer = await core.checkProofIssuer(circuit, publicInputs, { request: options.request, countryCondition: options.countryCondition });
|
|
1077
1079
|
if (!issuer.ok) {
|
|
1078
1080
|
return { valid: false, error: issuer.error };
|
|
1079
1081
|
}
|
|
@@ -1233,6 +1235,12 @@ class ProofportSDK {
|
|
|
1233
1235
|
* {@link ProofportSDK.MAX_REMEMBERED_RELAY_REQUESTS}.
|
|
1234
1236
|
*/
|
|
1235
1237
|
this.relayRequests = new Map();
|
|
1238
|
+
/**
|
|
1239
|
+
* requestId -> the country list and direction of the Coinbase Country relay
|
|
1240
|
+
* requests this instance created, so verifyResponse* can hold the proof to
|
|
1241
|
+
* them. Bounded like {@link relayRequests}.
|
|
1242
|
+
*/
|
|
1243
|
+
this.countryRequests = new Map();
|
|
1236
1244
|
this.signer = null;
|
|
1237
1245
|
this.socket = null;
|
|
1238
1246
|
/**
|
|
@@ -1364,6 +1372,15 @@ class ProofportSDK {
|
|
|
1364
1372
|
if (typeof inputs.isIncluded !== 'boolean') {
|
|
1365
1373
|
throw new Error('isIncluded is required for coinbase_country_attestation circuit');
|
|
1366
1374
|
}
|
|
1375
|
+
const listError = core.countryListError(inputs.countryList);
|
|
1376
|
+
if (listError)
|
|
1377
|
+
throw new Error(`${listError} (circuit: coinbase_country_attestation)`);
|
|
1378
|
+
// Coinbase Country v2 binds an action or none, like Coinbase KYC v2.
|
|
1379
|
+
if (inputs.action !== undefined) {
|
|
1380
|
+
const actionError = typedAction.validateTypedAction(inputs.action);
|
|
1381
|
+
if (actionError)
|
|
1382
|
+
throw new Error(`${actionError} (circuit: coinbase_country_attestation)`);
|
|
1383
|
+
}
|
|
1367
1384
|
const request = {
|
|
1368
1385
|
requestId: generateRequestId(),
|
|
1369
1386
|
circuit: 'coinbase_country_attestation',
|
|
@@ -1764,6 +1781,7 @@ class ProofportSDK {
|
|
|
1764
1781
|
return core.verifyProofOnChain(circuit, parsedProof, providerOrSigner, this.verifierTarget(circuit), undefined, {
|
|
1765
1782
|
request: options.request,
|
|
1766
1783
|
signerVariant: options.signerVariant,
|
|
1784
|
+
countryCondition: options.countryCondition,
|
|
1767
1785
|
});
|
|
1768
1786
|
}
|
|
1769
1787
|
/**
|
|
@@ -1804,6 +1822,43 @@ class ProofportSDK {
|
|
|
1804
1822
|
this.relayRequests.delete(oldest);
|
|
1805
1823
|
}
|
|
1806
1824
|
}
|
|
1825
|
+
/**
|
|
1826
|
+
* The country list and direction a `coinbase_country_attestation` response
|
|
1827
|
+
* must have been proved against: the one the caller passed, else the relay
|
|
1828
|
+
* request this instance created under the response's requestId, else the
|
|
1829
|
+
* deep-link request still pending under it. `{ error }` when there is none:
|
|
1830
|
+
* the proof's list is the prover's choice, so a response this SDK cannot
|
|
1831
|
+
* place is refused rather than accepted for whatever list it carries.
|
|
1832
|
+
*/
|
|
1833
|
+
countryConditionFor(response, explicit) {
|
|
1834
|
+
if (explicit !== undefined)
|
|
1835
|
+
return { condition: explicit };
|
|
1836
|
+
const remembered = this.countryRequests.get(response.requestId);
|
|
1837
|
+
if (remembered)
|
|
1838
|
+
return { condition: remembered };
|
|
1839
|
+
const pending = this.pendingRequests.get(response.requestId);
|
|
1840
|
+
const inputs = pending?.circuit === 'coinbase_country_attestation' ? pending.inputs : undefined;
|
|
1841
|
+
if (inputs && Array.isArray(inputs.countryList) && typeof inputs.isIncluded === 'boolean') {
|
|
1842
|
+
return { condition: { countryList: [...inputs.countryList], isIncluded: inputs.isIncluded } };
|
|
1843
|
+
}
|
|
1844
|
+
return {
|
|
1845
|
+
error: `No Coinbase Country request ${JSON.stringify(response.requestId)} was created by this SDK instance, so the ` +
|
|
1846
|
+
"proof's country list cannot be checked against what was asked. Pass { countryCondition: { countryList, " +
|
|
1847
|
+
'isIncluded } } -- the list and direction of the request you created.',
|
|
1848
|
+
};
|
|
1849
|
+
}
|
|
1850
|
+
/** @internal Remember a Coinbase Country relay request's list and direction for verifyResponse*. */
|
|
1851
|
+
rememberCountryRequest(requestId, inputs) {
|
|
1852
|
+
const i = inputs;
|
|
1853
|
+
if (typeof requestId !== 'string' || !i || !Array.isArray(i.countryList) || typeof i.isIncluded !== 'boolean')
|
|
1854
|
+
return;
|
|
1855
|
+
this.countryRequests.delete(requestId);
|
|
1856
|
+
this.countryRequests.set(requestId, { countryList: [...i.countryList], isIncluded: i.isIncluded });
|
|
1857
|
+
while (this.countryRequests.size > ProofportSDK.MAX_REMEMBERED_RELAY_REQUESTS) {
|
|
1858
|
+
const oldest = this.countryRequests.keys().next().value;
|
|
1859
|
+
this.countryRequests.delete(oldest);
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1807
1862
|
/**
|
|
1808
1863
|
* The verifier for a circuit: the one the dApp configured, otherwise the
|
|
1809
1864
|
* pinned deployment on the chain this SDK's environment verifies that
|
|
@@ -1832,6 +1887,10 @@ class ProofportSDK {
|
|
|
1832
1887
|
* @param options.request - For `oidc_domain_attestation`: the `{ scope, requestId }`
|
|
1833
1888
|
* the response answers. Not needed for a relay request this SDK instance
|
|
1834
1889
|
* created; an OIDC response this instance cannot place is refused without it.
|
|
1890
|
+
* @param options.countryCondition - For `coinbase_country_attestation`: the
|
|
1891
|
+
* `{ countryList, isIncluded }` the request asked for. Not needed for a
|
|
1892
|
+
* request this SDK instance created (relay or deep link); a Country response
|
|
1893
|
+
* this instance cannot place is refused without it.
|
|
1835
1894
|
*
|
|
1836
1895
|
* @returns Promise resolving to verification result with valid boolean and optional error message
|
|
1837
1896
|
*
|
|
@@ -1869,6 +1928,13 @@ class ProofportSDK {
|
|
|
1869
1928
|
return { valid: false, error: found.error };
|
|
1870
1929
|
request = found.request;
|
|
1871
1930
|
}
|
|
1931
|
+
let countryCondition;
|
|
1932
|
+
if (response.circuit === 'coinbase_country_attestation') {
|
|
1933
|
+
const found = this.countryConditionFor(response, options.countryCondition);
|
|
1934
|
+
if ('error' in found)
|
|
1935
|
+
return { valid: false, error: found.error };
|
|
1936
|
+
countryCondition = found.condition;
|
|
1937
|
+
}
|
|
1872
1938
|
const parsedProof = core.parseProofForOnChain(response.proof, response.publicInputs, response.publicInputs.length);
|
|
1873
1939
|
// The response's verifierAddress and chainId are a claim to check, never
|
|
1874
1940
|
// the contract to call: whoever wrote the response would otherwise pick
|
|
@@ -1877,7 +1943,7 @@ class ProofportSDK {
|
|
|
1877
1943
|
return core.verifyProofOnChain(response.circuit, parsedProof, providerOrSigner, this.verifierTarget(response.circuit), {
|
|
1878
1944
|
verifierAddress: response.verifierAddress,
|
|
1879
1945
|
chainId: response.chainId,
|
|
1880
|
-
}, { request, signerVariant: response.signerVariant });
|
|
1946
|
+
}, { request, signerVariant: response.signerVariant, countryCondition });
|
|
1881
1947
|
}
|
|
1882
1948
|
/**
|
|
1883
1949
|
* Verifies a proof response off-chain, against the circuit's verification key.
|
|
@@ -1914,7 +1980,14 @@ class ProofportSDK {
|
|
|
1914
1980
|
return { valid: false, error: found.error };
|
|
1915
1981
|
request = found.request;
|
|
1916
1982
|
}
|
|
1917
|
-
|
|
1983
|
+
let countryCondition;
|
|
1984
|
+
if (response.circuit === 'coinbase_country_attestation') {
|
|
1985
|
+
const found = this.countryConditionFor(response, options?.countryCondition);
|
|
1986
|
+
if ('error' in found)
|
|
1987
|
+
return { valid: false, error: found.error };
|
|
1988
|
+
countryCondition = found.condition;
|
|
1989
|
+
}
|
|
1990
|
+
return verifyProofOffChain(response.circuit, response.proof, response.publicInputs, { ...options, request, countryCondition, signerVariant: response.signerVariant });
|
|
1918
1991
|
}
|
|
1919
1992
|
// ============ Utility Methods ============
|
|
1920
1993
|
/**
|
|
@@ -2292,6 +2365,16 @@ class ProofportSDK {
|
|
|
2292
2365
|
}
|
|
2293
2366
|
}
|
|
2294
2367
|
}
|
|
2368
|
+
// A Coinbase Country list the circuit would refuse is refused here, before a
|
|
2369
|
+
// challenge is burned, as createProofRequest does.
|
|
2370
|
+
if (circuit === 'coinbase_country_attestation') {
|
|
2371
|
+
const c = inputs;
|
|
2372
|
+
const listError = core.countryListError(c.countryList);
|
|
2373
|
+
if (listError)
|
|
2374
|
+
throw new Error(`${listError} (circuit: ${circuit})`);
|
|
2375
|
+
if (typeof c.isIncluded !== 'boolean')
|
|
2376
|
+
throw new Error('isIncluded is required for coinbase_country_attestation circuit');
|
|
2377
|
+
}
|
|
2295
2378
|
// Return target: validated before we burn a challenge, so a typo surfaces
|
|
2296
2379
|
// as a local error instead of a relay 400 on the second round trip.
|
|
2297
2380
|
if (options.returnScheme !== undefined) {
|
|
@@ -2347,6 +2430,8 @@ class ProofportSDK {
|
|
|
2347
2430
|
}
|
|
2348
2431
|
const created = await response.json();
|
|
2349
2432
|
this.rememberRelayRequest(created.requestId, scope);
|
|
2433
|
+
if (circuit === 'coinbase_country_attestation')
|
|
2434
|
+
this.rememberCountryRequest(created.requestId, inputs);
|
|
2350
2435
|
return created;
|
|
2351
2436
|
}
|
|
2352
2437
|
/**
|
|
@@ -2649,6 +2734,10 @@ Object.defineProperty(exports, "COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT", {
|
|
|
2649
2734
|
enumerable: true,
|
|
2650
2735
|
get: function () { return core.COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT; }
|
|
2651
2736
|
});
|
|
2737
|
+
Object.defineProperty(exports, "COINBASE_COUNTRY_PUBLIC_INPUT_COUNT", {
|
|
2738
|
+
enumerable: true,
|
|
2739
|
+
get: function () { return core.COINBASE_COUNTRY_PUBLIC_INPUT_COUNT; }
|
|
2740
|
+
});
|
|
2652
2741
|
Object.defineProperty(exports, "COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT", {
|
|
2653
2742
|
enumerable: true,
|
|
2654
2743
|
get: function () { return core.COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT; }
|