@textrp/briij-js-sdk 41.0.1 → 43.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -1
- package/LICENSE +177 -177
- package/README.md +85 -3
- package/lib/@types/AESEncryptedSecretStoragePayload.js.map +1 -1
- package/lib/@types/IIdentityServerProvider.js.map +1 -1
- package/lib/@types/PushRules.js +14 -14
- package/lib/@types/PushRules.js.map +1 -1
- package/lib/@types/another-json.d.js.map +1 -1
- package/lib/@types/auth.d.ts +72 -1
- package/lib/@types/auth.d.ts.map +1 -1
- package/lib/@types/auth.js +57 -54
- package/lib/@types/auth.js.map +1 -1
- package/lib/@types/beacon.js +100 -100
- package/lib/@types/beacon.js.map +1 -1
- package/lib/@types/common.js.map +1 -1
- package/lib/@types/crypto.js.map +1 -1
- package/lib/@types/event.d.ts +59 -0
- package/lib/@types/event.d.ts.map +1 -1
- package/lib/@types/event.js +105 -102
- package/lib/@types/event.js.map +1 -1
- package/lib/@types/events.js.map +1 -1
- package/lib/@types/extensible_events.js +53 -53
- package/lib/@types/extensible_events.js.map +1 -1
- package/lib/@types/local_notifications.js.map +1 -1
- package/lib/@types/location.js +41 -41
- package/lib/@types/location.js.map +1 -1
- package/lib/@types/matrix-sdk-crypto-wasm.d.js.map +1 -1
- package/lib/@types/media.js.map +1 -1
- package/lib/@types/membership.js +39 -39
- package/lib/@types/membership.js.map +1 -1
- package/lib/@types/partials.js +25 -25
- package/lib/@types/partials.js.map +1 -1
- package/lib/@types/polls.js +46 -46
- package/lib/@types/polls.js.map +1 -1
- package/lib/@types/read_receipts.js +14 -14
- package/lib/@types/read_receipts.js.map +1 -1
- package/lib/@types/registration.js.map +1 -1
- package/lib/@types/search.js +14 -14
- package/lib/@types/search.js.map +1 -1
- package/lib/@types/signed.js.map +1 -1
- package/lib/@types/spaces.js.map +1 -1
- package/lib/@types/state_events.js.map +1 -1
- package/lib/@types/synapse.js.map +1 -1
- package/lib/@types/sync.js +18 -18
- package/lib/@types/sync.js.map +1 -1
- package/lib/@types/threepids.js +14 -14
- package/lib/@types/threepids.js.map +1 -1
- package/lib/@types/topic.js +47 -47
- package/lib/@types/topic.js.map +1 -1
- package/lib/@types/uia.js.map +1 -1
- package/lib/NamespacedValue.js +20 -20
- package/lib/NamespacedValue.js.map +1 -1
- package/lib/ReEmitter.js +16 -16
- package/lib/ReEmitter.js.map +1 -1
- package/lib/base64.js +32 -32
- package/lib/base64.js.map +1 -1
- package/lib/briij.d.ts +4 -0
- package/lib/briij.d.ts.map +1 -1
- package/lib/briij.js +4 -0
- package/lib/briij.js.map +1 -1
- package/lib/client.d.ts +48 -1
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +262 -108
- package/lib/client.js.map +1 -1
- package/lib/common-crypto/key-passphrase.js +19 -19
- package/lib/common-crypto/key-passphrase.js.map +1 -1
- package/lib/content-helpers.js +57 -57
- package/lib/content-helpers.js.map +1 -1
- package/lib/content-repo.js +36 -36
- package/lib/content-repo.js.map +1 -1
- package/lib/crypto/store/base.js +69 -69
- package/lib/crypto/store/base.js.map +1 -1
- package/lib/crypto/store/indexeddb-crypto-store-backend.js +58 -58
- package/lib/crypto/store/indexeddb-crypto-store-backend.js.map +1 -1
- package/lib/crypto/store/indexeddb-crypto-store.js +193 -193
- package/lib/crypto/store/indexeddb-crypto-store.js.map +1 -1
- package/lib/crypto/store/localStorage-crypto-store.js +72 -72
- package/lib/crypto/store/localStorage-crypto-store.js.map +1 -1
- package/lib/crypto/store/memory-crypto-store.js +74 -74
- package/lib/crypto/store/memory-crypto-store.js.map +1 -1
- package/lib/crypto-api/CryptoEventHandlerMap.js.map +1 -1
- package/lib/crypto-api/key-passphrase.js +22 -22
- package/lib/crypto-api/key-passphrase.js.map +1 -1
- package/lib/crypto-api/keybackup.js.map +1 -1
- package/lib/crypto-api/recovery-key.js +20 -20
- package/lib/crypto-api/recovery-key.js.map +1 -1
- package/lib/digest.js +21 -21
- package/lib/digest.js.map +1 -1
- package/lib/extensible_events_v1/ExtensibleEvent.js +39 -39
- package/lib/extensible_events_v1/ExtensibleEvent.js.map +1 -1
- package/lib/extensible_events_v1/InvalidEventError.js +16 -16
- package/lib/extensible_events_v1/InvalidEventError.js.map +1 -1
- package/lib/extensible_events_v1/MessageEvent.js +39 -39
- package/lib/extensible_events_v1/MessageEvent.js.map +1 -1
- package/lib/extensible_events_v1/PollEndEvent.js +29 -29
- package/lib/extensible_events_v1/PollEndEvent.js.map +1 -1
- package/lib/extensible_events_v1/PollResponseEvent.js +39 -39
- package/lib/extensible_events_v1/PollResponseEvent.js.map +1 -1
- package/lib/extensible_events_v1/PollStartEvent.js +52 -52
- package/lib/extensible_events_v1/PollStartEvent.js.map +1 -1
- package/lib/extensible_events_v1/utilities.js +22 -22
- package/lib/extensible_events_v1/utilities.js.map +1 -1
- package/lib/feature.js +16 -16
- package/lib/feature.js.map +1 -1
- package/lib/http-api/method.js +14 -14
- package/lib/http-api/method.js.map +1 -1
- package/lib/http-api/prefix.js +26 -26
- package/lib/http-api/prefix.js.map +1 -1
- package/lib/indexeddb-helpers.js +21 -21
- package/lib/indexeddb-helpers.js.map +1 -1
- package/lib/indexeddb-worker.js +18 -18
- package/lib/indexeddb-worker.js.map +1 -1
- package/lib/matrixrtc/IKeyTransport.js +17 -17
- package/lib/matrixrtc/IKeyTransport.js.map +1 -1
- package/lib/matrixrtc/IMembershipManager.js +27 -27
- package/lib/matrixrtc/IMembershipManager.js.map +1 -1
- package/lib/matrixrtc/LivekitTransport.js +19 -19
- package/lib/matrixrtc/LivekitTransport.js.map +1 -1
- package/lib/matrixrtc/index.js +14 -14
- package/lib/matrixrtc/index.js.map +1 -1
- package/lib/matrixrtc/utils.js +27 -27
- package/lib/matrixrtc/utils.js.map +1 -1
- package/lib/models/ToDeviceMessage.js.map +1 -1
- package/lib/models/device.js +24 -24
- package/lib/models/device.js.map +1 -1
- package/lib/models/event-status.js +17 -17
- package/lib/models/event-status.js.map +1 -1
- package/lib/models/invites-ignorer-types.js +25 -25
- package/lib/models/invites-ignorer-types.js.map +1 -1
- package/lib/models/profile-keys.js +26 -26
- package/lib/models/profile-keys.js.map +1 -1
- package/lib/models/room-summary.js +26 -26
- package/lib/models/room-summary.js.map +1 -1
- package/lib/models/search-result.js +22 -22
- package/lib/models/search-result.js.map +1 -1
- package/lib/models/typed-event-emitter.js +122 -122
- package/lib/models/typed-event-emitter.js.map +1 -1
- package/lib/oidc/authorize.js +76 -76
- package/lib/oidc/authorize.js.map +1 -1
- package/lib/oidc/error.js +17 -17
- package/lib/oidc/error.js.map +1 -1
- package/lib/oidc/index.js +17 -17
- package/lib/oidc/index.js.map +1 -1
- package/lib/oidc/register.js +41 -41
- package/lib/oidc/register.js.map +1 -1
- package/lib/oidc/tokenRefresher.js +51 -51
- package/lib/oidc/tokenRefresher.js.map +1 -1
- package/lib/oidc/validate.js +59 -59
- package/lib/oidc/validate.js.map +1 -1
- package/lib/randomstring.js +35 -35
- package/lib/randomstring.js.map +1 -1
- package/lib/realtime-callbacks.js +39 -39
- package/lib/realtime-callbacks.js.map +1 -1
- package/lib/receipt-accumulator.js +44 -44
- package/lib/receipt-accumulator.js.map +1 -1
- package/lib/rendezvous/RendezvousChannel.js.map +1 -1
- package/lib/rendezvous/RendezvousCode.js.map +1 -1
- package/lib/rendezvous/RendezvousError.js +14 -14
- package/lib/rendezvous/RendezvousError.js.map +1 -1
- package/lib/rendezvous/RendezvousFailureReason.js +14 -14
- package/lib/rendezvous/RendezvousFailureReason.js.map +1 -1
- package/lib/rendezvous/RendezvousIntent.js +14 -14
- package/lib/rendezvous/RendezvousIntent.js.map +1 -1
- package/lib/rendezvous/RendezvousTransport.js.map +1 -1
- package/lib/rendezvous/channels/MSC4108SecureChannel.js +63 -63
- package/lib/rendezvous/channels/MSC4108SecureChannel.js.map +1 -1
- package/lib/rendezvous/channels/index.js +14 -14
- package/lib/rendezvous/channels/index.js.map +1 -1
- package/lib/rendezvous/index.js +14 -14
- package/lib/rendezvous/index.js.map +1 -1
- package/lib/rendezvous/transports/index.js +14 -14
- package/lib/rendezvous/transports/index.js.map +1 -1
- package/lib/rust-crypto/CrossSigningIdentity.js +29 -29
- package/lib/rust-crypto/CrossSigningIdentity.js.map +1 -1
- package/lib/rust-crypto/OutgoingRequestsManager.js +37 -37
- package/lib/rust-crypto/OutgoingRequestsManager.js.map +1 -1
- package/lib/rust-crypto/device-converter.js +30 -30
- package/lib/rust-crypto/device-converter.js.map +1 -1
- package/lib/rust-crypto/secret-storage.js +30 -30
- package/lib/rust-crypto/secret-storage.js.map +1 -1
- package/lib/service-types.js +14 -14
- package/lib/service-types.js.map +1 -1
- package/lib/store/local-storage-events-emitter.js +21 -21
- package/lib/store/local-storage-events-emitter.js.map +1 -1
- package/lib/sync-accumulator.js +50 -50
- package/lib/sync-accumulator.js.map +1 -1
- package/lib/thread-utils.js +20 -20
- package/lib/thread-utils.js.map +1 -1
- package/lib/types.js +34 -34
- package/lib/types.js.map +1 -1
- package/lib/utils/decryptAESSecretStorageItem.js +22 -22
- package/lib/utils/decryptAESSecretStorageItem.js.map +1 -1
- package/lib/utils/encryptAESSecretStorageItem.js +26 -26
- package/lib/utils/encryptAESSecretStorageItem.js.map +1 -1
- package/lib/utils/internal/deriveKeys.js +21 -21
- package/lib/utils/internal/deriveKeys.js.map +1 -1
- package/lib/utils/roomVersion.js +26 -26
- package/lib/utils/roomVersion.js.map +1 -1
- package/lib/version-support.js +26 -26
- package/lib/version-support.js.map +1 -1
- package/lib/wallet-recovery.d.ts +24 -0
- package/lib/wallet-recovery.d.ts.map +1 -0
- package/lib/wallet-recovery.js +232 -0
- package/lib/wallet-recovery.js.map +1 -0
- package/lib/webrtc/audioContext.js +24 -24
- package/lib/webrtc/audioContext.js.map +1 -1
- package/lib/webrtc/callEventTypes.js.map +1 -1
- package/lib/webrtc/stats/callFeedStatsReporter.js +14 -14
- package/lib/webrtc/stats/callFeedStatsReporter.js.map +1 -1
- package/lib/webrtc/stats/callStatsReportGatherer.js +14 -14
- package/lib/webrtc/stats/callStatsReportGatherer.js.map +1 -1
- package/lib/webrtc/stats/callStatsReportSummary.js.map +1 -1
- package/lib/webrtc/stats/connectionStats.js +14 -14
- package/lib/webrtc/stats/connectionStats.js.map +1 -1
- package/lib/webrtc/stats/connectionStatsBuilder.js +14 -14
- package/lib/webrtc/stats/connectionStatsBuilder.js.map +1 -1
- package/lib/webrtc/stats/connectionStatsReportBuilder.js +14 -14
- package/lib/webrtc/stats/connectionStatsReportBuilder.js.map +1 -1
- package/lib/webrtc/stats/groupCallStats.js +14 -14
- package/lib/webrtc/stats/groupCallStats.js.map +1 -1
- package/lib/webrtc/stats/media/mediaSsrcHandler.js +14 -14
- package/lib/webrtc/stats/media/mediaSsrcHandler.js.map +1 -1
- package/lib/webrtc/stats/media/mediaTrackHandler.js +14 -14
- package/lib/webrtc/stats/media/mediaTrackHandler.js.map +1 -1
- package/lib/webrtc/stats/media/mediaTrackStats.js +27 -27
- package/lib/webrtc/stats/media/mediaTrackStats.js.map +1 -1
- package/lib/webrtc/stats/media/mediaTrackStatsHandler.js +20 -20
- package/lib/webrtc/stats/media/mediaTrackStatsHandler.js.map +1 -1
- package/lib/webrtc/stats/statsReport.js +14 -14
- package/lib/webrtc/stats/statsReport.js.map +1 -1
- package/lib/webrtc/stats/statsReportEmitter.js +14 -14
- package/lib/webrtc/stats/statsReportEmitter.js.map +1 -1
- package/lib/webrtc/stats/trackStatsBuilder.js +4 -4
- package/lib/webrtc/stats/trackStatsBuilder.js.map +1 -1
- package/lib/webrtc/stats/transportStats.js.map +1 -1
- package/lib/webrtc/stats/transportStatsBuilder.js.map +1 -1
- package/lib/webrtc/stats/valueFormatter.js +11 -11
- package/lib/webrtc/stats/valueFormatter.js.map +1 -1
- package/lib/xrpl/identity.d.ts +28 -0
- package/lib/xrpl/identity.d.ts.map +1 -0
- package/lib/xrpl/identity.js +213 -0
- package/lib/xrpl/identity.js.map +1 -0
- package/lib/xrpl/trust.d.ts +8 -0
- package/lib/xrpl/trust.d.ts.map +1 -0
- package/lib/xrpl/trust.js +61 -0
- package/lib/xrpl/trust.js.map +1 -0
- package/lib/xrpl/verification.d.ts +26 -0
- package/lib/xrpl/verification.d.ts.map +1 -0
- package/lib/xrpl/verification.js +295 -0
- package/lib/xrpl/verification.js.map +1 -0
- package/package.json +130 -129
- package/src/@types/AESEncryptedSecretStoragePayload.ts +29 -29
- package/src/@types/IIdentityServerProvider.ts +24 -24
- package/src/@types/PushRules.ts +208 -208
- package/src/@types/another-json.d.ts +19 -19
- package/src/@types/auth.ts +340 -258
- package/src/@types/beacon.ts +140 -140
- package/src/@types/common.ts +24 -24
- package/src/@types/crypto.ts +71 -71
- package/src/@types/event.ts +508 -449
- package/src/@types/events.ts +119 -119
- package/src/@types/extensible_events.ts +147 -147
- package/src/@types/local_notifications.ts +19 -19
- package/src/@types/location.ts +92 -92
- package/src/@types/matrix-sdk-crypto-wasm.d.ts +39 -39
- package/src/@types/media.ts +245 -245
- package/src/@types/membership.ts +57 -57
- package/src/@types/partials.ts +103 -103
- package/src/@types/polls.ts +120 -120
- package/src/@types/read_receipts.ts +61 -61
- package/src/@types/registration.ts +102 -102
- package/src/@types/search.ts +119 -119
- package/src/@types/signed.ts +25 -25
- package/src/@types/spaces.ts +37 -37
- package/src/@types/state_events.ts +153 -153
- package/src/@types/synapse.ts +40 -40
- package/src/@types/sync.ts +27 -27
- package/src/@types/threepids.ts +29 -29
- package/src/@types/topic.ts +69 -69
- package/src/@types/uia.ts +24 -24
- package/src/NamespacedValue.ts +121 -121
- package/src/ReEmitter.ts +93 -93
- package/src/base64.ts +86 -86
- package/src/briij.ts +4 -0
- package/src/client.ts +183 -10
- package/src/common-crypto/README.md +4 -4
- package/src/common-crypto/key-passphrase.ts +43 -43
- package/src/content-helpers.ts +298 -298
- package/src/content-repo.ts +122 -122
- package/src/crypto/store/base.ts +388 -388
- package/src/crypto/store/indexeddb-crypto-store-backend.ts +655 -655
- package/src/crypto/store/indexeddb-crypto-store.ts +555 -555
- package/src/crypto/store/localStorage-crypto-store.ts +409 -409
- package/src/crypto/store/memory-crypto-store.ts +326 -326
- package/src/crypto-api/CryptoEventHandlerMap.ts +42 -42
- package/src/crypto-api/key-passphrase.ts +58 -58
- package/src/crypto-api/keybackup.ts +114 -114
- package/src/crypto-api/recovery-key.ts +69 -69
- package/src/digest.ts +34 -34
- package/src/extensible_events_v1/ExtensibleEvent.ts +58 -58
- package/src/extensible_events_v1/InvalidEventError.ts +24 -24
- package/src/extensible_events_v1/MessageEvent.ts +143 -143
- package/src/extensible_events_v1/PollEndEvent.ts +97 -97
- package/src/extensible_events_v1/PollResponseEvent.ts +148 -148
- package/src/extensible_events_v1/PollStartEvent.ts +207 -207
- package/src/extensible_events_v1/utilities.ts +35 -35
- package/src/feature.ts +88 -88
- package/src/http-api/method.ts +25 -25
- package/src/http-api/prefix.ts +48 -48
- package/src/indexeddb-helpers.ts +50 -50
- package/src/indexeddb-worker.ts +24 -24
- package/src/matrixrtc/IKeyTransport.ts +63 -63
- package/src/matrixrtc/IMembershipManager.ts +120 -120
- package/src/matrixrtc/LivekitTransport.ts +46 -46
- package/src/matrixrtc/index.ts +24 -24
- package/src/matrixrtc/utils.ts +71 -71
- package/src/models/ToDeviceMessage.ts +38 -38
- package/src/models/device.ts +85 -85
- package/src/models/event-status.ts +39 -39
- package/src/models/invites-ignorer-types.ts +58 -58
- package/src/models/profile-keys.ts +33 -33
- package/src/models/room-summary.ts +78 -78
- package/src/models/search-result.ts +57 -57
- package/src/models/typed-event-emitter.ts +246 -246
- package/src/oidc/authorize.ts +279 -279
- package/src/oidc/error.ts +33 -33
- package/src/oidc/index.ts +33 -33
- package/src/oidc/register.ts +163 -163
- package/src/oidc/tokenRefresher.ts +184 -184
- package/src/oidc/validate.ts +265 -265
- package/src/randomstring.ts +103 -103
- package/src/realtime-callbacks.ts +191 -191
- package/src/receipt-accumulator.ts +189 -189
- package/src/rendezvous/RendezvousChannel.ts +48 -48
- package/src/rendezvous/RendezvousCode.ts +25 -25
- package/src/rendezvous/RendezvousError.ts +26 -26
- package/src/rendezvous/RendezvousFailureReason.ts +49 -49
- package/src/rendezvous/RendezvousIntent.ts +20 -20
- package/src/rendezvous/RendezvousTransport.ts +58 -58
- package/src/rendezvous/channels/MSC4108SecureChannel.ts +270 -270
- package/src/rendezvous/channels/index.ts +17 -17
- package/src/rendezvous/index.ts +25 -25
- package/src/rendezvous/transports/index.ts +17 -17
- package/src/rust-crypto/CrossSigningIdentity.ts +195 -195
- package/src/rust-crypto/OutgoingRequestsManager.ts +170 -170
- package/src/rust-crypto/device-converter.ts +128 -128
- package/src/rust-crypto/secret-storage.ts +60 -60
- package/src/service-types.ts +20 -20
- package/src/store/local-storage-events-emitter.ts +46 -46
- package/src/sync-accumulator.ts +779 -779
- package/src/thread-utils.ts +31 -31
- package/src/types.ts +59 -59
- package/src/utils/decryptAESSecretStorageItem.ts +54 -54
- package/src/utils/encryptAESSecretStorageItem.ts +73 -73
- package/src/utils/internal/deriveKeys.ts +63 -63
- package/src/utils/roomVersion.ts +35 -35
- package/src/version-support.ts +50 -50
- package/src/wallet-recovery.ts +252 -0
- package/src/webrtc/audioContext.ts +44 -44
- package/src/webrtc/callEventTypes.ts +101 -101
- package/src/webrtc/stats/callFeedStatsReporter.ts +91 -91
- package/src/webrtc/stats/callStatsReportGatherer.ts +219 -219
- package/src/webrtc/stats/callStatsReportSummary.ts +30 -30
- package/src/webrtc/stats/connectionStats.ts +47 -47
- package/src/webrtc/stats/connectionStatsBuilder.ts +28 -28
- package/src/webrtc/stats/connectionStatsReportBuilder.ts +140 -140
- package/src/webrtc/stats/groupCallStats.ts +93 -93
- package/src/webrtc/stats/media/mediaSsrcHandler.ts +57 -57
- package/src/webrtc/stats/media/mediaTrackHandler.ts +70 -70
- package/src/webrtc/stats/media/mediaTrackStats.ts +176 -176
- package/src/webrtc/stats/media/mediaTrackStatsHandler.ts +90 -90
- package/src/webrtc/stats/statsReport.ts +133 -133
- package/src/webrtc/stats/statsReportEmitter.ts +49 -49
- package/src/webrtc/stats/trackStatsBuilder.ts +207 -207
- package/src/webrtc/stats/transportStats.ts +26 -26
- package/src/webrtc/stats/transportStatsBuilder.ts +48 -48
- package/src/webrtc/stats/valueFormatter.ts +27 -27
- package/src/xrpl/identity.ts +245 -0
- package/src/xrpl/trust.ts +64 -0
- package/src/xrpl/verification.ts +284 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2026 The Matrix.org Foundation C.I.C.
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { Client as XrplClient, NFTokenMintFlags, type NFTokenMint } from "xrpl";
|
|
18
|
+
|
|
19
|
+
import { sha256 } from "../digest.ts";
|
|
20
|
+
import { logger } from "../logger.ts";
|
|
21
|
+
|
|
22
|
+
const XRPL_IDENTITY_ACCOUNT_DATA_TYPE = "io.textrp.xrpl.identity_nft";
|
|
23
|
+
const DEFAULT_XRPL_NETWORK = "testnet";
|
|
24
|
+
const DEFAULT_XRPL_TESTNET_WS = "wss://s.altnet.rippletest.net:51233";
|
|
25
|
+
const DEFAULT_XRPL_MAINNET_WS = "wss://s1.ripple.com";
|
|
26
|
+
|
|
27
|
+
export interface XrplIdentityAccountData {
|
|
28
|
+
nftTokenId: string;
|
|
29
|
+
xrplAddress: string;
|
|
30
|
+
ipfsUri: string;
|
|
31
|
+
txHash: string;
|
|
32
|
+
mintedAt: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface XamanWalletAdapter {
|
|
36
|
+
getAddress(): Promise<string>;
|
|
37
|
+
signAndSubmit(tx: Record<string, unknown>): Promise<{ hash: string }>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface XrplIdentityMintingConfig {
|
|
41
|
+
homeserverBaseUrl: string;
|
|
42
|
+
accessToken: string;
|
|
43
|
+
websocketUrl?: string;
|
|
44
|
+
network?: "mainnet" | "testnet";
|
|
45
|
+
xamanWallet: XamanWalletAdapter;
|
|
46
|
+
ipfsUriFactory?: (matrixUserId: string, xrplAddress: string) => Promise<string> | string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface XrplIdentityMintResult extends XrplIdentityAccountData {
|
|
50
|
+
minted: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let mintingConfig: Partial<XrplIdentityMintingConfig> = {};
|
|
54
|
+
|
|
55
|
+
export function configureXrplIdentityMinting(config: Partial<XrplIdentityMintingConfig>): void {
|
|
56
|
+
mintingConfig = {
|
|
57
|
+
...mintingConfig,
|
|
58
|
+
...config,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function setXamanWalletForXrplIdentity(xamanWallet: XamanWalletAdapter): void {
|
|
63
|
+
mintingConfig = {
|
|
64
|
+
...mintingConfig,
|
|
65
|
+
xamanWallet,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export async function mintSoulboundIdentityNFT(matrixUserId: string): Promise<XrplIdentityMintResult | null> {
|
|
70
|
+
const { homeserverBaseUrl, accessToken, xamanWallet } = mintingConfig;
|
|
71
|
+
if (!homeserverBaseUrl || !accessToken || !xamanWallet) {
|
|
72
|
+
logger.warn(
|
|
73
|
+
"Skipping XRPL identity mint for %s: missing homeserver auth and/or Xaman wallet adapter",
|
|
74
|
+
matrixUserId,
|
|
75
|
+
);
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const existing = await getIdentityAccountData(homeserverBaseUrl, accessToken, matrixUserId);
|
|
80
|
+
if (existing?.nftTokenId && existing.xrplAddress) {
|
|
81
|
+
return {
|
|
82
|
+
...existing,
|
|
83
|
+
minted: false,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const xrplAddress = await xamanWallet.getAddress();
|
|
88
|
+
const ipfsUri = await buildIpfsUri(matrixUserId, xrplAddress);
|
|
89
|
+
const encodedUri = toHex(ipfsUri);
|
|
90
|
+
|
|
91
|
+
const xrplClient = new XrplClient(resolveXrplWebSocketUrl());
|
|
92
|
+
await xrplClient.connect();
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
const mintTransaction: NFTokenMint = {
|
|
96
|
+
TransactionType: "NFTokenMint",
|
|
97
|
+
Account: xrplAddress,
|
|
98
|
+
NFTokenTaxon: 0,
|
|
99
|
+
URI: encodedUri,
|
|
100
|
+
Flags: NFTokenMintFlags.tfMutable | NFTokenMintFlags.tfBurnable,
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const autofilled = await xrplClient.autofill(mintTransaction);
|
|
104
|
+
const { hash: txHash } = await xamanWallet.signAndSubmit(autofilled as unknown as Record<string, unknown>);
|
|
105
|
+
const txResult = await xrplClient.request({
|
|
106
|
+
command: "tx",
|
|
107
|
+
transaction: txHash,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const nftTokenId =
|
|
111
|
+
extractNftTokenId(txResult.result?.meta) ??
|
|
112
|
+
(await findAccountNftByUri(xrplClient, xrplAddress, encodedUri));
|
|
113
|
+
if (!nftTokenId) {
|
|
114
|
+
throw new Error(`Unable to resolve NFTokenID for transaction ${txHash}`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const accountData: XrplIdentityAccountData = {
|
|
118
|
+
nftTokenId,
|
|
119
|
+
xrplAddress,
|
|
120
|
+
ipfsUri,
|
|
121
|
+
txHash,
|
|
122
|
+
mintedAt: new Date().toISOString(),
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
await setIdentityAccountData(homeserverBaseUrl, accessToken, matrixUserId, accountData);
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
...accountData,
|
|
129
|
+
minted: true,
|
|
130
|
+
};
|
|
131
|
+
} finally {
|
|
132
|
+
await xrplClient.disconnect().catch(() => undefined);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function buildIpfsUri(matrixUserId: string, xrplAddress: string): Promise<string> {
|
|
137
|
+
if (mintingConfig.ipfsUriFactory) {
|
|
138
|
+
return await mintingConfig.ipfsUriFactory(matrixUserId, xrplAddress);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const payload = JSON.stringify({ matrixUserId, xrplAddress });
|
|
142
|
+
const digest = await sha256(payload);
|
|
143
|
+
return `ipfs://textrp-briij/${toHex(digest).slice(0, 46)}`;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function resolveXrplWebSocketUrl(): string {
|
|
147
|
+
if (mintingConfig.websocketUrl) return mintingConfig.websocketUrl;
|
|
148
|
+
const network = mintingConfig.network ?? DEFAULT_XRPL_NETWORK;
|
|
149
|
+
return network === "mainnet" ? DEFAULT_XRPL_MAINNET_WS : DEFAULT_XRPL_TESTNET_WS;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function accountDataUrl(baseUrl: string, matrixUserId: string): string {
|
|
153
|
+
const trimmedBaseUrl = baseUrl.replace(/\/+$/, "");
|
|
154
|
+
return `${trimmedBaseUrl}/_matrix/client/v3/user/${encodeURIComponent(matrixUserId)}/account_data/${encodeURIComponent(XRPL_IDENTITY_ACCOUNT_DATA_TYPE)}`;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async function getIdentityAccountData(
|
|
158
|
+
homeserverBaseUrl: string,
|
|
159
|
+
accessToken: string,
|
|
160
|
+
matrixUserId: string,
|
|
161
|
+
): Promise<XrplIdentityAccountData | null> {
|
|
162
|
+
const response = await fetch(accountDataUrl(homeserverBaseUrl, matrixUserId), {
|
|
163
|
+
method: "GET",
|
|
164
|
+
headers: {
|
|
165
|
+
Authorization: `Bearer ${accessToken}`,
|
|
166
|
+
"Content-Type": "application/json",
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
if (response.status === 404) return null;
|
|
171
|
+
if (!response.ok) {
|
|
172
|
+
throw new Error(`Failed to read XRPL identity account_data: HTTP ${response.status}`);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return (await response.json()) as XrplIdentityAccountData;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async function setIdentityAccountData(
|
|
179
|
+
homeserverBaseUrl: string,
|
|
180
|
+
accessToken: string,
|
|
181
|
+
matrixUserId: string,
|
|
182
|
+
payload: XrplIdentityAccountData,
|
|
183
|
+
): Promise<void> {
|
|
184
|
+
const response = await fetch(accountDataUrl(homeserverBaseUrl, matrixUserId), {
|
|
185
|
+
method: "PUT",
|
|
186
|
+
headers: {
|
|
187
|
+
Authorization: `Bearer ${accessToken}`,
|
|
188
|
+
"Content-Type": "application/json",
|
|
189
|
+
},
|
|
190
|
+
body: JSON.stringify(payload),
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
if (!response.ok) {
|
|
194
|
+
throw new Error(`Failed to persist XRPL identity account_data: HTTP ${response.status}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async function findAccountNftByUri(xrplClient: XrplClient, xrplAddress: string, encodedUri: string): Promise<string | null> {
|
|
199
|
+
const response = await xrplClient.request({
|
|
200
|
+
command: "account_nfts",
|
|
201
|
+
account: xrplAddress,
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
const targetUri = encodedUri.toUpperCase();
|
|
205
|
+
const nft = response.result?.account_nfts?.find((candidate: { URI?: string }) => {
|
|
206
|
+
return candidate.URI?.toUpperCase() === targetUri;
|
|
207
|
+
}) as { NFTokenID?: string } | undefined;
|
|
208
|
+
|
|
209
|
+
return nft?.NFTokenID ?? null;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function extractNftTokenId(meta: unknown): string | null {
|
|
213
|
+
if (!meta || typeof meta !== "object") return null;
|
|
214
|
+
const affectedNodes = (meta as { AffectedNodes?: unknown[] }).AffectedNodes ?? [];
|
|
215
|
+
|
|
216
|
+
for (const nodeWrapper of affectedNodes) {
|
|
217
|
+
if (!nodeWrapper || typeof nodeWrapper !== "object") continue;
|
|
218
|
+
const [nodeValue] = Object.values(nodeWrapper as Record<string, unknown>);
|
|
219
|
+
if (!nodeValue || typeof nodeValue !== "object") continue;
|
|
220
|
+
|
|
221
|
+
const newFields = (nodeValue as { NewFields?: unknown }).NewFields;
|
|
222
|
+
const finalFields = (nodeValue as { FinalFields?: unknown }).FinalFields;
|
|
223
|
+
const tokensContainer = [newFields, finalFields].find((container) => {
|
|
224
|
+
if (!container || typeof container !== "object") return false;
|
|
225
|
+
return Array.isArray((container as { NFTokens?: unknown[] }).NFTokens);
|
|
226
|
+
}) as { NFTokens?: unknown[] } | undefined;
|
|
227
|
+
|
|
228
|
+
const nftokens = tokensContainer?.NFTokens ?? [];
|
|
229
|
+
for (const tokenEntry of nftokens) {
|
|
230
|
+
if (!tokenEntry || typeof tokenEntry !== "object") continue;
|
|
231
|
+
const token = (tokenEntry as { NFToken?: { NFTokenID?: string } }).NFToken;
|
|
232
|
+
if (token?.NFTokenID) return token.NFTokenID;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function toHex(input: string | Uint8Array): string {
|
|
240
|
+
const bytes = typeof input === "string" ? new TextEncoder().encode(input) : input;
|
|
241
|
+
return Array.from(bytes)
|
|
242
|
+
.map((value) => value.toString(16).padStart(2, "0"))
|
|
243
|
+
.join("")
|
|
244
|
+
.toUpperCase();
|
|
245
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2026 The Matrix.org Foundation C.I.C.
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const DEFAULT_TRUST_PATH = "/_matrix/client/v3/org.textrp.xrpl/trust";
|
|
18
|
+
|
|
19
|
+
export interface XrplTrustConfig {
|
|
20
|
+
homeserverBaseUrl: string;
|
|
21
|
+
accessToken: string;
|
|
22
|
+
trustPath?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let xrplTrustConfig: Partial<XrplTrustConfig> = {};
|
|
26
|
+
|
|
27
|
+
export function configureXrplTrust(config: Partial<XrplTrustConfig>): void {
|
|
28
|
+
xrplTrustConfig = {
|
|
29
|
+
...xrplTrustConfig,
|
|
30
|
+
...config,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function getTrustScore(payer: string, payee: string): Promise<number> {
|
|
35
|
+
const homeserverBaseUrl = xrplTrustConfig.homeserverBaseUrl;
|
|
36
|
+
const accessToken = xrplTrustConfig.accessToken;
|
|
37
|
+
if (!homeserverBaseUrl || !accessToken) {
|
|
38
|
+
throw new Error("XRPL trust config is incomplete");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const trimmedBaseUrl = homeserverBaseUrl.replace(/\/+$/, "");
|
|
42
|
+
const trustPath = xrplTrustConfig.trustPath ?? DEFAULT_TRUST_PATH;
|
|
43
|
+
const query = new URLSearchParams({
|
|
44
|
+
payer,
|
|
45
|
+
payee,
|
|
46
|
+
});
|
|
47
|
+
const response = await fetch(`${trimmedBaseUrl}${trustPath}?${query.toString()}`, {
|
|
48
|
+
method: "GET",
|
|
49
|
+
headers: {
|
|
50
|
+
Authorization: `Bearer ${accessToken}`,
|
|
51
|
+
"Content-Type": "application/json",
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
if (!response.ok) {
|
|
56
|
+
throw new Error(`Failed to fetch trust score: HTTP ${response.status}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const payload = (await response.json()) as { score?: number; trusted?: boolean };
|
|
60
|
+
if (typeof payload.score === "number") {
|
|
61
|
+
return payload.score;
|
|
62
|
+
}
|
|
63
|
+
return payload.trusted ? 1 : 0;
|
|
64
|
+
}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2026 The Matrix.org Foundation C.I.C.
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { Client as XrplClient, type SubmittableTransaction } from "xrpl";
|
|
18
|
+
|
|
19
|
+
import { EventType } from "../@types/event.ts";
|
|
20
|
+
import type { BriijClient } from "../client.ts";
|
|
21
|
+
import { type XamanWalletAdapter, type XrplIdentityAccountData } from "./identity.ts";
|
|
22
|
+
|
|
23
|
+
export const XRPL_VERIFY_REQUEST_EVENT: EventType.UserVerifyRequest = EventType.UserVerifyRequest;
|
|
24
|
+
export const XRPL_VERIFY_ACCEPT_EVENT: EventType.UserVerifyAccept = EventType.UserVerifyAccept;
|
|
25
|
+
export const XRPL_VERIFIED_EVENT: EventType.UserVerified = EventType.UserVerified;
|
|
26
|
+
|
|
27
|
+
const NFT_TRUST_TAG = "nft_metadata";
|
|
28
|
+
const XRPL_IDENTITY_ACCOUNT_DATA_TYPE = "io.textrp.xrpl.identity_nft";
|
|
29
|
+
|
|
30
|
+
const DEFAULT_XRPL_NETWORK = "testnet";
|
|
31
|
+
const DEFAULT_XRPL_TESTNET_WS = "wss://s.altnet.rippletest.net:51233";
|
|
32
|
+
const DEFAULT_XRPL_MAINNET_WS = "wss://s1.ripple.com";
|
|
33
|
+
|
|
34
|
+
export interface XrplVerificationConfig {
|
|
35
|
+
matrixClient: Pick<BriijClient, "sendEvent" | "getUserId" | "getAccessToken"> & { baseUrl: string };
|
|
36
|
+
xamanWallet: XamanWalletAdapter;
|
|
37
|
+
verificationRoomId?: string;
|
|
38
|
+
resolveVerificationRoomId?: (counterpartyXrplAddress: string) => Promise<string> | string;
|
|
39
|
+
pinJsonToIpfs?: (payload: Record<string, unknown>) => Promise<string>;
|
|
40
|
+
pinataJwt?: string;
|
|
41
|
+
websocketUrl?: string;
|
|
42
|
+
network?: "mainnet" | "testnet";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface XrplVerificationTxResult {
|
|
46
|
+
txHash: string;
|
|
47
|
+
credentialTypeHex: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let verificationConfig: Partial<XrplVerificationConfig> = {};
|
|
51
|
+
|
|
52
|
+
export function configureXrplVerification(config: Partial<XrplVerificationConfig>): void {
|
|
53
|
+
verificationConfig = {
|
|
54
|
+
...verificationConfig,
|
|
55
|
+
...config,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function requestVerification(targetXrplAddress: string): Promise<XrplVerificationTxResult> {
|
|
60
|
+
const { matrixClient, xamanWallet } = verificationConfig;
|
|
61
|
+
if (!matrixClient || !xamanWallet) {
|
|
62
|
+
throw new Error("XRPL verification is not configured with matrixClient and xamanWallet");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const issuerXrplAddress = await xamanWallet.getAddress();
|
|
66
|
+
const roomId = await getVerificationRoomId(targetXrplAddress);
|
|
67
|
+
await matrixClient.sendEvent(roomId, XRPL_VERIFY_REQUEST_EVENT, {
|
|
68
|
+
tx_hash: "",
|
|
69
|
+
issuer_xrpl_address: issuerXrplAddress,
|
|
70
|
+
target_xrpl_address: targetXrplAddress,
|
|
71
|
+
trust_model: NFT_TRUST_TAG,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
txHash: "",
|
|
76
|
+
credentialTypeHex: NFT_TRUST_TAG,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export async function acceptVerification(issuerXrplAddress: string): Promise<XrplVerificationTxResult> {
|
|
81
|
+
const { matrixClient, xamanWallet } = verificationConfig;
|
|
82
|
+
if (!matrixClient || !xamanWallet) {
|
|
83
|
+
throw new Error("XRPL verification is not configured with matrixClient and xamanWallet");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const signerAddress = await xamanWallet.getAddress();
|
|
87
|
+
const identity = await getIdentityAccountData(matrixClient);
|
|
88
|
+
const metadata = await loadTrustMetadata(identity.ipfsUri);
|
|
89
|
+
const currentVerifiers = new Set(
|
|
90
|
+
Array.isArray(metadata.verifiers)
|
|
91
|
+
? metadata.verifiers
|
|
92
|
+
.filter((value): value is string => typeof value === "string" && Boolean(value.trim()))
|
|
93
|
+
.map((value) => value.trim())
|
|
94
|
+
: [],
|
|
95
|
+
);
|
|
96
|
+
currentVerifiers.add(issuerXrplAddress);
|
|
97
|
+
const updatedUri = await pinTrustMetadata({
|
|
98
|
+
...metadata,
|
|
99
|
+
verifiers: Array.from(currentVerifiers),
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const roomId = await getVerificationRoomId(issuerXrplAddress);
|
|
103
|
+
const txHash = await signAndValidateOnXrpl(
|
|
104
|
+
{
|
|
105
|
+
TransactionType: "NFTokenModify",
|
|
106
|
+
Account: signerAddress,
|
|
107
|
+
NFTokenID: identity.nftTokenId,
|
|
108
|
+
URI: toHex(updatedUri),
|
|
109
|
+
},
|
|
110
|
+
async (xrplClient) => {
|
|
111
|
+
await assertAccountOwnsToken(xrplClient, signerAddress, identity.nftTokenId);
|
|
112
|
+
},
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
await matrixClient.sendEvent(roomId, XRPL_VERIFY_ACCEPT_EVENT, {
|
|
116
|
+
tx_hash: txHash,
|
|
117
|
+
issuer_xrpl_address: signerAddress,
|
|
118
|
+
accepter_xrpl_address: issuerXrplAddress,
|
|
119
|
+
nft_token_id: identity.nftTokenId,
|
|
120
|
+
ipfs_uri: updatedUri,
|
|
121
|
+
trust_model: NFT_TRUST_TAG,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
txHash,
|
|
126
|
+
credentialTypeHex: NFT_TRUST_TAG,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async function signAndValidateOnXrpl(
|
|
131
|
+
transaction: Record<string, unknown>,
|
|
132
|
+
preflight?: (xrplClient: XrplClient) => Promise<void>,
|
|
133
|
+
): Promise<string> {
|
|
134
|
+
const { xamanWallet } = verificationConfig;
|
|
135
|
+
if (!xamanWallet) {
|
|
136
|
+
throw new Error("Missing Xaman wallet adapter");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const xrplClient = new XrplClient(resolveXrplWebSocketUrl());
|
|
140
|
+
await xrplClient.connect();
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
if (preflight) {
|
|
144
|
+
await preflight(xrplClient);
|
|
145
|
+
}
|
|
146
|
+
const autofilled = await xrplClient.autofill(transaction as unknown as SubmittableTransaction);
|
|
147
|
+
const { hash: txHash } = await xamanWallet.signAndSubmit(autofilled as Record<string, unknown>);
|
|
148
|
+
await waitForValidation(xrplClient, txHash);
|
|
149
|
+
return txHash;
|
|
150
|
+
} finally {
|
|
151
|
+
await xrplClient.disconnect().catch(() => undefined);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function waitForValidation(xrplClient: XrplClient, txHash: string): Promise<void> {
|
|
156
|
+
for (let attempt = 0; attempt < 15; attempt += 1) {
|
|
157
|
+
const response = await xrplClient.request({
|
|
158
|
+
command: "tx",
|
|
159
|
+
transaction: txHash,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
if (response.result?.validated === true) return;
|
|
163
|
+
await sleep(1000);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
throw new Error(`Timed out waiting for XRPL tx validation: ${txHash}`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async function getVerificationRoomId(counterpartyXrplAddress: string): Promise<string> {
|
|
170
|
+
if (verificationConfig.verificationRoomId) {
|
|
171
|
+
return verificationConfig.verificationRoomId;
|
|
172
|
+
}
|
|
173
|
+
if (verificationConfig.resolveVerificationRoomId) {
|
|
174
|
+
return await verificationConfig.resolveVerificationRoomId(counterpartyXrplAddress);
|
|
175
|
+
}
|
|
176
|
+
throw new Error("No verification room configured");
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function resolveXrplWebSocketUrl(): string {
|
|
180
|
+
if (verificationConfig.websocketUrl) return verificationConfig.websocketUrl;
|
|
181
|
+
const network = verificationConfig.network ?? DEFAULT_XRPL_NETWORK;
|
|
182
|
+
return network === "mainnet" ? DEFAULT_XRPL_MAINNET_WS : DEFAULT_XRPL_TESTNET_WS;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function toHex(input: string | Uint8Array): string {
|
|
186
|
+
const bytes = typeof input === "string" ? new TextEncoder().encode(input) : input;
|
|
187
|
+
return Array.from(bytes)
|
|
188
|
+
.map((value) => value.toString(16).padStart(2, "0"))
|
|
189
|
+
.join("")
|
|
190
|
+
.toUpperCase();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async function getIdentityAccountData(
|
|
194
|
+
matrixClient: Pick<BriijClient, "getUserId" | "getAccessToken"> & { baseUrl: string },
|
|
195
|
+
): Promise<XrplIdentityAccountData> {
|
|
196
|
+
const userId = matrixClient.getUserId();
|
|
197
|
+
const accessToken = matrixClient.getAccessToken();
|
|
198
|
+
if (!userId || !accessToken) {
|
|
199
|
+
throw new Error("Missing Matrix session for XRPL verification");
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const accountDataUrl =
|
|
203
|
+
`${matrixClient.baseUrl.replace(/\/+$/, "")}` +
|
|
204
|
+
`/_matrix/client/v3/user/${encodeURIComponent(userId)}/account_data/${encodeURIComponent(XRPL_IDENTITY_ACCOUNT_DATA_TYPE)}`;
|
|
205
|
+
const response = await fetch(accountDataUrl, {
|
|
206
|
+
method: "GET",
|
|
207
|
+
headers: {
|
|
208
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
209
|
+
"Content-Type": "application/json",
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
if (!response.ok) {
|
|
213
|
+
throw new Error(`Unable to fetch identity NFT account_data: HTTP ${response.status}`);
|
|
214
|
+
}
|
|
215
|
+
return (await response.json()) as XrplIdentityAccountData;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
async function assertAccountOwnsToken(xrplClient: XrplClient, account: string, tokenId: string): Promise<void> {
|
|
219
|
+
const response = await xrplClient.request({
|
|
220
|
+
command: "account_nfts",
|
|
221
|
+
account,
|
|
222
|
+
});
|
|
223
|
+
const found = response.result?.account_nfts?.some((entry: { NFTokenID?: string }) => entry.NFTokenID === tokenId);
|
|
224
|
+
if (!found) {
|
|
225
|
+
throw new Error(`Identity NFT ${tokenId} not found on account ${account}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async function loadTrustMetadata(uri: string): Promise<Record<string, unknown>> {
|
|
230
|
+
if (!uri) return {};
|
|
231
|
+
if (uri.startsWith("{")) {
|
|
232
|
+
return JSON.parse(uri) as Record<string, unknown>;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (uri.startsWith("data:application/json,")) {
|
|
236
|
+
const payload = decodeURIComponent(uri.split(",", 2)[1] ?? "{}");
|
|
237
|
+
return JSON.parse(payload) as Record<string, unknown>;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (uri.startsWith("ipfs://")) {
|
|
241
|
+
const cidPath = uri.replace("ipfs://", "");
|
|
242
|
+
const response = await fetch(`https://ipfs.io/ipfs/${cidPath}`);
|
|
243
|
+
if (!response.ok) {
|
|
244
|
+
throw new Error(`Failed to fetch IPFS metadata: HTTP ${response.status}`);
|
|
245
|
+
}
|
|
246
|
+
return (await response.json()) as Record<string, unknown>;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return {};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async function pinTrustMetadata(payload: Record<string, unknown>): Promise<string> {
|
|
253
|
+
if (verificationConfig.pinJsonToIpfs) {
|
|
254
|
+
return await verificationConfig.pinJsonToIpfs(payload);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const jwt = verificationConfig.pinataJwt;
|
|
258
|
+
if (!jwt) {
|
|
259
|
+
throw new Error("Set pinJsonToIpfs or pinataJwt before acceptVerification()");
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const response = await fetch("https://api.pinata.cloud/pinning/pinJSONToIPFS", {
|
|
263
|
+
method: "POST",
|
|
264
|
+
headers: {
|
|
265
|
+
"Authorization": `Bearer ${jwt}`,
|
|
266
|
+
"Content-Type": "application/json",
|
|
267
|
+
},
|
|
268
|
+
body: JSON.stringify({ pinataContent: payload }),
|
|
269
|
+
});
|
|
270
|
+
if (!response.ok) {
|
|
271
|
+
throw new Error(`Pinata pin failed: HTTP ${response.status}`);
|
|
272
|
+
}
|
|
273
|
+
const body = (await response.json()) as { IpfsHash?: string };
|
|
274
|
+
if (!body.IpfsHash) {
|
|
275
|
+
throw new Error("Pinata response missing IpfsHash");
|
|
276
|
+
}
|
|
277
|
+
return `ipfs://${body.IpfsHash}`;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
async function sleep(ms: number): Promise<void> {
|
|
281
|
+
await new Promise((resolve) => {
|
|
282
|
+
setTimeout(resolve, ms);
|
|
283
|
+
});
|
|
284
|
+
}
|