@did-btcr2/method 0.54.1 → 0.56.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/.tsbuildinfo +1 -1
- package/dist/browser.js +3 -3
- package/dist/browser.mjs +3 -3
- package/dist/cjs/index.js +251 -200
- package/dist/esm/core/beacon/signal-discovery.js +124 -38
- package/dist/esm/core/beacon/signal-discovery.js.map +1 -1
- package/dist/esm/core/beacon/utils.js +0 -10
- package/dist/esm/core/beacon/utils.js.map +1 -1
- package/dist/esm/core/resolver.js +42 -0
- package/dist/esm/core/resolver.js.map +1 -1
- package/dist/esm/utils/appendix.js +3 -2
- package/dist/esm/utils/appendix.js.map +1 -1
- package/dist/types/core/beacon/signal-discovery.d.ts +36 -9
- package/dist/types/core/beacon/signal-discovery.d.ts.map +1 -1
- package/dist/types/core/beacon/utils.d.ts +0 -6
- package/dist/types/core/beacon/utils.d.ts.map +1 -1
- package/dist/types/core/resolver.d.ts.map +1 -1
- package/dist/types/utils/appendix.d.ts +1 -1
- package/dist/types/utils/appendix.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/core/beacon/signal-discovery.ts +141 -42
- package/src/core/beacon/utils.ts +0 -13
- package/src/core/resolver.ts +49 -0
- package/src/utils/appendix.ts +3 -2
package/dist/cjs/index.js
CHANGED
|
@@ -60,7 +60,7 @@ __export(index_exports, {
|
|
|
60
60
|
buildAggregationBeaconTx: () => buildAggregationBeaconTx,
|
|
61
61
|
deriveSingletonAddress: () => deriveSingletonAddress,
|
|
62
62
|
detectSingletonScriptKind: () => detectSingletonScriptKind,
|
|
63
|
-
|
|
63
|
+
extractOpReturnSignalHash: () => extractOpReturnSignalHash,
|
|
64
64
|
getAggregationCommunicationKey: () => getAggregationCommunicationKey,
|
|
65
65
|
isMultikeyVerificationMethod: () => isMultikeyVerificationMethod,
|
|
66
66
|
opReturnScript: () => opReturnScript,
|
|
@@ -694,15 +694,16 @@ var BeaconFactory = class {
|
|
|
694
694
|
|
|
695
695
|
// src/core/beacon/signal-discovery.ts
|
|
696
696
|
var import_bitcoin3 = require("@did-btcr2/bitcoin");
|
|
697
|
-
var
|
|
697
|
+
var import_common9 = require("@did-btcr2/common");
|
|
698
698
|
|
|
699
699
|
// src/core/beacon/utils.ts
|
|
700
700
|
var import_bitcoin2 = require("@did-btcr2/bitcoin");
|
|
701
|
-
var
|
|
701
|
+
var import_common8 = require("@did-btcr2/common");
|
|
702
702
|
var import_btc_signer2 = require("@scure/btc-signer");
|
|
703
703
|
|
|
704
704
|
// src/utils/appendix.ts
|
|
705
705
|
var import_dids = require("@web5/dids");
|
|
706
|
+
var import_common6 = require("@did-btcr2/common");
|
|
706
707
|
var Appendix = class _Appendix {
|
|
707
708
|
/**
|
|
708
709
|
* Extracts a DID fragment from a given input
|
|
@@ -744,10 +745,10 @@ var Appendix = class _Appendix {
|
|
|
744
745
|
* Extracts the verification methods from a given DID Document.
|
|
745
746
|
* @param didDocument The DID Document to extract the verification methods from
|
|
746
747
|
* @returns An array of DidVerificationMethod objects
|
|
747
|
-
* @throws
|
|
748
|
+
* @throws {DidDocumentError} if the didDocument is not provided
|
|
748
749
|
*/
|
|
749
750
|
static getVerificationMethods(didDocument) {
|
|
750
|
-
if (!didDocument) throw new
|
|
751
|
+
if (!didDocument) throw new import_common6.DidDocumentError(`Required parameter missing: 'didDocument'`);
|
|
751
752
|
const verificationMethods = [];
|
|
752
753
|
verificationMethods.push(...didDocument.verificationMethod?.filter(_Appendix.isDidVerificationMethod) ?? []);
|
|
753
754
|
Object.keys(import_dids.DidVerificationRelationship).forEach((relationship) => {
|
|
@@ -851,7 +852,7 @@ var Appendix = class _Appendix {
|
|
|
851
852
|
};
|
|
852
853
|
|
|
853
854
|
// src/core/identifier.ts
|
|
854
|
-
var
|
|
855
|
+
var import_common7 = require("@did-btcr2/common");
|
|
855
856
|
var import_keypair = require("@did-btcr2/keypair");
|
|
856
857
|
var import_base = require("@scure/base");
|
|
857
858
|
var Identifier = class _Identifier {
|
|
@@ -871,33 +872,33 @@ var Identifier = class _Identifier {
|
|
|
871
872
|
*/
|
|
872
873
|
static encode(genesisBytes, options) {
|
|
873
874
|
const { idType, version = 1, network = "bitcoin" } = options;
|
|
874
|
-
if (!(idType in
|
|
875
|
-
throw new
|
|
875
|
+
if (!(idType in import_common7.IdentifierTypes)) {
|
|
876
|
+
throw new import_common7.IdentifierError('Expected "idType" to be "KEY" or "EXTERNAL"', import_common7.INVALID_DID, { idType });
|
|
876
877
|
}
|
|
877
878
|
if (version !== 1) {
|
|
878
|
-
throw new
|
|
879
|
+
throw new import_common7.IdentifierError('Expected "version" to be 1', import_common7.INVALID_DID, { version });
|
|
879
880
|
}
|
|
880
881
|
if (typeof network !== "string") {
|
|
881
|
-
throw new
|
|
882
|
+
throw new import_common7.IdentifierError('Expected "network" to be a known network name', import_common7.INVALID_DID, { network });
|
|
882
883
|
}
|
|
883
|
-
const networkValue =
|
|
884
|
+
const networkValue = import_common7.BitcoinNetworkNames[network];
|
|
884
885
|
if (networkValue === void 0) {
|
|
885
|
-
throw new
|
|
886
|
+
throw new import_common7.IdentifierError('Invalid "network" name', import_common7.INVALID_DID, { network });
|
|
886
887
|
}
|
|
887
888
|
if (idType === "KEY") {
|
|
888
889
|
try {
|
|
889
890
|
new import_keypair.CompressedSecp256k1PublicKey(genesisBytes);
|
|
890
891
|
} catch {
|
|
891
|
-
throw new
|
|
892
|
+
throw new import_common7.IdentifierError(
|
|
892
893
|
'Expected "genesisBytes" to be a valid compressed secp256k1 public key',
|
|
893
|
-
|
|
894
|
+
import_common7.INVALID_DID,
|
|
894
895
|
{ genesisBytes }
|
|
895
896
|
);
|
|
896
897
|
}
|
|
897
898
|
} else if (genesisBytes.length !== 32) {
|
|
898
|
-
throw new
|
|
899
|
+
throw new import_common7.IdentifierError(
|
|
899
900
|
'Expected "genesisBytes" to be a 32-byte hash for EXTERNAL identifiers',
|
|
900
|
-
|
|
901
|
+
import_common7.INVALID_DID,
|
|
901
902
|
{ genesisBytes }
|
|
902
903
|
);
|
|
903
904
|
}
|
|
@@ -917,50 +918,50 @@ var Identifier = class _Identifier {
|
|
|
917
918
|
static decode(identifier) {
|
|
918
919
|
const components = identifier.split(":");
|
|
919
920
|
if (components.length !== 3) {
|
|
920
|
-
throw new
|
|
921
|
+
throw new import_common7.IdentifierError(`Invalid did: ${identifier}`, import_common7.INVALID_DID, { identifier });
|
|
921
922
|
}
|
|
922
923
|
const [scheme, method, encoded] = components;
|
|
923
924
|
if (scheme !== "did") {
|
|
924
|
-
throw new
|
|
925
|
+
throw new import_common7.IdentifierError(`Invalid did: ${identifier}`, import_common7.INVALID_DID, { identifier });
|
|
925
926
|
}
|
|
926
927
|
if (method !== "btcr2") {
|
|
927
|
-
throw new
|
|
928
|
+
throw new import_common7.IdentifierError(`Invalid did method: ${method}`, import_common7.METHOD_NOT_SUPPORTED, { identifier });
|
|
928
929
|
}
|
|
929
930
|
if (!encoded) {
|
|
930
|
-
throw new
|
|
931
|
+
throw new import_common7.IdentifierError(`Invalid method-specific id: ${identifier}`, import_common7.INVALID_DID, { identifier });
|
|
931
932
|
}
|
|
932
933
|
const { prefix: hrp, bytes: dataBytes } = import_base.bech32m.decodeToBytes(encoded);
|
|
933
934
|
if (!["x", "k"].includes(hrp)) {
|
|
934
|
-
throw new
|
|
935
|
+
throw new import_common7.IdentifierError(`Invalid hrp: ${hrp}`, import_common7.INVALID_DID, { identifier });
|
|
935
936
|
}
|
|
936
937
|
if (!dataBytes || dataBytes.length < 1) {
|
|
937
|
-
throw new
|
|
938
|
+
throw new import_common7.IdentifierError(`Failed to decode id: ${encoded}`, import_common7.INVALID_DID, { identifier });
|
|
938
939
|
}
|
|
939
940
|
const idType = hrp === "k" ? "KEY" : "EXTERNAL";
|
|
940
941
|
const btcr2Version = dataBytes[0] >>> 4;
|
|
941
942
|
if (btcr2Version !== 0) {
|
|
942
|
-
throw new
|
|
943
|
+
throw new import_common7.IdentifierError(`Invalid btcr2_version (expected 0): ${btcr2Version}`, import_common7.INVALID_DID, { identifier });
|
|
943
944
|
}
|
|
944
945
|
const version = 1;
|
|
945
946
|
const networkValue = dataBytes[0] & 15;
|
|
946
|
-
const networkName =
|
|
947
|
+
const networkName = import_common7.BitcoinNetworkNames[networkValue];
|
|
947
948
|
let network;
|
|
948
949
|
if (typeof networkName === "string") {
|
|
949
950
|
network = networkName;
|
|
950
951
|
} else if (networkValue >= 12 && networkValue <= 14) {
|
|
951
952
|
network = networkValue - 11;
|
|
952
953
|
} else {
|
|
953
|
-
throw new
|
|
954
|
+
throw new import_common7.IdentifierError(`Invalid network: ${networkValue}`, import_common7.INVALID_DID, { identifier });
|
|
954
955
|
}
|
|
955
956
|
const genesisBytes = dataBytes.slice(1);
|
|
956
957
|
if (idType === "KEY") {
|
|
957
958
|
try {
|
|
958
959
|
new import_keypair.CompressedSecp256k1PublicKey(genesisBytes);
|
|
959
960
|
} catch {
|
|
960
|
-
throw new
|
|
961
|
+
throw new import_common7.IdentifierError(`Invalid genesisBytes: ${genesisBytes}`, import_common7.INVALID_DID, { identifier });
|
|
961
962
|
}
|
|
962
963
|
} else if (genesisBytes.length !== 32) {
|
|
963
|
-
throw new
|
|
964
|
+
throw new import_common7.IdentifierError(`Invalid genesisBytes: ${genesisBytes}`, import_common7.INVALID_DID, { identifier });
|
|
964
965
|
}
|
|
965
966
|
return { idType, hrp, version, network, genesisBytes };
|
|
966
967
|
}
|
|
@@ -989,9 +990,9 @@ var Identifier = class _Identifier {
|
|
|
989
990
|
static getPublicKey(did) {
|
|
990
991
|
const { idType, genesisBytes } = _Identifier.decode(did);
|
|
991
992
|
if (idType !== "KEY") {
|
|
992
|
-
throw new
|
|
993
|
+
throw new import_common7.IdentifierError(
|
|
993
994
|
`Cannot extract public key from EXTERNAL DID: ${did}. EXTERNAL DIDs encode a document hash, not a public key.`,
|
|
994
|
-
|
|
995
|
+
import_common7.INVALID_DID,
|
|
995
996
|
{ did, idType }
|
|
996
997
|
);
|
|
997
998
|
}
|
|
@@ -1022,7 +1023,7 @@ var BeaconUtils = class {
|
|
|
1022
1023
|
*/
|
|
1023
1024
|
static parseBitcoinAddress(uri) {
|
|
1024
1025
|
if (!uri.startsWith("bitcoin:")) {
|
|
1025
|
-
throw new
|
|
1026
|
+
throw new import_common8.MethodError("Invalid Bitcoin URI format", "BEACON_SERVICE_ERROR", { uri });
|
|
1026
1027
|
}
|
|
1027
1028
|
return uri.replace("bitcoin:", "").split("?")[0];
|
|
1028
1029
|
}
|
|
@@ -1103,7 +1104,7 @@ var BeaconUtils = class {
|
|
|
1103
1104
|
const p2wpkhAddr = (0, import_btc_signer2.p2wpkh)(publicKey, network).address;
|
|
1104
1105
|
const p2trAddr = (0, import_btc_signer2.p2tr)(publicKey.slice(1, 33), void 0, network).address;
|
|
1105
1106
|
if (!p2pkhAddr || !p2wpkhAddr || !p2trAddr) {
|
|
1106
|
-
throw new
|
|
1107
|
+
throw new import_common8.DidMethodError("Failed to generate bitcoin addresses");
|
|
1107
1108
|
}
|
|
1108
1109
|
return [
|
|
1109
1110
|
{
|
|
@@ -1138,16 +1139,6 @@ var BeaconUtils = class {
|
|
|
1138
1139
|
static parseBeaconServiceEndpoint(beacon) {
|
|
1139
1140
|
return { ...beacon, serviceEndpoint: beacon.serviceEndpoint.replace("bitcoin:", "") };
|
|
1140
1141
|
}
|
|
1141
|
-
/**
|
|
1142
|
-
* Create a map of address => beaconService with address field.
|
|
1143
|
-
* @param {Array<BeaconService>} beacons The list of beacon services.
|
|
1144
|
-
* @returns {Map<string, BeaconService>} A map of address => beaconService.
|
|
1145
|
-
*/
|
|
1146
|
-
static getBeaconServicesMap(beacons) {
|
|
1147
|
-
return new Map(
|
|
1148
|
-
beacons.map(this.parseBeaconServiceEndpoint).map((beacon) => [beacon.serviceEndpoint, beacon])
|
|
1149
|
-
);
|
|
1150
|
-
}
|
|
1151
1142
|
/**
|
|
1152
1143
|
* Get the beacon service ids from a list of beacon services.
|
|
1153
1144
|
* @param {DidDocument} didDocument The DID Document to extract the services from.
|
|
@@ -1159,21 +1150,53 @@ var BeaconUtils = class {
|
|
|
1159
1150
|
};
|
|
1160
1151
|
|
|
1161
1152
|
// src/core/beacon/signal-discovery.ts
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
}
|
|
1166
|
-
const tokens = asm.trim().split(/\s+/);
|
|
1167
|
-
if (tokens.length !== 3 || tokens[0] !== "OP_RETURN" || tokens[1] !== "OP_PUSHBYTES_32") {
|
|
1153
|
+
var BEACON_SIGNAL_SCRIPT = /^6a20([0-9a-f]{64})$/i;
|
|
1154
|
+
function extractOpReturnSignalHash(scriptPubKey) {
|
|
1155
|
+
if (!scriptPubKey) {
|
|
1168
1156
|
return null;
|
|
1169
1157
|
}
|
|
1170
|
-
const
|
|
1171
|
-
if (
|
|
1158
|
+
const signal = BEACON_SIGNAL_SCRIPT.exec(scriptPubKey.trim());
|
|
1159
|
+
if (!signal) {
|
|
1172
1160
|
return null;
|
|
1173
1161
|
}
|
|
1174
|
-
return
|
|
1162
|
+
return signal[1].toLowerCase();
|
|
1175
1163
|
}
|
|
1176
|
-
var BeaconSignalDiscovery = class {
|
|
1164
|
+
var BeaconSignalDiscovery = class _BeaconSignalDiscovery {
|
|
1165
|
+
/**
|
|
1166
|
+
* Determines whether a candidate transaction spends an output controlled by the given
|
|
1167
|
+
* beacon address.
|
|
1168
|
+
*
|
|
1169
|
+
* A Beacon Signal is a transaction that *spends from* a Beacon Address, but an address
|
|
1170
|
+
* transaction listing returns every transaction touching the address in either
|
|
1171
|
+
* direction. Without this check, anyone able to pay dust to a beacon address could
|
|
1172
|
+
* attach an arbitrary 32-byte OP_RETURN and have it read as a signal, so the input side
|
|
1173
|
+
* has to be inspected before a transaction is treated as one.
|
|
1174
|
+
*
|
|
1175
|
+
* Esplora embeds the spent output in `vin[].prevout`; when a backend omits it the
|
|
1176
|
+
* funding transaction is fetched instead, so a missing field cannot silently drop a
|
|
1177
|
+
* real signal.
|
|
1178
|
+
*
|
|
1179
|
+
* @param {RawTransactionRest} tx The candidate transaction.
|
|
1180
|
+
* @param {string} address The beacon address the transaction must spend from.
|
|
1181
|
+
* @param {BitcoinConnection} bitcoin Bitcoin network connection to use for REST calls.
|
|
1182
|
+
* @returns {Promise<boolean>} True if at least one input spends an output of the beacon address.
|
|
1183
|
+
*/
|
|
1184
|
+
static async spendsFromAddress(tx, address, bitcoin) {
|
|
1185
|
+
for (const vin of tx.vin ?? []) {
|
|
1186
|
+
if (vin.is_coinbase) {
|
|
1187
|
+
continue;
|
|
1188
|
+
}
|
|
1189
|
+
let prevout = vin.prevout;
|
|
1190
|
+
if (!prevout && vin.txid) {
|
|
1191
|
+
const fundingTx = await bitcoin.rest.transaction.get(vin.txid);
|
|
1192
|
+
prevout = fundingTx?.vout?.[vin.vout];
|
|
1193
|
+
}
|
|
1194
|
+
if (prevout?.scriptpubkey_address === address) {
|
|
1195
|
+
return true;
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
return false;
|
|
1199
|
+
}
|
|
1177
1200
|
/**
|
|
1178
1201
|
* Retrieves the beacon signals for the given array of BeaconService objects
|
|
1179
1202
|
* using an esplora/electrs REST API connection via a bitcoin I/O driver.
|
|
@@ -1186,21 +1209,23 @@ var BeaconSignalDiscovery = class {
|
|
|
1186
1209
|
const currentBlockCount = await bitcoin.rest.block.count();
|
|
1187
1210
|
for (const beaconService of beaconServices) {
|
|
1188
1211
|
beaconServiceSignals.set(beaconService, []);
|
|
1189
|
-
const
|
|
1190
|
-
|
|
1191
|
-
);
|
|
1212
|
+
const beaconAddress = BeaconUtils.parseBitcoinAddress(beaconService.serviceEndpoint);
|
|
1213
|
+
const beaconSignals = await bitcoin.rest.address.getTxs(beaconAddress);
|
|
1192
1214
|
if (!beaconSignals || !beaconSignals.length) {
|
|
1193
1215
|
continue;
|
|
1194
1216
|
}
|
|
1195
1217
|
for (const beaconSignal of beaconSignals) {
|
|
1196
|
-
const
|
|
1197
|
-
if (!
|
|
1218
|
+
const lastSignalVout = beaconSignal.vout.slice(-1)[0];
|
|
1219
|
+
if (!lastSignalVout) {
|
|
1198
1220
|
continue;
|
|
1199
1221
|
}
|
|
1200
|
-
const updateHash =
|
|
1222
|
+
const updateHash = extractOpReturnSignalHash(lastSignalVout.scriptpubkey);
|
|
1201
1223
|
if (!updateHash) {
|
|
1202
1224
|
continue;
|
|
1203
1225
|
}
|
|
1226
|
+
if (!await _BeaconSignalDiscovery.spendsFromAddress(beaconSignal, beaconAddress, bitcoin)) {
|
|
1227
|
+
continue;
|
|
1228
|
+
}
|
|
1204
1229
|
const confirmations = currentBlockCount - beaconSignal.status.block_height + 1;
|
|
1205
1230
|
beaconServiceSignals.get(beaconService)?.push({
|
|
1206
1231
|
tx: beaconSignal,
|
|
@@ -1228,10 +1253,12 @@ var BeaconSignalDiscovery = class {
|
|
|
1228
1253
|
}
|
|
1229
1254
|
const rpc = bitcoin.rpc;
|
|
1230
1255
|
if (!rpc) {
|
|
1231
|
-
throw new
|
|
1256
|
+
throw new import_common9.ResolveError("RPC connection is not available", "RPC_CONNECTION_ERROR", bitcoin);
|
|
1232
1257
|
}
|
|
1233
1258
|
const targetHeight = await rpc.getBlockCount();
|
|
1234
|
-
const beaconServicesMap =
|
|
1259
|
+
const beaconServicesMap = new Map(
|
|
1260
|
+
beaconServices.map((service) => [BeaconUtils.parseBitcoinAddress(service.serviceEndpoint), service])
|
|
1261
|
+
);
|
|
1235
1262
|
let height = 0;
|
|
1236
1263
|
let block = await bitcoin.rpc.getBlock({ height });
|
|
1237
1264
|
console.info(`Searching for beacon signals, please wait ...`);
|
|
@@ -1240,6 +1267,15 @@ var BeaconSignalDiscovery = class {
|
|
|
1240
1267
|
if (tx.txid === import_bitcoin3.GENESIS_TX_ID) {
|
|
1241
1268
|
continue;
|
|
1242
1269
|
}
|
|
1270
|
+
const lastSignalVout = tx.vout.slice(-1)[0];
|
|
1271
|
+
if (!lastSignalVout) {
|
|
1272
|
+
continue;
|
|
1273
|
+
}
|
|
1274
|
+
const updateHash = extractOpReturnSignalHash(lastSignalVout.scriptPubKey?.hex);
|
|
1275
|
+
if (!updateHash) {
|
|
1276
|
+
continue;
|
|
1277
|
+
}
|
|
1278
|
+
const signaled = /* @__PURE__ */ new Set();
|
|
1243
1279
|
for (const vin of tx.vin) {
|
|
1244
1280
|
if (vin.coinbase) {
|
|
1245
1281
|
continue;
|
|
@@ -1262,15 +1298,11 @@ var BeaconSignalDiscovery = class {
|
|
|
1262
1298
|
continue;
|
|
1263
1299
|
}
|
|
1264
1300
|
const beaconService = beaconServicesMap.get(scriptPubKey.address);
|
|
1265
|
-
if (!beaconService) {
|
|
1266
|
-
continue;
|
|
1267
|
-
}
|
|
1268
|
-
const txVoutScriptPubkeyAsm = prevout.vout[vin.vout].scriptPubKey.asm;
|
|
1269
|
-
const updateHash = extractOpReturnSignal(txVoutScriptPubkeyAsm);
|
|
1270
|
-
if (!updateHash) {
|
|
1301
|
+
if (!beaconService || signaled.has(beaconService)) {
|
|
1271
1302
|
continue;
|
|
1272
1303
|
}
|
|
1273
|
-
|
|
1304
|
+
signaled.add(beaconService);
|
|
1305
|
+
console.info(`Tx ${tx.txid} contains beacon address ${scriptPubKey.address}`);
|
|
1274
1306
|
beaconServiceSignals.get(beaconService)?.push({
|
|
1275
1307
|
tx,
|
|
1276
1308
|
signalBytes: updateHash,
|
|
@@ -1295,27 +1327,27 @@ var BeaconSignalDiscovery = class {
|
|
|
1295
1327
|
};
|
|
1296
1328
|
|
|
1297
1329
|
// src/core/did-sender-resolver.ts
|
|
1298
|
-
var
|
|
1330
|
+
var import_common14 = require("@did-btcr2/common");
|
|
1299
1331
|
var import_cryptosuite3 = require("@did-btcr2/cryptosuite");
|
|
1300
1332
|
var import_keypair4 = require("@did-btcr2/keypair");
|
|
1301
1333
|
|
|
1302
1334
|
// src/core/resolver.ts
|
|
1303
1335
|
var import_bitcoin5 = require("@did-btcr2/bitcoin");
|
|
1304
|
-
var
|
|
1336
|
+
var import_common13 = require("@did-btcr2/common");
|
|
1305
1337
|
var import_cryptosuite2 = require("@did-btcr2/cryptosuite");
|
|
1306
1338
|
var import_keypair3 = require("@did-btcr2/keypair");
|
|
1307
1339
|
|
|
1308
1340
|
// src/did-btcr2.ts
|
|
1309
|
-
var
|
|
1341
|
+
var import_common12 = require("@did-btcr2/common");
|
|
1310
1342
|
var import_dids2 = require("@web5/dids");
|
|
1311
1343
|
|
|
1312
1344
|
// src/core/updater.ts
|
|
1313
|
-
var
|
|
1345
|
+
var import_common11 = require("@did-btcr2/common");
|
|
1314
1346
|
var import_cryptosuite = require("@did-btcr2/cryptosuite");
|
|
1315
1347
|
|
|
1316
1348
|
// src/utils/did-document.ts
|
|
1317
1349
|
var import_bitcoin4 = require("@did-btcr2/bitcoin");
|
|
1318
|
-
var
|
|
1350
|
+
var import_common10 = require("@did-btcr2/common");
|
|
1319
1351
|
var import_keypair2 = require("@did-btcr2/keypair");
|
|
1320
1352
|
var import_utils4 = require("@web5/dids/utils");
|
|
1321
1353
|
var import_btc_signer3 = require("@scure/btc-signer");
|
|
@@ -1343,16 +1375,16 @@ var DidVerificationMethod = class {
|
|
|
1343
1375
|
secretKeyMultibase;
|
|
1344
1376
|
constructor({ id, type, controller, publicKeyMultibase, secretKeyMultibase }) {
|
|
1345
1377
|
if (type !== MULTIKEY_VERIFICATION_METHOD_TYPE) {
|
|
1346
|
-
throw new
|
|
1378
|
+
throw new import_common10.DidDocumentError(
|
|
1347
1379
|
`Invalid verification method: type must be "${MULTIKEY_VERIFICATION_METHOD_TYPE}"`,
|
|
1348
|
-
|
|
1380
|
+
import_common10.INVALID_DID_DOCUMENT,
|
|
1349
1381
|
{ id, type }
|
|
1350
1382
|
);
|
|
1351
1383
|
}
|
|
1352
1384
|
if (typeof publicKeyMultibase !== "string" || !publicKeyMultibase.startsWith(MULTIKEY_PUBLIC_KEY_MULTIBASE_PREFIX)) {
|
|
1353
|
-
throw new
|
|
1385
|
+
throw new import_common10.DidDocumentError(
|
|
1354
1386
|
`Invalid verification method: publicKeyMultibase must start with "${MULTIKEY_PUBLIC_KEY_MULTIBASE_PREFIX}"`,
|
|
1355
|
-
|
|
1387
|
+
import_common10.INVALID_DID_DOCUMENT,
|
|
1356
1388
|
{ id, publicKeyMultibase }
|
|
1357
1389
|
);
|
|
1358
1390
|
}
|
|
@@ -1382,20 +1414,20 @@ var DidDocument = class _DidDocument {
|
|
|
1382
1414
|
deactivated;
|
|
1383
1415
|
constructor(document) {
|
|
1384
1416
|
if (!document.id) {
|
|
1385
|
-
throw new
|
|
1417
|
+
throw new import_common10.DidDocumentError("DID Document must have an id", import_common10.INVALID_DID_DOCUMENT, document);
|
|
1386
1418
|
}
|
|
1387
|
-
const idType = document.id.includes("k1") ?
|
|
1419
|
+
const idType = document.id.includes("k1") ? import_common10.IdentifierTypes.KEY : import_common10.IdentifierTypes.EXTERNAL;
|
|
1388
1420
|
const isGenesis = document.id === ID_PLACEHOLDER_VALUE;
|
|
1389
1421
|
const { id, verificationMethod: vm, service } = document;
|
|
1390
1422
|
if (!isGenesis) {
|
|
1391
1423
|
if (!_DidDocument.isValidId(id)) {
|
|
1392
|
-
throw new
|
|
1424
|
+
throw new import_common10.DidDocumentError(`Invalid id: ${id}`, import_common10.INVALID_DID_DOCUMENT, document);
|
|
1393
1425
|
}
|
|
1394
1426
|
if (!_DidDocument.isValidVerificationMethods(vm)) {
|
|
1395
|
-
throw new
|
|
1427
|
+
throw new import_common10.DidDocumentError("Invalid verificationMethod: " + vm, import_common10.INVALID_DID_DOCUMENT, document);
|
|
1396
1428
|
}
|
|
1397
1429
|
if (!_DidDocument.isValidServices(service)) {
|
|
1398
|
-
throw new
|
|
1430
|
+
throw new import_common10.DidDocumentError("Invalid service: " + service, import_common10.INVALID_DID_DOCUMENT, document);
|
|
1399
1431
|
}
|
|
1400
1432
|
}
|
|
1401
1433
|
this.id = document.id;
|
|
@@ -1405,7 +1437,7 @@ var DidDocument = class _DidDocument {
|
|
|
1405
1437
|
"https://www.w3.org/ns/did/v1.1",
|
|
1406
1438
|
"https://btcr2.dev/context/v1"
|
|
1407
1439
|
];
|
|
1408
|
-
if (idType ===
|
|
1440
|
+
if (idType === import_common10.IdentifierTypes.KEY) {
|
|
1409
1441
|
const keyRef = `${this.id}#initialKey`;
|
|
1410
1442
|
this.authentication = document.authentication || [keyRef];
|
|
1411
1443
|
this.assertionMethod = document.assertionMethod || [keyRef];
|
|
@@ -1491,19 +1523,19 @@ var DidDocument = class _DidDocument {
|
|
|
1491
1523
|
*/
|
|
1492
1524
|
static isValid(didDocument) {
|
|
1493
1525
|
if (!this.isValidContext(didDocument?.["@context"])) {
|
|
1494
|
-
throw new
|
|
1526
|
+
throw new import_common10.DidDocumentError('Invalid "@context"', import_common10.INVALID_DID_DOCUMENT, didDocument);
|
|
1495
1527
|
}
|
|
1496
1528
|
if (!this.isValidId(didDocument?.id)) {
|
|
1497
|
-
throw new
|
|
1529
|
+
throw new import_common10.DidDocumentError('Invalid "id"', import_common10.INVALID_DID_DOCUMENT, didDocument);
|
|
1498
1530
|
}
|
|
1499
1531
|
if (!this.isValidVerificationMethods(didDocument?.verificationMethod)) {
|
|
1500
|
-
throw new
|
|
1532
|
+
throw new import_common10.DidDocumentError('Invalid "verificationMethod"', import_common10.INVALID_DID_DOCUMENT, didDocument);
|
|
1501
1533
|
}
|
|
1502
1534
|
if (!this.isValidServices(didDocument?.service)) {
|
|
1503
|
-
throw new
|
|
1535
|
+
throw new import_common10.DidDocumentError('Invalid "service"', import_common10.INVALID_DID_DOCUMENT, didDocument);
|
|
1504
1536
|
}
|
|
1505
1537
|
if (!this.isValidVerificationRelationships(didDocument)) {
|
|
1506
|
-
throw new
|
|
1538
|
+
throw new import_common10.DidDocumentError("Invalid verification relationships", import_common10.INVALID_DID_DOCUMENT, didDocument);
|
|
1507
1539
|
}
|
|
1508
1540
|
return true;
|
|
1509
1541
|
}
|
|
@@ -1591,16 +1623,16 @@ var DidDocument = class _DidDocument {
|
|
|
1591
1623
|
*/
|
|
1592
1624
|
validateGenesis() {
|
|
1593
1625
|
if (this.id !== ID_PLACEHOLDER_VALUE) {
|
|
1594
|
-
throw new
|
|
1626
|
+
throw new import_common10.DidDocumentError("Invalid GenesisDocument ID", import_common10.INVALID_DID_DOCUMENT, this);
|
|
1595
1627
|
}
|
|
1596
1628
|
if (!this.verificationMethod.every((vm) => vm.id.includes(ID_PLACEHOLDER_VALUE) && vm.controller === ID_PLACEHOLDER_VALUE)) {
|
|
1597
|
-
throw new
|
|
1629
|
+
throw new import_common10.DidDocumentError("Invalid GenesisDocument verificationMethod", import_common10.INVALID_DID_DOCUMENT, this);
|
|
1598
1630
|
}
|
|
1599
1631
|
if (!this.service.every((svc) => svc.id.includes(ID_PLACEHOLDER_VALUE))) {
|
|
1600
|
-
throw new
|
|
1632
|
+
throw new import_common10.DidDocumentError("Invalid GenesisDocument service", import_common10.INVALID_DID_DOCUMENT, this);
|
|
1601
1633
|
}
|
|
1602
1634
|
if (!_DidDocument.isValidVerificationRelationships(this)) {
|
|
1603
|
-
throw new
|
|
1635
|
+
throw new import_common10.DidDocumentError("Invalid GenesisDocument assertionMethod", import_common10.INVALID_DID_DOCUMENT, this);
|
|
1604
1636
|
}
|
|
1605
1637
|
return true;
|
|
1606
1638
|
}
|
|
@@ -1610,7 +1642,7 @@ var DidDocument = class _DidDocument {
|
|
|
1610
1642
|
*/
|
|
1611
1643
|
toIntermediate() {
|
|
1612
1644
|
if (this.id.includes("k1")) {
|
|
1613
|
-
throw new
|
|
1645
|
+
throw new import_common10.DidDocumentError("Cannot convert a key identifier to an intermediate document", import_common10.INVALID_DID_DOCUMENT, this);
|
|
1614
1646
|
}
|
|
1615
1647
|
return new GenesisDocument(this);
|
|
1616
1648
|
}
|
|
@@ -1635,7 +1667,7 @@ var GenesisDocument = class _GenesisDocument extends DidDocument {
|
|
|
1635
1667
|
* @returns {GenesisDocument} The GenesisDocument representation of the DidDocument.
|
|
1636
1668
|
*/
|
|
1637
1669
|
static fromDidDocument(didDocument) {
|
|
1638
|
-
const intermediateDocument =
|
|
1670
|
+
const intermediateDocument = import_common10.JSONUtils.cloneReplace(didDocument, DID_REGEX, ID_PLACEHOLDER_VALUE);
|
|
1639
1671
|
return new _GenesisDocument(intermediateDocument);
|
|
1640
1672
|
}
|
|
1641
1673
|
/**
|
|
@@ -1692,7 +1724,7 @@ var GenesisDocument = class _GenesisDocument extends DidDocument {
|
|
|
1692
1724
|
* @returns {Bytes} The genesis bytes.
|
|
1693
1725
|
*/
|
|
1694
1726
|
static toGenesisBytes(genesisDocument) {
|
|
1695
|
-
return (0,
|
|
1727
|
+
return (0, import_common10.hash)((0, import_common10.canonicalize)(genesisDocument));
|
|
1696
1728
|
}
|
|
1697
1729
|
};
|
|
1698
1730
|
|
|
@@ -1737,26 +1769,26 @@ var Updater = class _Updater {
|
|
|
1737
1769
|
patch: patches,
|
|
1738
1770
|
targetHash: "",
|
|
1739
1771
|
targetVersionId: sourceVersionId + 1,
|
|
1740
|
-
sourceHash: (0,
|
|
1772
|
+
sourceHash: (0, import_common11.canonicalHash)(sourceDocument)
|
|
1741
1773
|
};
|
|
1742
|
-
const targetDocument =
|
|
1774
|
+
const targetDocument = import_common11.JSONPatch.apply(sourceDocument, patches);
|
|
1743
1775
|
if (targetDocument.id !== sourceDocument.id) {
|
|
1744
|
-
throw new
|
|
1776
|
+
throw new import_common11.UpdateError(
|
|
1745
1777
|
`Patches must not change the DID document id (source "${sourceDocument.id}" to target "${targetDocument.id}").`,
|
|
1746
|
-
|
|
1778
|
+
import_common11.INVALID_DID_UPDATE,
|
|
1747
1779
|
{ sourceId: sourceDocument.id, targetId: targetDocument.id }
|
|
1748
1780
|
);
|
|
1749
1781
|
}
|
|
1750
1782
|
try {
|
|
1751
1783
|
DidDocument.isValid(targetDocument);
|
|
1752
1784
|
} catch (error) {
|
|
1753
|
-
throw new
|
|
1785
|
+
throw new import_common11.UpdateError(
|
|
1754
1786
|
"Error validating targetDocument: " + (error instanceof Error ? error.message : String(error)),
|
|
1755
|
-
|
|
1787
|
+
import_common11.INVALID_DID_UPDATE,
|
|
1756
1788
|
targetDocument
|
|
1757
1789
|
);
|
|
1758
1790
|
}
|
|
1759
|
-
unsignedUpdate.targetHash = (0,
|
|
1791
|
+
unsignedUpdate.targetHash = (0, import_common11.canonicalHash)(targetDocument);
|
|
1760
1792
|
return unsignedUpdate;
|
|
1761
1793
|
}
|
|
1762
1794
|
/**
|
|
@@ -1770,18 +1802,18 @@ var Updater = class _Updater {
|
|
|
1770
1802
|
*/
|
|
1771
1803
|
static sign(did, unsignedUpdate, verificationMethod, signer) {
|
|
1772
1804
|
if (!did.startsWith("did:btcr2:")) {
|
|
1773
|
-
throw new
|
|
1805
|
+
throw new import_common11.UpdateError(
|
|
1774
1806
|
`Expected a did:btcr2 identifier for the root capability; got "${did}".`,
|
|
1775
|
-
|
|
1807
|
+
import_common11.INVALID_DID_UPDATE,
|
|
1776
1808
|
{ did }
|
|
1777
1809
|
);
|
|
1778
1810
|
}
|
|
1779
1811
|
const controller = verificationMethod.controller;
|
|
1780
1812
|
const hashIdx = verificationMethod.id.indexOf("#");
|
|
1781
1813
|
if (hashIdx < 0) {
|
|
1782
|
-
throw new
|
|
1814
|
+
throw new import_common11.UpdateError(
|
|
1783
1815
|
`Verification method id must contain a fragment (e.g. "${verificationMethod.id}#initialKey"); got "${verificationMethod.id}".`,
|
|
1784
|
-
|
|
1816
|
+
import_common11.INVALID_DID_UPDATE,
|
|
1785
1817
|
{ verificationMethodId: verificationMethod.id }
|
|
1786
1818
|
);
|
|
1787
1819
|
}
|
|
@@ -1789,9 +1821,9 @@ var Updater = class _Updater {
|
|
|
1789
1821
|
const multikey = import_cryptosuite.SchnorrMultikey.fromSigner(id, controller, signer);
|
|
1790
1822
|
const signerKey = multikey.publicKey.multibase.encoded;
|
|
1791
1823
|
if (verificationMethod.publicKeyMultibase && signerKey !== verificationMethod.publicKeyMultibase) {
|
|
1792
|
-
throw new
|
|
1824
|
+
throw new import_common11.UpdateError(
|
|
1793
1825
|
`Signing key does not match verification method "${verificationMethod.id}": the signer's public key differs from the method's published publicKeyMultibase.`,
|
|
1794
|
-
|
|
1826
|
+
import_common11.INVALID_DID_UPDATE,
|
|
1795
1827
|
{
|
|
1796
1828
|
verificationMethodId: verificationMethod.id,
|
|
1797
1829
|
expected: verificationMethod.publicKeyMultibase,
|
|
@@ -1908,16 +1940,16 @@ var Updater = class _Updater {
|
|
|
1908
1940
|
switch (need.kind) {
|
|
1909
1941
|
case "NeedSigningKey": {
|
|
1910
1942
|
if (this.#state.phase !== "Sign") {
|
|
1911
|
-
throw new
|
|
1943
|
+
throw new import_common11.UpdateError(
|
|
1912
1944
|
`Cannot provide NeedSigningKey: updater phase is ${this.#state.phase}, expected Sign.`,
|
|
1913
|
-
|
|
1945
|
+
import_common11.INVALID_DID_UPDATE,
|
|
1914
1946
|
{ phase: this.#state.phase }
|
|
1915
1947
|
);
|
|
1916
1948
|
}
|
|
1917
1949
|
if (!data) {
|
|
1918
|
-
throw new
|
|
1950
|
+
throw new import_common11.UpdateError(
|
|
1919
1951
|
"NeedSigningKey requires a Signer.",
|
|
1920
|
-
|
|
1952
|
+
import_common11.INVALID_DID_UPDATE
|
|
1921
1953
|
);
|
|
1922
1954
|
}
|
|
1923
1955
|
const unsignedUpdate = this.#state.unsignedUpdate;
|
|
@@ -1932,18 +1964,18 @@ var Updater = class _Updater {
|
|
|
1932
1964
|
}
|
|
1933
1965
|
case "NeedFunding": {
|
|
1934
1966
|
if (this.#state.phase !== "Fund") {
|
|
1935
|
-
throw new
|
|
1967
|
+
throw new import_common11.UpdateError(
|
|
1936
1968
|
`Cannot provide NeedFunding: updater phase is ${this.#state.phase}, expected Fund.`,
|
|
1937
|
-
|
|
1969
|
+
import_common11.INVALID_DID_UPDATE,
|
|
1938
1970
|
{ phase: this.#state.phase }
|
|
1939
1971
|
);
|
|
1940
1972
|
}
|
|
1941
1973
|
if (data !== void 0) {
|
|
1942
1974
|
const proof = data;
|
|
1943
1975
|
if (typeof proof.utxoCount !== "number" || !Number.isFinite(proof.utxoCount) || proof.utxoCount < 1) {
|
|
1944
|
-
throw new
|
|
1976
|
+
throw new import_common11.UpdateError(
|
|
1945
1977
|
`NeedFunding proof must have utxoCount >= 1; got ${String(proof.utxoCount)}.`,
|
|
1946
|
-
|
|
1978
|
+
import_common11.INVALID_DID_UPDATE,
|
|
1947
1979
|
{ utxoCount: proof.utxoCount }
|
|
1948
1980
|
);
|
|
1949
1981
|
}
|
|
@@ -1957,9 +1989,9 @@ var Updater = class _Updater {
|
|
|
1957
1989
|
}
|
|
1958
1990
|
case "NeedBroadcast": {
|
|
1959
1991
|
if (this.#state.phase !== "Broadcast") {
|
|
1960
|
-
throw new
|
|
1992
|
+
throw new import_common11.UpdateError(
|
|
1961
1993
|
`Cannot provide NeedBroadcast: updater phase is ${this.#state.phase}, expected Broadcast.`,
|
|
1962
|
-
|
|
1994
|
+
import_common11.INVALID_DID_UPDATE,
|
|
1963
1995
|
{ phase: this.#state.phase }
|
|
1964
1996
|
);
|
|
1965
1997
|
}
|
|
@@ -1995,9 +2027,9 @@ var DidBtcr2 = class {
|
|
|
1995
2027
|
static create(genesisBytes, options) {
|
|
1996
2028
|
const { idType, version = 1, network = "bitcoin" } = options || {};
|
|
1997
2029
|
if (!idType) {
|
|
1998
|
-
throw new
|
|
2030
|
+
throw new import_common12.MethodError(
|
|
1999
2031
|
"idType is required for creating a did:btcr2 identifier",
|
|
2000
|
-
|
|
2032
|
+
import_common12.INVALID_DID_DOCUMENT,
|
|
2001
2033
|
options
|
|
2002
2034
|
);
|
|
2003
2035
|
}
|
|
@@ -2027,7 +2059,7 @@ var DidBtcr2 = class {
|
|
|
2027
2059
|
static resolve(did, resolutionOptions = {}) {
|
|
2028
2060
|
const didComponents = Identifier.decode(did);
|
|
2029
2061
|
const sidecarData = Resolver.sidecarData(resolutionOptions.sidecar);
|
|
2030
|
-
const currentDocument = didComponents.hrp ===
|
|
2062
|
+
const currentDocument = didComponents.hrp === import_common12.IdentifierHrp.k ? Resolver.deterministic(didComponents) : null;
|
|
2031
2063
|
return new Resolver(didComponents, sidecarData, currentDocument, {
|
|
2032
2064
|
versionId: resolutionOptions.versionId,
|
|
2033
2065
|
versionTime: resolutionOptions.versionTime,
|
|
@@ -2066,39 +2098,39 @@ var DidBtcr2 = class {
|
|
|
2066
2098
|
beaconId
|
|
2067
2099
|
}) {
|
|
2068
2100
|
if (!sourceDocument.capabilityInvocation?.some((vr) => vr === verificationMethodId)) {
|
|
2069
|
-
throw new
|
|
2101
|
+
throw new import_common12.UpdateError(
|
|
2070
2102
|
"Invalid verificationMethodId: not authorized for capabilityInvocation",
|
|
2071
|
-
|
|
2103
|
+
import_common12.INVALID_DID_DOCUMENT,
|
|
2072
2104
|
sourceDocument
|
|
2073
2105
|
);
|
|
2074
2106
|
}
|
|
2075
2107
|
const verificationMethod = this.getSigningMethod(sourceDocument, verificationMethodId);
|
|
2076
2108
|
if (!verificationMethod) {
|
|
2077
|
-
throw new
|
|
2109
|
+
throw new import_common12.UpdateError(
|
|
2078
2110
|
"Invalid verificationMethod: not found in source document",
|
|
2079
|
-
|
|
2111
|
+
import_common12.INVALID_DID_DOCUMENT,
|
|
2080
2112
|
{ sourceDocument, verificationMethodId }
|
|
2081
2113
|
);
|
|
2082
2114
|
}
|
|
2083
2115
|
if (verificationMethod.type !== MULTIKEY_VERIFICATION_METHOD_TYPE) {
|
|
2084
|
-
throw new
|
|
2116
|
+
throw new import_common12.UpdateError(
|
|
2085
2117
|
`Invalid verificationMethod: verificationMethod.type must be "${MULTIKEY_VERIFICATION_METHOD_TYPE}"`,
|
|
2086
|
-
|
|
2118
|
+
import_common12.INVALID_DID_DOCUMENT,
|
|
2087
2119
|
verificationMethod
|
|
2088
2120
|
);
|
|
2089
2121
|
}
|
|
2090
2122
|
if (!verificationMethod.publicKeyMultibase?.startsWith(MULTIKEY_PUBLIC_KEY_MULTIBASE_PREFIX)) {
|
|
2091
|
-
throw new
|
|
2123
|
+
throw new import_common12.UpdateError(
|
|
2092
2124
|
`Invalid verificationMethodId: publicKeyMultibase prefix must start with "${MULTIKEY_PUBLIC_KEY_MULTIBASE_PREFIX}"`,
|
|
2093
|
-
|
|
2125
|
+
import_common12.INVALID_DID_DOCUMENT,
|
|
2094
2126
|
verificationMethod
|
|
2095
2127
|
);
|
|
2096
2128
|
}
|
|
2097
2129
|
const beaconService = sourceDocument.service.filter((service) => service.id === beaconId).filter((service) => !!service).shift();
|
|
2098
2130
|
if (!beaconService) {
|
|
2099
|
-
throw new
|
|
2131
|
+
throw new import_common12.UpdateError(
|
|
2100
2132
|
"No beacon service found for provided beaconId",
|
|
2101
|
-
|
|
2133
|
+
import_common12.INVALID_DID_UPDATE,
|
|
2102
2134
|
{ sourceDocument, beaconId }
|
|
2103
2135
|
);
|
|
2104
2136
|
}
|
|
@@ -2124,7 +2156,7 @@ var DidBtcr2 = class {
|
|
|
2124
2156
|
methodId ??= "#initialKey";
|
|
2125
2157
|
const parsedDid = import_dids2.Did.parse(didDocument.id);
|
|
2126
2158
|
if (parsedDid && parsedDid.method !== this.methodName) {
|
|
2127
|
-
throw new
|
|
2159
|
+
throw new import_common12.MethodError(`Method not supported: ${parsedDid.method}`, import_common12.METHOD_NOT_SUPPORTED, { identifier: didDocument.id });
|
|
2128
2160
|
}
|
|
2129
2161
|
const verificationMethod = didDocument.verificationMethod?.find(
|
|
2130
2162
|
(vm) => Appendix.extractDidFragment(vm.id) === (Appendix.extractDidFragment(methodId) ?? Appendix.extractDidFragment(didDocument.assertionMethod?.[0]))
|
|
@@ -2155,6 +2187,11 @@ function isSMTProof(value) {
|
|
|
2155
2187
|
if (!isRecord(value)) return false;
|
|
2156
2188
|
return typeof value.id === "string" && typeof value.collapsed === "string" && Array.isArray(value.hashes);
|
|
2157
2189
|
}
|
|
2190
|
+
function relationshipMethodId(documentId, entry) {
|
|
2191
|
+
const id = isRecord(entry) ? entry.id : entry;
|
|
2192
|
+
if (typeof id !== "string" || id.length === 0) return void 0;
|
|
2193
|
+
return id.startsWith("#") ? `${documentId}${id}` : id;
|
|
2194
|
+
}
|
|
2158
2195
|
var Resolver = class _Resolver {
|
|
2159
2196
|
// --- Immutable inputs ---
|
|
2160
2197
|
#didComponents;
|
|
@@ -2244,14 +2281,14 @@ var Resolver = class _Resolver {
|
|
|
2244
2281
|
* @throws {ResolveError} InvalidDidDocument if not conformant to DID Core v1.1
|
|
2245
2282
|
*/
|
|
2246
2283
|
static external(didComponents, genesisDocument) {
|
|
2247
|
-
const genesisDocumentHash = (0,
|
|
2284
|
+
const genesisDocumentHash = (0, import_common13.canonicalHashBytes)(genesisDocument);
|
|
2248
2285
|
if (!(0, import_utils6.equalBytes)(didComponents.genesisBytes, genesisDocumentHash)) {
|
|
2249
|
-
throw new
|
|
2286
|
+
throw new import_common13.ResolveError(
|
|
2250
2287
|
`Initial document mismatch: genesisBytes !== genesisDocumentHash`,
|
|
2251
|
-
|
|
2288
|
+
import_common13.INVALID_DID_DOCUMENT,
|
|
2252
2289
|
{
|
|
2253
|
-
genesisBytes: (0,
|
|
2254
|
-
genesisDocumentHash: (0,
|
|
2290
|
+
genesisBytes: (0, import_common13.encode)(didComponents.genesisBytes, "hex"),
|
|
2291
|
+
genesisDocumentHash: (0, import_common13.encode)(genesisDocumentHash, "hex")
|
|
2255
2292
|
}
|
|
2256
2293
|
);
|
|
2257
2294
|
}
|
|
@@ -2270,17 +2307,17 @@ var Resolver = class _Resolver {
|
|
|
2270
2307
|
const updateMap = /* @__PURE__ */ new Map();
|
|
2271
2308
|
if (sidecar.updates?.length)
|
|
2272
2309
|
for (const update of sidecar.updates) {
|
|
2273
|
-
updateMap.set((0,
|
|
2310
|
+
updateMap.set((0, import_common13.canonicalHash)(update, { encoding: "hex" }), update);
|
|
2274
2311
|
}
|
|
2275
2312
|
const casMap = /* @__PURE__ */ new Map();
|
|
2276
2313
|
if (sidecar.casUpdates?.length)
|
|
2277
2314
|
for (const update of sidecar.casUpdates) {
|
|
2278
|
-
casMap.set((0,
|
|
2315
|
+
casMap.set((0, import_common13.canonicalHash)(update, { encoding: "hex" }), update);
|
|
2279
2316
|
}
|
|
2280
2317
|
const smtMap = /* @__PURE__ */ new Map();
|
|
2281
2318
|
if (sidecar.smtProofs?.length)
|
|
2282
2319
|
for (const proof of sidecar.smtProofs) {
|
|
2283
|
-
smtMap.set((0,
|
|
2320
|
+
smtMap.set((0, import_common13.encode)((0, import_common13.decode)(proof.id, "base64urlnopad"), "hex"), proof);
|
|
2284
2321
|
}
|
|
2285
2322
|
return { updateMap, casMap, smtMap };
|
|
2286
2323
|
}
|
|
@@ -2311,38 +2348,38 @@ var Resolver = class _Resolver {
|
|
|
2311
2348
|
}
|
|
2312
2349
|
};
|
|
2313
2350
|
for (const [update, block] of updates) {
|
|
2314
|
-
const currentDocumentHash = (0,
|
|
2315
|
-
const blocktime =
|
|
2316
|
-
response.metadata.updated =
|
|
2351
|
+
const currentDocumentHash = (0, import_common13.canonicalHashBytes)(response.didDocument);
|
|
2352
|
+
const blocktime = import_common13.DateUtils.blocktimeToTimestamp(block.time);
|
|
2353
|
+
response.metadata.updated = import_common13.DateUtils.toISOStringNonFractional(blocktime);
|
|
2317
2354
|
response.metadata.confirmations = block.confirmations;
|
|
2318
2355
|
if (update.targetVersionId <= currentVersionId) {
|
|
2319
2356
|
this.confirmDuplicate(update, updateHashHistory);
|
|
2320
2357
|
continue;
|
|
2321
2358
|
}
|
|
2322
2359
|
if (versionTime) {
|
|
2323
|
-
if (blocktime >
|
|
2360
|
+
if (blocktime > import_common13.DateUtils.dateStringToTimestamp(versionTime)) {
|
|
2324
2361
|
return response;
|
|
2325
2362
|
}
|
|
2326
2363
|
}
|
|
2327
2364
|
if (update.targetVersionId === currentVersionId + 1) {
|
|
2328
|
-
const sourceHashBytes = (0,
|
|
2365
|
+
const sourceHashBytes = (0, import_common13.decode)(update.sourceHash, "base64urlnopad");
|
|
2329
2366
|
if (!(0, import_utils6.equalBytes)(sourceHashBytes, currentDocumentHash)) {
|
|
2330
|
-
throw new
|
|
2367
|
+
throw new import_common13.ResolveError(
|
|
2331
2368
|
`Hash mismatch: update.sourceHash !== currentDocumentHash`,
|
|
2332
|
-
|
|
2369
|
+
import_common13.INVALID_DID_UPDATE,
|
|
2333
2370
|
{
|
|
2334
2371
|
sourceHash: update.sourceHash,
|
|
2335
|
-
currentDocumentHash: (0,
|
|
2372
|
+
currentDocumentHash: (0, import_common13.encode)(currentDocumentHash, "hex")
|
|
2336
2373
|
}
|
|
2337
2374
|
);
|
|
2338
2375
|
}
|
|
2339
2376
|
response.didDocument = this.applyUpdate(response.didDocument, update);
|
|
2340
|
-
const unsignedUpdate =
|
|
2341
|
-
updateHashHistory.push((0,
|
|
2377
|
+
const unsignedUpdate = import_common13.JSONUtils.deleteKeys(update, ["proof"]);
|
|
2378
|
+
updateHashHistory.push((0, import_common13.canonicalHashBytes)(unsignedUpdate));
|
|
2342
2379
|
} else {
|
|
2343
|
-
throw new
|
|
2380
|
+
throw new import_common13.ResolveError(
|
|
2344
2381
|
`Version Id Mismatch: targetVersionId cannot be > currentVersionId + 1`,
|
|
2345
|
-
|
|
2382
|
+
import_common13.LATE_PUBLISHING_ERROR,
|
|
2346
2383
|
{
|
|
2347
2384
|
targetVersionId: update.targetVersionId,
|
|
2348
2385
|
currentVersionId: currentVersionId + 1
|
|
@@ -2371,19 +2408,19 @@ var Resolver = class _Resolver {
|
|
|
2371
2408
|
*/
|
|
2372
2409
|
static confirmDuplicate(update, updateHashHistory) {
|
|
2373
2410
|
if (!Number.isInteger(update.targetVersionId) || update.targetVersionId < 2) {
|
|
2374
|
-
throw new
|
|
2411
|
+
throw new import_common13.ResolveError(
|
|
2375
2412
|
`Invalid duplicate: targetVersionId must be an integer >= 2`,
|
|
2376
|
-
|
|
2413
|
+
import_common13.INVALID_DID_UPDATE,
|
|
2377
2414
|
{ targetVersionId: update.targetVersionId }
|
|
2378
2415
|
);
|
|
2379
2416
|
}
|
|
2380
2417
|
const { proof: _, ...unsignedUpdate } = update;
|
|
2381
|
-
const unsignedUpdateHash = (0,
|
|
2418
|
+
const unsignedUpdateHash = (0, import_common13.canonicalHashBytes)(unsignedUpdate);
|
|
2382
2419
|
const historicalUpdateHash = updateHashHistory[update.targetVersionId - 2];
|
|
2383
2420
|
if (historicalUpdateHash === void 0) {
|
|
2384
|
-
throw new
|
|
2421
|
+
throw new import_common13.ResolveError(
|
|
2385
2422
|
`Invalid duplicate: no applied update in history for targetVersionId`,
|
|
2386
|
-
|
|
2423
|
+
import_common13.LATE_PUBLISHING_ERROR,
|
|
2387
2424
|
{
|
|
2388
2425
|
targetVersionId: update.targetVersionId,
|
|
2389
2426
|
historyLength: updateHashHistory.length
|
|
@@ -2391,12 +2428,12 @@ var Resolver = class _Resolver {
|
|
|
2391
2428
|
);
|
|
2392
2429
|
}
|
|
2393
2430
|
if (!(0, import_utils6.equalBytes)(historicalUpdateHash, unsignedUpdateHash)) {
|
|
2394
|
-
throw new
|
|
2431
|
+
throw new import_common13.ResolveError(
|
|
2395
2432
|
`Invalid duplicate: unsigned update hash does not match historical hash`,
|
|
2396
|
-
|
|
2433
|
+
import_common13.LATE_PUBLISHING_ERROR,
|
|
2397
2434
|
{
|
|
2398
|
-
unsignedUpdateHash: (0,
|
|
2399
|
-
historicalHash: (0,
|
|
2435
|
+
unsignedUpdateHash: (0, import_common13.encode)(unsignedUpdateHash, "hex"),
|
|
2436
|
+
historicalHash: (0, import_common13.encode)(historicalUpdateHash, "hex")
|
|
2400
2437
|
}
|
|
2401
2438
|
);
|
|
2402
2439
|
}
|
|
@@ -2411,42 +2448,56 @@ var Resolver = class _Resolver {
|
|
|
2411
2448
|
static applyUpdate(currentDocument, update) {
|
|
2412
2449
|
const capabilityId = update.proof?.capability;
|
|
2413
2450
|
if (!capabilityId) {
|
|
2414
|
-
throw new
|
|
2451
|
+
throw new import_common13.ResolveError("No root capability found in update", import_common13.INVALID_DID_UPDATE, update);
|
|
2415
2452
|
}
|
|
2416
2453
|
const rootCapability = Appendix.dereferenceZcapId(capabilityId);
|
|
2417
2454
|
const { invocationTarget, controller: rootController } = rootCapability;
|
|
2418
2455
|
if (![invocationTarget, rootController].every((id) => id === currentDocument.id)) {
|
|
2419
|
-
throw new
|
|
2456
|
+
throw new import_common13.ResolveError(
|
|
2420
2457
|
"Invalid root capability",
|
|
2421
|
-
|
|
2458
|
+
import_common13.INVALID_DID_UPDATE,
|
|
2422
2459
|
{ rootCapability, currentDocument }
|
|
2423
2460
|
);
|
|
2424
2461
|
}
|
|
2425
2462
|
const verificationMethodId = update.proof?.verificationMethod;
|
|
2426
2463
|
if (!verificationMethodId) {
|
|
2427
|
-
throw new
|
|
2464
|
+
throw new import_common13.ResolveError("No verificationMethod found in update", import_common13.INVALID_DID_UPDATE, update);
|
|
2465
|
+
}
|
|
2466
|
+
const authorizedMethodId = relationshipMethodId(currentDocument.id, verificationMethodId);
|
|
2467
|
+
const authorized = authorizedMethodId !== void 0 && currentDocument.capabilityInvocation?.some(
|
|
2468
|
+
(entry) => relationshipMethodId(currentDocument.id, entry) === authorizedMethodId
|
|
2469
|
+
);
|
|
2470
|
+
if (!authorized) {
|
|
2471
|
+
throw new import_common13.ResolveError(
|
|
2472
|
+
"Invalid update: verificationMethod is not authorized for capabilityInvocation",
|
|
2473
|
+
import_common13.INVALID_DID_UPDATE,
|
|
2474
|
+
{
|
|
2475
|
+
verificationMethodId,
|
|
2476
|
+
capabilityInvocation: currentDocument.capabilityInvocation
|
|
2477
|
+
}
|
|
2478
|
+
);
|
|
2428
2479
|
}
|
|
2429
2480
|
const vm = DidBtcr2.getSigningMethod(currentDocument, verificationMethodId);
|
|
2430
2481
|
const multikey = import_cryptosuite2.SchnorrMultikey.fromVerificationMethod(vm);
|
|
2431
2482
|
const cryptosuite = new import_cryptosuite2.BIP340Cryptosuite(multikey);
|
|
2432
|
-
const canonicalUpdate = (0,
|
|
2483
|
+
const canonicalUpdate = (0, import_common13.canonicalize)(update);
|
|
2433
2484
|
const diProof = new import_cryptosuite2.BIP340DataIntegrityProof(cryptosuite);
|
|
2434
2485
|
const verificationResult = diProof.verifyProof(canonicalUpdate, "capabilityInvocation");
|
|
2435
2486
|
if (!verificationResult.verified) {
|
|
2436
|
-
throw new
|
|
2487
|
+
throw new import_common13.ResolveError(
|
|
2437
2488
|
"Invalid update: proof not verified",
|
|
2438
|
-
|
|
2489
|
+
import_common13.INVALID_DID_UPDATE,
|
|
2439
2490
|
verificationResult
|
|
2440
2491
|
);
|
|
2441
2492
|
}
|
|
2442
|
-
const updatedDocument =
|
|
2493
|
+
const updatedDocument = import_common13.JSONPatch.apply(currentDocument, update.patch);
|
|
2443
2494
|
DidDocument.validate(updatedDocument);
|
|
2444
|
-
const currentDocumentHash = (0,
|
|
2445
|
-
const updateTargetHash = (0,
|
|
2495
|
+
const currentDocumentHash = (0, import_common13.canonicalHashBytes)(updatedDocument);
|
|
2496
|
+
const updateTargetHash = (0, import_common13.decode)(update.targetHash);
|
|
2446
2497
|
if (!(0, import_utils6.equalBytes)(updateTargetHash, currentDocumentHash)) {
|
|
2447
|
-
throw new
|
|
2498
|
+
throw new import_common13.ResolveError(
|
|
2448
2499
|
`Invalid update: update.targetHash !== currentDocumentHash`,
|
|
2449
|
-
|
|
2500
|
+
import_common13.INVALID_DID_UPDATE,
|
|
2450
2501
|
{ updateTargetHash, currentDocumentHash }
|
|
2451
2502
|
);
|
|
2452
2503
|
}
|
|
@@ -2474,7 +2525,7 @@ var Resolver = class _Resolver {
|
|
|
2474
2525
|
this.#phase = "BeaconDiscovery" /* BeaconDiscovery */;
|
|
2475
2526
|
continue;
|
|
2476
2527
|
}
|
|
2477
|
-
const genesisHash = (0,
|
|
2528
|
+
const genesisHash = (0, import_common13.encode)(this.#didComponents.genesisBytes, "hex");
|
|
2478
2529
|
return {
|
|
2479
2530
|
status: "action-required",
|
|
2480
2531
|
needs: [{ kind: "NeedGenesisDocument", genesisHash }]
|
|
@@ -2543,9 +2594,9 @@ var Resolver = class _Resolver {
|
|
|
2543
2594
|
});
|
|
2544
2595
|
if (hasNewServices) {
|
|
2545
2596
|
if (++this.#discoveryRounds > this.#maxDiscoveryRounds) {
|
|
2546
|
-
throw new
|
|
2597
|
+
throw new import_common13.ResolveError(
|
|
2547
2598
|
`Exceeded the configured maximum of ${this.#maxDiscoveryRounds} beacon-discovery rounds. Raise or remove ResolutionOptions.maxDiscoveryRounds to resolve this DID.`,
|
|
2548
|
-
|
|
2599
|
+
import_common13.INTERNAL_ERROR,
|
|
2549
2600
|
{ maxDiscoveryRounds: this.#maxDiscoveryRounds, discoveryRounds: this.#discoveryRounds }
|
|
2550
2601
|
);
|
|
2551
2602
|
}
|
|
@@ -2576,9 +2627,9 @@ var Resolver = class _Resolver {
|
|
|
2576
2627
|
switch (need.kind) {
|
|
2577
2628
|
case "NeedGenesisDocument": {
|
|
2578
2629
|
if (!isRecord(data)) {
|
|
2579
|
-
throw new
|
|
2630
|
+
throw new import_common13.ResolveError(
|
|
2580
2631
|
"Provided data for NeedGenesisDocument must be a document object.",
|
|
2581
|
-
|
|
2632
|
+
import_common13.INVALID_DID_UPDATE,
|
|
2582
2633
|
{ kind: need.kind }
|
|
2583
2634
|
);
|
|
2584
2635
|
}
|
|
@@ -2587,9 +2638,9 @@ var Resolver = class _Resolver {
|
|
|
2587
2638
|
}
|
|
2588
2639
|
case "NeedBeaconSignals": {
|
|
2589
2640
|
if (!(data instanceof Map)) {
|
|
2590
|
-
throw new
|
|
2641
|
+
throw new import_common13.ResolveError(
|
|
2591
2642
|
"Provided data for NeedBeaconSignals must be a Map of beacon services to signals.",
|
|
2592
|
-
|
|
2643
|
+
import_common13.INVALID_DID_UPDATE,
|
|
2593
2644
|
{ kind: need.kind }
|
|
2594
2645
|
);
|
|
2595
2646
|
}
|
|
@@ -2600,17 +2651,17 @@ var Resolver = class _Resolver {
|
|
|
2600
2651
|
}
|
|
2601
2652
|
case "NeedCASAnnouncement": {
|
|
2602
2653
|
if (!isCASAnnouncement(data)) {
|
|
2603
|
-
throw new
|
|
2654
|
+
throw new import_common13.ResolveError(
|
|
2604
2655
|
"Provided data for NeedCASAnnouncement is not a CAS announcement.",
|
|
2605
|
-
|
|
2656
|
+
import_common13.INVALID_DID_UPDATE,
|
|
2606
2657
|
{ kind: need.kind }
|
|
2607
2658
|
);
|
|
2608
2659
|
}
|
|
2609
|
-
const announcementHash = (0,
|
|
2660
|
+
const announcementHash = (0, import_common13.canonicalHash)(data, { encoding: "hex" });
|
|
2610
2661
|
if (announcementHash !== need.announcementHash) {
|
|
2611
|
-
throw new
|
|
2662
|
+
throw new import_common13.ResolveError(
|
|
2612
2663
|
`CAS announcement hash mismatch: expected ${need.announcementHash}, got ${announcementHash}.`,
|
|
2613
|
-
|
|
2664
|
+
import_common13.INVALID_DID_UPDATE,
|
|
2614
2665
|
{ expected: need.announcementHash, actual: announcementHash }
|
|
2615
2666
|
);
|
|
2616
2667
|
}
|
|
@@ -2619,17 +2670,17 @@ var Resolver = class _Resolver {
|
|
|
2619
2670
|
}
|
|
2620
2671
|
case "NeedSignedUpdate": {
|
|
2621
2672
|
if (!isSignedBTCR2Update(data)) {
|
|
2622
|
-
throw new
|
|
2673
|
+
throw new import_common13.ResolveError(
|
|
2623
2674
|
"Provided data for NeedSignedUpdate is not a signed BTCR2 update.",
|
|
2624
|
-
|
|
2675
|
+
import_common13.INVALID_DID_UPDATE,
|
|
2625
2676
|
{ kind: need.kind }
|
|
2626
2677
|
);
|
|
2627
2678
|
}
|
|
2628
|
-
const updateHash = (0,
|
|
2679
|
+
const updateHash = (0, import_common13.canonicalHash)(data, { encoding: "hex" });
|
|
2629
2680
|
if (updateHash !== need.updateHash) {
|
|
2630
|
-
throw new
|
|
2681
|
+
throw new import_common13.ResolveError(
|
|
2631
2682
|
`Signed update hash mismatch: expected ${need.updateHash}, got ${updateHash}.`,
|
|
2632
|
-
|
|
2683
|
+
import_common13.INVALID_DID_UPDATE,
|
|
2633
2684
|
{ expected: need.updateHash, actual: updateHash }
|
|
2634
2685
|
);
|
|
2635
2686
|
}
|
|
@@ -2638,17 +2689,17 @@ var Resolver = class _Resolver {
|
|
|
2638
2689
|
}
|
|
2639
2690
|
case "NeedSMTProof": {
|
|
2640
2691
|
if (!isSMTProof(data)) {
|
|
2641
|
-
throw new
|
|
2692
|
+
throw new import_common13.ResolveError(
|
|
2642
2693
|
"Provided data for NeedSMTProof is not an SMT proof.",
|
|
2643
|
-
|
|
2694
|
+
import_common13.INVALID_DID_UPDATE,
|
|
2644
2695
|
{ kind: need.kind }
|
|
2645
2696
|
);
|
|
2646
2697
|
}
|
|
2647
|
-
const proofIdHex = (0,
|
|
2698
|
+
const proofIdHex = (0, import_common13.encode)((0, import_common13.decode)(data.id, "base64urlnopad"), "hex");
|
|
2648
2699
|
if (proofIdHex !== need.smtRootHash) {
|
|
2649
|
-
throw new
|
|
2700
|
+
throw new import_common13.ResolveError(
|
|
2650
2701
|
`SMT proof root hash mismatch: expected ${need.smtRootHash}, got ${proofIdHex}`,
|
|
2651
|
-
|
|
2702
|
+
import_common13.INVALID_DID_UPDATE,
|
|
2652
2703
|
{ expected: need.smtRootHash, actual: proofIdHex }
|
|
2653
2704
|
);
|
|
2654
2705
|
}
|
|
@@ -2663,17 +2714,17 @@ var Resolver = class _Resolver {
|
|
|
2663
2714
|
function getAggregationCommunicationKey(document) {
|
|
2664
2715
|
const invocation = document.capabilityInvocation?.[0];
|
|
2665
2716
|
if (invocation === void 0) {
|
|
2666
|
-
throw new
|
|
2717
|
+
throw new import_common14.DidDocumentError(
|
|
2667
2718
|
"Cannot derive aggregation communication key: capabilityInvocation is absent",
|
|
2668
|
-
|
|
2719
|
+
import_common14.INVALID_DID_DOCUMENT,
|
|
2669
2720
|
{ id: document.id }
|
|
2670
2721
|
);
|
|
2671
2722
|
}
|
|
2672
2723
|
const vm = typeof invocation === "string" ? document.verificationMethod?.find((method) => method.id === invocation) : invocation;
|
|
2673
2724
|
if (!vm) {
|
|
2674
|
-
throw new
|
|
2725
|
+
throw new import_common14.DidDocumentError(
|
|
2675
2726
|
`Cannot derive aggregation communication key: capabilityInvocation[0] "${invocation}" does not resolve to a verification method`,
|
|
2676
|
-
|
|
2727
|
+
import_common14.INVALID_DID_DOCUMENT,
|
|
2677
2728
|
{ id: document.id, invocation }
|
|
2678
2729
|
);
|
|
2679
2730
|
}
|
|
@@ -2695,12 +2746,12 @@ function resolveBtcr2SenderPk(did, opts) {
|
|
|
2695
2746
|
}
|
|
2696
2747
|
|
|
2697
2748
|
// src/utils/did-document-builder.ts
|
|
2698
|
-
var
|
|
2749
|
+
var import_common15 = require("@did-btcr2/common");
|
|
2699
2750
|
var DidDocumentBuilder = class {
|
|
2700
2751
|
document = {};
|
|
2701
2752
|
constructor(initialDocument) {
|
|
2702
2753
|
if (!initialDocument.id) {
|
|
2703
|
-
throw new
|
|
2754
|
+
throw new import_common15.DidDocumentError('Missing required "id" property', import_common15.INVALID_DID_DOCUMENT, initialDocument);
|
|
2704
2755
|
}
|
|
2705
2756
|
this.document.id = initialDocument.id;
|
|
2706
2757
|
this.document.verificationMethod = initialDocument.verificationMethod ?? [];
|
|
@@ -2790,7 +2841,7 @@ var DidDocumentBuilder = class {
|
|
|
2790
2841
|
buildAggregationBeaconTx,
|
|
2791
2842
|
deriveSingletonAddress,
|
|
2792
2843
|
detectSingletonScriptKind,
|
|
2793
|
-
|
|
2844
|
+
extractOpReturnSignalHash,
|
|
2794
2845
|
getAggregationCommunicationKey,
|
|
2795
2846
|
isMultikeyVerificationMethod,
|
|
2796
2847
|
opReturnScript,
|