@originals/sdk 1.1.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/.eslintrc.json +33 -0
- package/.turbo/turbo-build.log +1 -0
- package/.turbo/turbo-test.log +68353 -0
- package/dist/adapters/FeeOracleMock.d.ts +6 -0
- package/dist/adapters/FeeOracleMock.js +8 -0
- package/dist/adapters/index.d.ts +4 -0
- package/dist/adapters/index.js +4 -0
- package/dist/adapters/providers/OrdHttpProvider.d.ts +56 -0
- package/dist/adapters/providers/OrdHttpProvider.js +110 -0
- package/dist/adapters/providers/OrdMockProvider.d.ts +70 -0
- package/dist/adapters/providers/OrdMockProvider.js +75 -0
- package/dist/adapters/types.d.ts +71 -0
- package/dist/adapters/types.js +1 -0
- package/dist/bitcoin/BitcoinManager.d.ts +15 -0
- package/dist/bitcoin/BitcoinManager.js +262 -0
- package/dist/bitcoin/BroadcastClient.d.ts +30 -0
- package/dist/bitcoin/BroadcastClient.js +35 -0
- package/dist/bitcoin/OrdinalsClient.d.ts +21 -0
- package/dist/bitcoin/OrdinalsClient.js +105 -0
- package/dist/bitcoin/PSBTBuilder.d.ts +24 -0
- package/dist/bitcoin/PSBTBuilder.js +80 -0
- package/dist/bitcoin/fee-calculation.d.ts +14 -0
- package/dist/bitcoin/fee-calculation.js +31 -0
- package/dist/bitcoin/providers/OrdNodeProvider.d.ts +38 -0
- package/dist/bitcoin/providers/OrdNodeProvider.js +67 -0
- package/dist/bitcoin/providers/OrdinalsProvider.d.ts +33 -0
- package/dist/bitcoin/providers/OrdinalsProvider.js +50 -0
- package/dist/bitcoin/providers/types.d.ts +63 -0
- package/dist/bitcoin/providers/types.js +1 -0
- package/dist/bitcoin/transactions/commit.d.ts +89 -0
- package/dist/bitcoin/transactions/commit.js +311 -0
- package/dist/bitcoin/transactions/index.d.ts +7 -0
- package/dist/bitcoin/transactions/index.js +8 -0
- package/dist/bitcoin/transfer.d.ts +9 -0
- package/dist/bitcoin/transfer.js +26 -0
- package/dist/bitcoin/utxo-selection.d.ts +78 -0
- package/dist/bitcoin/utxo-selection.js +237 -0
- package/dist/bitcoin/utxo.d.ts +26 -0
- package/dist/bitcoin/utxo.js +78 -0
- package/dist/contexts/credentials-v1.json +195 -0
- package/dist/contexts/credentials-v2-examples.json +5 -0
- package/dist/contexts/credentials-v2.json +301 -0
- package/dist/contexts/credentials.json +195 -0
- package/dist/contexts/data-integrity-v2.json +81 -0
- package/dist/contexts/dids.json +57 -0
- package/dist/contexts/ed255192020.json +93 -0
- package/dist/contexts/ordinals-plus.json +23 -0
- package/dist/contexts/originals.json +22 -0
- package/dist/core/OriginalsSDK.d.ts +158 -0
- package/dist/core/OriginalsSDK.js +274 -0
- package/dist/crypto/Multikey.d.ts +30 -0
- package/dist/crypto/Multikey.js +149 -0
- package/dist/crypto/Signer.d.ts +21 -0
- package/dist/crypto/Signer.js +196 -0
- package/dist/crypto/noble-init.d.ts +18 -0
- package/dist/crypto/noble-init.js +106 -0
- package/dist/did/BtcoDidResolver.d.ts +57 -0
- package/dist/did/BtcoDidResolver.js +166 -0
- package/dist/did/DIDManager.d.ts +101 -0
- package/dist/did/DIDManager.js +493 -0
- package/dist/did/Ed25519Verifier.d.ts +30 -0
- package/dist/did/Ed25519Verifier.js +59 -0
- package/dist/did/KeyManager.d.ts +17 -0
- package/dist/did/KeyManager.js +207 -0
- package/dist/did/WebVHManager.d.ts +100 -0
- package/dist/did/WebVHManager.js +304 -0
- package/dist/did/createBtcoDidDocument.d.ts +10 -0
- package/dist/did/createBtcoDidDocument.js +42 -0
- package/dist/did/providers/OrdinalsClientProviderAdapter.d.ts +23 -0
- package/dist/did/providers/OrdinalsClientProviderAdapter.js +51 -0
- package/dist/events/EventEmitter.d.ts +115 -0
- package/dist/events/EventEmitter.js +198 -0
- package/dist/events/index.d.ts +7 -0
- package/dist/events/index.js +6 -0
- package/dist/events/types.d.ts +286 -0
- package/dist/events/types.js +9 -0
- package/dist/examples/basic-usage.d.ts +3 -0
- package/dist/examples/basic-usage.js +62 -0
- package/dist/examples/run.d.ts +1 -0
- package/dist/examples/run.js +4 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.js +47 -0
- package/dist/lifecycle/BatchOperations.d.ts +147 -0
- package/dist/lifecycle/BatchOperations.js +251 -0
- package/dist/lifecycle/LifecycleManager.d.ts +116 -0
- package/dist/lifecycle/LifecycleManager.js +971 -0
- package/dist/lifecycle/OriginalsAsset.d.ts +164 -0
- package/dist/lifecycle/OriginalsAsset.js +380 -0
- package/dist/lifecycle/ProvenanceQuery.d.ts +126 -0
- package/dist/lifecycle/ProvenanceQuery.js +220 -0
- package/dist/lifecycle/ResourceVersioning.d.ts +73 -0
- package/dist/lifecycle/ResourceVersioning.js +127 -0
- package/dist/migration/MigrationManager.d.ts +86 -0
- package/dist/migration/MigrationManager.js +412 -0
- package/dist/migration/audit/AuditLogger.d.ts +51 -0
- package/dist/migration/audit/AuditLogger.js +156 -0
- package/dist/migration/checkpoint/CheckpointManager.d.ts +31 -0
- package/dist/migration/checkpoint/CheckpointManager.js +96 -0
- package/dist/migration/checkpoint/CheckpointStorage.d.ts +26 -0
- package/dist/migration/checkpoint/CheckpointStorage.js +89 -0
- package/dist/migration/index.d.ts +22 -0
- package/dist/migration/index.js +27 -0
- package/dist/migration/operations/BaseMigration.d.ts +48 -0
- package/dist/migration/operations/BaseMigration.js +83 -0
- package/dist/migration/operations/PeerToBtcoMigration.d.ts +25 -0
- package/dist/migration/operations/PeerToBtcoMigration.js +67 -0
- package/dist/migration/operations/PeerToWebvhMigration.d.ts +19 -0
- package/dist/migration/operations/PeerToWebvhMigration.js +46 -0
- package/dist/migration/operations/WebvhToBtcoMigration.d.ts +25 -0
- package/dist/migration/operations/WebvhToBtcoMigration.js +67 -0
- package/dist/migration/rollback/RollbackManager.d.ts +29 -0
- package/dist/migration/rollback/RollbackManager.js +146 -0
- package/dist/migration/state/StateMachine.d.ts +25 -0
- package/dist/migration/state/StateMachine.js +76 -0
- package/dist/migration/state/StateTracker.d.ts +36 -0
- package/dist/migration/state/StateTracker.js +123 -0
- package/dist/migration/types.d.ts +306 -0
- package/dist/migration/types.js +33 -0
- package/dist/migration/validation/BitcoinValidator.d.ts +13 -0
- package/dist/migration/validation/BitcoinValidator.js +83 -0
- package/dist/migration/validation/CredentialValidator.d.ts +13 -0
- package/dist/migration/validation/CredentialValidator.js +46 -0
- package/dist/migration/validation/DIDCompatibilityValidator.d.ts +16 -0
- package/dist/migration/validation/DIDCompatibilityValidator.js +127 -0
- package/dist/migration/validation/LifecycleValidator.d.ts +10 -0
- package/dist/migration/validation/LifecycleValidator.js +52 -0
- package/dist/migration/validation/StorageValidator.d.ts +10 -0
- package/dist/migration/validation/StorageValidator.js +65 -0
- package/dist/migration/validation/ValidationPipeline.d.ts +29 -0
- package/dist/migration/validation/ValidationPipeline.js +180 -0
- package/dist/storage/LocalStorageAdapter.d.ts +11 -0
- package/dist/storage/LocalStorageAdapter.js +53 -0
- package/dist/storage/MemoryStorageAdapter.d.ts +6 -0
- package/dist/storage/MemoryStorageAdapter.js +21 -0
- package/dist/storage/StorageAdapter.d.ts +16 -0
- package/dist/storage/StorageAdapter.js +1 -0
- package/dist/storage/index.d.ts +2 -0
- package/dist/storage/index.js +2 -0
- package/dist/types/bitcoin.d.ts +84 -0
- package/dist/types/bitcoin.js +1 -0
- package/dist/types/common.d.ts +82 -0
- package/dist/types/common.js +1 -0
- package/dist/types/credentials.d.ts +75 -0
- package/dist/types/credentials.js +1 -0
- package/dist/types/did.d.ts +26 -0
- package/dist/types/did.js +1 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.js +5 -0
- package/dist/types/network.d.ts +78 -0
- package/dist/types/network.js +145 -0
- package/dist/utils/EventLogger.d.ts +71 -0
- package/dist/utils/EventLogger.js +232 -0
- package/dist/utils/Logger.d.ts +106 -0
- package/dist/utils/Logger.js +257 -0
- package/dist/utils/MetricsCollector.d.ts +110 -0
- package/dist/utils/MetricsCollector.js +264 -0
- package/dist/utils/bitcoin-address.d.ts +38 -0
- package/dist/utils/bitcoin-address.js +113 -0
- package/dist/utils/cbor.d.ts +2 -0
- package/dist/utils/cbor.js +9 -0
- package/dist/utils/encoding.d.ts +37 -0
- package/dist/utils/encoding.js +120 -0
- package/dist/utils/hash.d.ts +1 -0
- package/dist/utils/hash.js +5 -0
- package/dist/utils/retry.d.ts +10 -0
- package/dist/utils/retry.js +35 -0
- package/dist/utils/satoshi-validation.d.ts +60 -0
- package/dist/utils/satoshi-validation.js +156 -0
- package/dist/utils/serialization.d.ts +14 -0
- package/dist/utils/serialization.js +76 -0
- package/dist/utils/telemetry.d.ts +17 -0
- package/dist/utils/telemetry.js +24 -0
- package/dist/utils/validation.d.ts +5 -0
- package/dist/utils/validation.js +98 -0
- package/dist/vc/CredentialManager.d.ts +22 -0
- package/dist/vc/CredentialManager.js +227 -0
- package/dist/vc/Issuer.d.ts +27 -0
- package/dist/vc/Issuer.js +70 -0
- package/dist/vc/Verifier.d.ts +16 -0
- package/dist/vc/Verifier.js +50 -0
- package/dist/vc/cryptosuites/bbs.d.ts +44 -0
- package/dist/vc/cryptosuites/bbs.js +213 -0
- package/dist/vc/cryptosuites/bbsSimple.d.ts +9 -0
- package/dist/vc/cryptosuites/bbsSimple.js +12 -0
- package/dist/vc/cryptosuites/eddsa.d.ts +30 -0
- package/dist/vc/cryptosuites/eddsa.js +81 -0
- package/dist/vc/documentLoader.d.ts +16 -0
- package/dist/vc/documentLoader.js +59 -0
- package/dist/vc/proofs/data-integrity.d.ts +21 -0
- package/dist/vc/proofs/data-integrity.js +15 -0
- package/dist/vc/utils/jsonld.d.ts +2 -0
- package/dist/vc/utils/jsonld.js +15 -0
- package/package.json +79 -0
- package/src/adapters/FeeOracleMock.ts +9 -0
- package/src/adapters/index.ts +5 -0
- package/src/adapters/providers/OrdHttpProvider.ts +126 -0
- package/src/adapters/providers/OrdMockProvider.ts +101 -0
- package/src/adapters/types.ts +66 -0
- package/src/bitcoin/BitcoinManager.ts +330 -0
- package/src/bitcoin/BroadcastClient.ts +54 -0
- package/src/bitcoin/OrdinalsClient.ts +119 -0
- package/src/bitcoin/PSBTBuilder.ts +106 -0
- package/src/bitcoin/fee-calculation.ts +38 -0
- package/src/bitcoin/providers/OrdNodeProvider.ts +92 -0
- package/src/bitcoin/providers/OrdinalsProvider.ts +56 -0
- package/src/bitcoin/providers/types.ts +59 -0
- package/src/bitcoin/transactions/commit.ts +465 -0
- package/src/bitcoin/transactions/index.ts +13 -0
- package/src/bitcoin/transfer.ts +43 -0
- package/src/bitcoin/utxo-selection.ts +322 -0
- package/src/bitcoin/utxo.ts +113 -0
- package/src/contexts/credentials-v1.json +237 -0
- package/src/contexts/credentials-v2-examples.json +5 -0
- package/src/contexts/credentials-v2.json +340 -0
- package/src/contexts/credentials.json +237 -0
- package/src/contexts/data-integrity-v2.json +81 -0
- package/src/contexts/dids.json +58 -0
- package/src/contexts/ed255192020.json +93 -0
- package/src/contexts/ordinals-plus.json +23 -0
- package/src/contexts/originals.json +22 -0
- package/src/core/OriginalsSDK.ts +416 -0
- package/src/crypto/Multikey.ts +194 -0
- package/src/crypto/Signer.ts +254 -0
- package/src/crypto/noble-init.ts +121 -0
- package/src/did/BtcoDidResolver.ts +227 -0
- package/src/did/DIDManager.ts +694 -0
- package/src/did/Ed25519Verifier.ts +68 -0
- package/src/did/KeyManager.ts +236 -0
- package/src/did/WebVHManager.ts +489 -0
- package/src/did/createBtcoDidDocument.ts +59 -0
- package/src/did/providers/OrdinalsClientProviderAdapter.ts +68 -0
- package/src/events/EventEmitter.ts +222 -0
- package/src/events/index.ts +19 -0
- package/src/events/types.ts +331 -0
- package/src/examples/basic-usage.ts +78 -0
- package/src/examples/run.ts +5 -0
- package/src/index.ts +84 -0
- package/src/lifecycle/BatchOperations.ts +373 -0
- package/src/lifecycle/LifecycleManager.ts +1218 -0
- package/src/lifecycle/OriginalsAsset.ts +524 -0
- package/src/lifecycle/ProvenanceQuery.ts +280 -0
- package/src/lifecycle/ResourceVersioning.ts +163 -0
- package/src/migration/MigrationManager.ts +527 -0
- package/src/migration/audit/AuditLogger.ts +176 -0
- package/src/migration/checkpoint/CheckpointManager.ts +112 -0
- package/src/migration/checkpoint/CheckpointStorage.ts +101 -0
- package/src/migration/index.ts +33 -0
- package/src/migration/operations/BaseMigration.ts +126 -0
- package/src/migration/operations/PeerToBtcoMigration.ts +105 -0
- package/src/migration/operations/PeerToWebvhMigration.ts +62 -0
- package/src/migration/operations/WebvhToBtcoMigration.ts +105 -0
- package/src/migration/rollback/RollbackManager.ts +170 -0
- package/src/migration/state/StateMachine.ts +92 -0
- package/src/migration/state/StateTracker.ts +156 -0
- package/src/migration/types.ts +344 -0
- package/src/migration/validation/BitcoinValidator.ts +107 -0
- package/src/migration/validation/CredentialValidator.ts +62 -0
- package/src/migration/validation/DIDCompatibilityValidator.ts +151 -0
- package/src/migration/validation/LifecycleValidator.ts +64 -0
- package/src/migration/validation/StorageValidator.ts +79 -0
- package/src/migration/validation/ValidationPipeline.ts +213 -0
- package/src/storage/LocalStorageAdapter.ts +61 -0
- package/src/storage/MemoryStorageAdapter.ts +29 -0
- package/src/storage/StorageAdapter.ts +25 -0
- package/src/storage/index.ts +3 -0
- package/src/types/bitcoin.ts +98 -0
- package/src/types/common.ts +92 -0
- package/src/types/credentials.ts +88 -0
- package/src/types/did.ts +31 -0
- package/src/types/external-shims.d.ts +53 -0
- package/src/types/index.ts +7 -0
- package/src/types/network.ts +175 -0
- package/src/utils/EventLogger.ts +298 -0
- package/src/utils/Logger.ts +322 -0
- package/src/utils/MetricsCollector.ts +358 -0
- package/src/utils/bitcoin-address.ts +130 -0
- package/src/utils/cbor.ts +12 -0
- package/src/utils/encoding.ts +127 -0
- package/src/utils/hash.ts +6 -0
- package/src/utils/retry.ts +46 -0
- package/src/utils/satoshi-validation.ts +196 -0
- package/src/utils/serialization.ts +96 -0
- package/src/utils/telemetry.ts +40 -0
- package/src/utils/validation.ts +119 -0
- package/src/vc/CredentialManager.ts +273 -0
- package/src/vc/Issuer.ts +100 -0
- package/src/vc/Verifier.ts +47 -0
- package/src/vc/cryptosuites/bbs.ts +253 -0
- package/src/vc/cryptosuites/bbsSimple.ts +21 -0
- package/src/vc/cryptosuites/eddsa.ts +99 -0
- package/src/vc/documentLoader.ts +67 -0
- package/src/vc/proofs/data-integrity.ts +33 -0
- package/src/vc/utils/jsonld.ts +18 -0
- package/test/logs/did_webvh_QmQsRNhXxPSCSeLjpbKYcNMZj8b1kBQAoC6cZmkFAgmpHt_example_com.jsonl +1 -0
- package/test/logs/did_webvh_QmSQkpD58qxcqMWHYcEmDUn3wk7hHvJwzYTrZmhh6zjPQ8_example_com_users_alice123_profile.jsonl +1 -0
- package/test/logs/did_webvh_QmTMda6VW3cUPdKk5Yc3onnv1vdgEumvWWdP2noAYFSjeG_example_com.jsonl +1 -0
- package/test/logs/did_webvh_QmTkb8KnCYcsnKKDCY4eUQuKQdKJLrCinvhw13v3zETxpE_example_com_users_etc_passwd.jsonl +1 -0
- package/test/logs/did_webvh_QmTn9FdCfpXFDrxHH52pwB4iNrDFVvNDjJ5FQTcDbmM3Fg_example_com.jsonl +1 -0
- package/test/logs/did_webvh_QmUCQUi1xjtJjnSQ1XJZgKqcWgErx1v7E2dz4DAPraAyJP_example_com_etc_passwd.jsonl +1 -0
- package/test/logs/did_webvh_QmUENQJCDKBJVRS5BkL6zjaUvcRjkb9xHmy7foCgRjmv3W_example_com.jsonl +1 -0
- package/test/logs/did_webvh_QmUPdGyjYBEnQ3aQUkmqyyBKTyjvCP5RZQGiaEDeTtf6dc_example_com.jsonl +1 -0
- package/test/logs/did_webvh_QmUoHTuHMWzQM29ZFrE9VLtMxkZ5u869yqee8LwcCLN39M_example_com.jsonl +1 -0
- package/test/logs/did_webvh_QmUrnms8G65ggVKsr9oQeWrLUBuGChwQPPb2LCFvaoNxaw_example_com_users_alice.jsonl +1 -0
- package/test/logs/did_webvh_QmUwiw3eSXdHG1hPvoAGu3cuK5jF4aXRYDLBAjPXfv1qzb_example_com_level1_level2.jsonl +1 -0
- package/test/logs/did_webvh_QmW7bzKh6yFEKNAtmVsrPGvvsMHTUQdzJSNsTZkbuGFpbj_example_com_secret.jsonl +1 -0
- package/test/logs/did_webvh_QmXbFTFBBJ8zpjdz9WE1DNN44A2wprFmdvAubjSffeyoAG_example_com.jsonl +1 -0
- package/test/logs/did_webvh_QmXyVXFPCTffGb2mTUFDeMCsScjnpLWkyUkVkB6q6QoeBf_example_com_C_Windows_System32.jsonl +1 -0
- package/test/logs/did_webvh_QmZK9B81gxZtvo5fYHYKDtKt8zZfZZPhmCMhbujBJuRRzE_example_com_etc_passwd.jsonl +1 -0
- package/test/logs/did_webvh_QmbNLCVSdXSVLrwFBvCBQPAabjtRb1SGHjkGVyw3QUbfBL_example_com_users_etc_passwd.jsonl +1 -0
- package/test/logs/did_webvh_QmbeaicmGW3Q7Yzbqmftc8a9jLBngokveb5A2KVKfVGZRb_example_com_my_org_user_name_test_123.jsonl +1 -0
- package/test/logs/did_webvh_Qmdv7c7AjUreUfoKyvkN2UpAWTozxKsv99srQetPJMJEnp_example_com_users_etc_passwd.jsonl +1 -0
- package/test/logs/did_webvh_QmeioWY3uypYLkYpCXe9eCYnn4xBVruP9C1d79azMrTEHG_example_com.jsonl +1 -0
- package/test/logs/did_webvh_Qmf4QH5dsA6Ecr5HJ6KaJL9uJRyY8RxrQdqoRCM25DzvPi_example_com_users_alice.jsonl +1 -0
- package/tests/__mocks__/bbs-signatures.js +17 -0
- package/tests/__mocks__/mf-base58.js +24 -0
- package/tests/e2e/README.md +97 -0
- package/tests/e2e/example.spec.ts +78 -0
- package/tests/fixtures/did-documents.ts +247 -0
- package/tests/index.test.ts +21 -0
- package/tests/integration/BatchOperations.test.ts +531 -0
- package/tests/integration/CompleteLifecycle.e2e.test.ts +735 -0
- package/tests/integration/CredentialManager.test.ts +42 -0
- package/tests/integration/DIDManager.test.ts +41 -0
- package/tests/integration/DidPeerToWebVhFlow.test.ts +351 -0
- package/tests/integration/Events.test.ts +435 -0
- package/tests/integration/Lifecycle.transfer.btco.integration.test.ts +25 -0
- package/tests/integration/LifecycleManager.test.ts +21 -0
- package/tests/integration/MultikeyFlow.test.ts +52 -0
- package/tests/integration/TelemetryIntegration.test.ts +395 -0
- package/tests/integration/WebVhPublish.test.ts +48 -0
- package/tests/integration/migration/peer-to-webvh.test.ts +172 -0
- package/tests/manual/test-commit-creation.ts +323 -0
- package/tests/mocks/MockKeyStore.ts +38 -0
- package/tests/mocks/adapters/MemoryStorageAdapter.ts +24 -0
- package/tests/mocks/adapters/MockFeeOracle.ts +11 -0
- package/tests/mocks/adapters/MockOrdinalsProvider.ts +76 -0
- package/tests/mocks/adapters/OrdMockProvider.test.ts +176 -0
- package/tests/mocks/adapters/index.ts +6 -0
- package/tests/performance/BatchOperations.perf.test.ts +403 -0
- package/tests/performance/logging.perf.test.ts +336 -0
- package/tests/sdk.test.ts +43 -0
- package/tests/security/bitcoin-penetration-tests.test.ts +622 -0
- package/tests/setup.bun.ts +69 -0
- package/tests/setup.jest.ts +23 -0
- package/tests/stress/batch-operations-stress.test.ts +571 -0
- package/tests/unit/adapters/FeeOracleMock.test.ts +40 -0
- package/tests/unit/bitcoin/BitcoinManager.test.ts +293 -0
- package/tests/unit/bitcoin/BroadcastClient.test.ts +52 -0
- package/tests/unit/bitcoin/OrdNodeProvider.test.ts +53 -0
- package/tests/unit/bitcoin/OrdinalsClient.test.ts +381 -0
- package/tests/unit/bitcoin/OrdinalsClientProvider.test.ts +102 -0
- package/tests/unit/bitcoin/PSBTBuilder.test.ts +84 -0
- package/tests/unit/bitcoin/fee-calculation.test.ts +261 -0
- package/tests/unit/bitcoin/transactions/commit.test.ts +649 -0
- package/tests/unit/bitcoin/transfer.test.ts +31 -0
- package/tests/unit/bitcoin/utxo-selection-new.test.ts +502 -0
- package/tests/unit/bitcoin/utxo.more.test.ts +39 -0
- package/tests/unit/bitcoin/utxo.selection.test.ts +38 -0
- package/tests/unit/core/OriginalsSDK.test.ts +152 -0
- package/tests/unit/crypto/Multikey.test.ts +206 -0
- package/tests/unit/crypto/Signer.test.ts +408 -0
- package/tests/unit/did/BtcoDidResolver.test.ts +611 -0
- package/tests/unit/did/DIDManager.more.test.ts +43 -0
- package/tests/unit/did/DIDManager.test.ts +185 -0
- package/tests/unit/did/Ed25519Verifier.test.ts +160 -0
- package/tests/unit/did/KeyManager.test.ts +452 -0
- package/tests/unit/did/OrdinalsClientProviderAdapter.test.ts +45 -0
- package/tests/unit/did/WebVHManager.test.ts +435 -0
- package/tests/unit/did/createBtcoDidDocument.test.ts +67 -0
- package/tests/unit/did/providers/OrdinalsClientProviderAdapter.test.ts +159 -0
- package/tests/unit/events/EventEmitter.test.ts +407 -0
- package/tests/unit/lifecycle/BatchOperations.test.ts +527 -0
- package/tests/unit/lifecycle/LifecycleManager.keymanagement.test.ts +312 -0
- package/tests/unit/lifecycle/LifecycleManager.prov.test.ts +18 -0
- package/tests/unit/lifecycle/LifecycleManager.test.ts +213 -0
- package/tests/unit/lifecycle/LifecycleManager.transfer.unit.test.ts +30 -0
- package/tests/unit/lifecycle/OriginalsAsset.test.ts +176 -0
- package/tests/unit/lifecycle/ProvenanceQuery.test.ts +577 -0
- package/tests/unit/lifecycle/ResourceVersioning.test.ts +651 -0
- package/tests/unit/storage/MemoryStorageAdapter.test.ts +93 -0
- package/tests/unit/types/network.test.ts +255 -0
- package/tests/unit/utils/EventIntegration.test.ts +384 -0
- package/tests/unit/utils/Logger.test.ts +473 -0
- package/tests/unit/utils/MetricsCollector.test.ts +358 -0
- package/tests/unit/utils/bitcoin-address.test.ts +250 -0
- package/tests/unit/utils/cbor.test.ts +35 -0
- package/tests/unit/utils/encoding.test.ts +318 -0
- package/tests/unit/utils/hash.test.ts +12 -0
- package/tests/unit/utils/retry.test.ts +100 -0
- package/tests/unit/utils/satoshi-validation.test.ts +354 -0
- package/tests/unit/utils/serialization.test.ts +124 -0
- package/tests/unit/utils/telemetry.test.ts +52 -0
- package/tests/unit/utils/validation.test.ts +141 -0
- package/tests/unit/vc/CredentialManager.test.ts +487 -0
- package/tests/unit/vc/Issuer.test.ts +107 -0
- package/tests/unit/vc/Verifier.test.ts +525 -0
- package/tests/unit/vc/bbs.test.ts +282 -0
- package/tests/unit/vc/cryptosuites/eddsa.test.ts +398 -0
- package/tests/unit/vc/documentLoader.test.ts +121 -0
- package/tests/unit/vc/proofs/data-integrity.test.ts +24 -0
- package/tsconfig.json +32 -0
- package/tsconfig.test.json +15 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,649 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for commit transaction creation
|
|
3
|
+
*/
|
|
4
|
+
import { describe, test, expect, beforeEach } from 'bun:test';
|
|
5
|
+
import {
|
|
6
|
+
createCommitTransaction,
|
|
7
|
+
type CommitTransactionParams,
|
|
8
|
+
type CommitTransactionResult
|
|
9
|
+
} from '../../../../src/bitcoin/transactions/commit.js';
|
|
10
|
+
import type { Utxo } from '../../../../src/types/bitcoin.js';
|
|
11
|
+
|
|
12
|
+
// Helper to create test UTXOs
|
|
13
|
+
const createUtxo = (value: number, index: number = 0, network: 'mainnet' | 'testnet' | 'signet' | 'regtest' = 'mainnet'): Utxo => {
|
|
14
|
+
const addressMap = {
|
|
15
|
+
mainnet: 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4',
|
|
16
|
+
testnet: 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx',
|
|
17
|
+
signet: 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx',
|
|
18
|
+
regtest: 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx' // Use testnet format for regtest compatibility with @scure/btc-signer
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
txid: `${'a'.repeat(62)}${index.toString().padStart(2, '0')}`,
|
|
23
|
+
vout: index,
|
|
24
|
+
value,
|
|
25
|
+
scriptPubKey: '0014' + 'b'.repeat(40), // Mock P2WPKH scriptPubKey
|
|
26
|
+
address: addressMap[network]
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Helper to create basic commit params
|
|
31
|
+
const createCommitParams = (overrides: Partial<CommitTransactionParams> = {}): CommitTransactionParams => {
|
|
32
|
+
const network = overrides.network || 'mainnet';
|
|
33
|
+
const addressMap = {
|
|
34
|
+
mainnet: 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4',
|
|
35
|
+
testnet: 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx',
|
|
36
|
+
signet: 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx',
|
|
37
|
+
regtest: 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx' // Use testnet format for regtest compatibility with @scure/btc-signer
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
content: Buffer.from('Hello Ordinals'),
|
|
42
|
+
contentType: 'text/plain',
|
|
43
|
+
utxos: overrides.utxos || [createUtxo(10000, 0, network)],
|
|
44
|
+
changeAddress: addressMap[network],
|
|
45
|
+
feeRate: 10,
|
|
46
|
+
network,
|
|
47
|
+
...overrides
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
describe('createCommitTransaction', () => {
|
|
52
|
+
describe('Basic Functionality', () => {
|
|
53
|
+
test('creates commit transaction with valid inputs', async () => {
|
|
54
|
+
const params = createCommitParams();
|
|
55
|
+
const result = await createCommitTransaction(params);
|
|
56
|
+
|
|
57
|
+
expect(result).toBeDefined();
|
|
58
|
+
expect(result.commitAddress).toBeDefined();
|
|
59
|
+
expect(result.commitPsbtBase64).toBeDefined();
|
|
60
|
+
expect(result.commitPsbt).toBeDefined();
|
|
61
|
+
expect(result.selectedUtxos).toHaveLength(1);
|
|
62
|
+
expect(result.fees.commit).toBeGreaterThan(0);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('generates valid P2TR commit address', async () => {
|
|
66
|
+
const params = createCommitParams();
|
|
67
|
+
const result = await createCommitTransaction(params);
|
|
68
|
+
|
|
69
|
+
// P2TR addresses start with bc1p for mainnet
|
|
70
|
+
expect(result.commitAddress).toMatch(/^bc1p[a-z0-9]{58}$/);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('generates reveal keypair', async () => {
|
|
74
|
+
const params = createCommitParams();
|
|
75
|
+
const result = await createCommitTransaction(params);
|
|
76
|
+
|
|
77
|
+
expect(result.revealPrivateKey).toBeDefined();
|
|
78
|
+
expect(result.revealPublicKey).toBeDefined();
|
|
79
|
+
expect(result.revealPrivateKey).toHaveLength(64); // 32 bytes in hex
|
|
80
|
+
expect(result.revealPublicKey).toHaveLength(64); // 32 bytes x-only pubkey in hex
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('includes inscription script data', async () => {
|
|
84
|
+
const params = createCommitParams();
|
|
85
|
+
const result = await createCommitTransaction(params);
|
|
86
|
+
|
|
87
|
+
expect(result.inscriptionScript).toBeDefined();
|
|
88
|
+
expect(result.inscriptionScript.script).toBeInstanceOf(Uint8Array);
|
|
89
|
+
expect(result.inscriptionScript.controlBlock).toBeInstanceOf(Uint8Array);
|
|
90
|
+
expect(result.inscriptionScript.leafVersion).toBe(0xc0);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('returns correct commit amount', async () => {
|
|
94
|
+
const params = createCommitParams({ minimumCommitAmount: 1000 });
|
|
95
|
+
const result = await createCommitTransaction(params);
|
|
96
|
+
|
|
97
|
+
expect(result.commitAmount).toBeGreaterThanOrEqual(1000);
|
|
98
|
+
expect(result.commitAmount).toBeGreaterThanOrEqual(546); // Dust limit
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('UTXO Selection', () => {
|
|
103
|
+
test('selects single UTXO when sufficient', async () => {
|
|
104
|
+
const params = createCommitParams({
|
|
105
|
+
utxos: [createUtxo(10000, 0)]
|
|
106
|
+
});
|
|
107
|
+
const result = await createCommitTransaction(params);
|
|
108
|
+
|
|
109
|
+
expect(result.selectedUtxos).toHaveLength(1);
|
|
110
|
+
expect(result.selectedUtxos[0].value).toBe(10000);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test('selects multiple UTXOs when needed', async () => {
|
|
114
|
+
const params = createCommitParams({
|
|
115
|
+
utxos: [
|
|
116
|
+
createUtxo(2000, 0),
|
|
117
|
+
createUtxo(2000, 1),
|
|
118
|
+
createUtxo(2000, 2)
|
|
119
|
+
],
|
|
120
|
+
minimumCommitAmount: 2000
|
|
121
|
+
});
|
|
122
|
+
const result = await createCommitTransaction(params);
|
|
123
|
+
|
|
124
|
+
expect(result.selectedUtxos.length).toBeGreaterThan(1);
|
|
125
|
+
const totalValue = result.selectedUtxos.reduce((sum, utxo) => sum + utxo.value, 0);
|
|
126
|
+
expect(totalValue).toBeGreaterThanOrEqual(2000 + result.fees.commit);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('throws when insufficient funds', async () => {
|
|
130
|
+
const params = createCommitParams({
|
|
131
|
+
utxos: [createUtxo(100, 0)], // Not enough for commit + fees
|
|
132
|
+
minimumCommitAmount: 546
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
await expect(createCommitTransaction(params)).rejects.toThrow(/Insufficient funds/);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
describe('Fee Calculation', () => {
|
|
140
|
+
test('calculates correct fee for 1 input', async () => {
|
|
141
|
+
const feeRate = 10; // 10 sats/vB
|
|
142
|
+
const params = createCommitParams({
|
|
143
|
+
feeRate,
|
|
144
|
+
utxos: [createUtxo(10000, 0)]
|
|
145
|
+
});
|
|
146
|
+
const result = await createCommitTransaction(params);
|
|
147
|
+
|
|
148
|
+
// Fee should be reasonable for 1 input, 2 outputs (commit + change)
|
|
149
|
+
// Estimate: ~10.5 overhead + 68 input + 43 P2TR + 31 change = ~152 vB
|
|
150
|
+
// At 10 sats/vB = ~1520 sats
|
|
151
|
+
expect(result.fees.commit).toBeGreaterThan(1000);
|
|
152
|
+
expect(result.fees.commit).toBeLessThan(3000);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test('fee scales with fee rate', async () => {
|
|
156
|
+
const params1 = createCommitParams({ feeRate: 5 });
|
|
157
|
+
const params2 = createCommitParams({ feeRate: 50 });
|
|
158
|
+
|
|
159
|
+
const result1 = await createCommitTransaction(params1);
|
|
160
|
+
const result2 = await createCommitTransaction(params2);
|
|
161
|
+
|
|
162
|
+
// Fee should be ~10x higher for 10x fee rate
|
|
163
|
+
expect(result2.fees.commit).toBeGreaterThan(result1.fees.commit * 8);
|
|
164
|
+
expect(result2.fees.commit).toBeLessThan(result1.fees.commit * 12);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test('fee increases with multiple inputs', async () => {
|
|
168
|
+
const params1 = createCommitParams({
|
|
169
|
+
utxos: [createUtxo(10000, 0)]
|
|
170
|
+
});
|
|
171
|
+
const params2 = createCommitParams({
|
|
172
|
+
utxos: [
|
|
173
|
+
createUtxo(1500, 0),
|
|
174
|
+
createUtxo(1500, 1),
|
|
175
|
+
createUtxo(1500, 2),
|
|
176
|
+
createUtxo(1500, 3)
|
|
177
|
+
],
|
|
178
|
+
minimumCommitAmount: 2000 // Force use of multiple UTXOs
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const result1 = await createCommitTransaction(params1);
|
|
182
|
+
const result2 = await createCommitTransaction(params2);
|
|
183
|
+
|
|
184
|
+
// More inputs = higher fee
|
|
185
|
+
expect(result2.fees.commit).toBeGreaterThan(result1.fees.commit);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
describe('PSBT Construction', () => {
|
|
190
|
+
test('PSBT has correct number of inputs', async () => {
|
|
191
|
+
const params = createCommitParams({
|
|
192
|
+
utxos: [createUtxo(10000, 0)]
|
|
193
|
+
});
|
|
194
|
+
const result = await createCommitTransaction(params);
|
|
195
|
+
|
|
196
|
+
expect(result.commitPsbt.inputsLength).toBe(1);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test('PSBT includes commit output', async () => {
|
|
200
|
+
const params = createCommitParams();
|
|
201
|
+
const result = await createCommitTransaction(params);
|
|
202
|
+
|
|
203
|
+
expect(result.commitPsbt.outputsLength).toBeGreaterThanOrEqual(1);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test('PSBT creates change output when needed', async () => {
|
|
207
|
+
const params = createCommitParams({
|
|
208
|
+
utxos: [createUtxo(100000, 0)], // Large UTXO
|
|
209
|
+
minimumCommitAmount: 546
|
|
210
|
+
});
|
|
211
|
+
const result = await createCommitTransaction(params);
|
|
212
|
+
|
|
213
|
+
// Should have commit output + change output
|
|
214
|
+
expect(result.commitPsbt.outputsLength).toBe(2);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
test('PSBT omits change when below dust limit', async () => {
|
|
218
|
+
const params = createCommitParams({
|
|
219
|
+
utxos: [createUtxo(2500, 0)], // Enough for commit + fees with minimal change below dust
|
|
220
|
+
minimumCommitAmount: 546,
|
|
221
|
+
feeRate: 10
|
|
222
|
+
});
|
|
223
|
+
const result = await createCommitTransaction(params);
|
|
224
|
+
|
|
225
|
+
// Should have only commit output (change below dust limit)
|
|
226
|
+
expect(result.commitPsbt.outputsLength).toBe(1);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
test('PSBT is valid base64', async () => {
|
|
230
|
+
const params = createCommitParams();
|
|
231
|
+
const result = await createCommitTransaction(params);
|
|
232
|
+
|
|
233
|
+
expect(result.commitPsbtBase64).toBeDefined();
|
|
234
|
+
expect(typeof result.commitPsbtBase64).toBe('string');
|
|
235
|
+
|
|
236
|
+
// Should be valid base64
|
|
237
|
+
const decoded = Buffer.from(result.commitPsbtBase64, 'base64');
|
|
238
|
+
expect(decoded.length).toBeGreaterThan(0);
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
describe('Inscription Content', () => {
|
|
243
|
+
test('handles text content', async () => {
|
|
244
|
+
const params = createCommitParams({
|
|
245
|
+
content: Buffer.from('Hello World'),
|
|
246
|
+
contentType: 'text/plain'
|
|
247
|
+
});
|
|
248
|
+
const result = await createCommitTransaction(params);
|
|
249
|
+
|
|
250
|
+
expect(result).toBeDefined();
|
|
251
|
+
expect(result.commitAddress).toBeDefined();
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
test('handles JSON content', async () => {
|
|
255
|
+
const params = createCommitParams({
|
|
256
|
+
content: Buffer.from(JSON.stringify({ test: 'data' })),
|
|
257
|
+
contentType: 'application/json'
|
|
258
|
+
});
|
|
259
|
+
const result = await createCommitTransaction(params);
|
|
260
|
+
|
|
261
|
+
expect(result).toBeDefined();
|
|
262
|
+
expect(result.commitAddress).toBeDefined();
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
test('handles binary content', async () => {
|
|
266
|
+
const params = createCommitParams({
|
|
267
|
+
content: Buffer.from([0x89, 0x50, 0x4E, 0x47]), // PNG header
|
|
268
|
+
contentType: 'image/png'
|
|
269
|
+
});
|
|
270
|
+
const result = await createCommitTransaction(params);
|
|
271
|
+
|
|
272
|
+
expect(result).toBeDefined();
|
|
273
|
+
expect(result.commitAddress).toBeDefined();
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
test('handles large content (1KB)', async () => {
|
|
277
|
+
const largeContent = Buffer.alloc(1024, 'a');
|
|
278
|
+
const params = createCommitParams({
|
|
279
|
+
content: largeContent,
|
|
280
|
+
contentType: 'text/plain',
|
|
281
|
+
utxos: [createUtxo(100000, 0)]
|
|
282
|
+
});
|
|
283
|
+
const result = await createCommitTransaction(params);
|
|
284
|
+
|
|
285
|
+
expect(result).toBeDefined();
|
|
286
|
+
expect(result.commitAddress).toBeDefined();
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
test('includes metadata when provided', async () => {
|
|
290
|
+
const params = createCommitParams({
|
|
291
|
+
metadata: { title: 'Test Inscription', author: 'Tester' }
|
|
292
|
+
});
|
|
293
|
+
const result = await createCommitTransaction(params);
|
|
294
|
+
|
|
295
|
+
expect(result).toBeDefined();
|
|
296
|
+
expect(result.commitAddress).toBeDefined();
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
test('handles missing pointer gracefully', async () => {
|
|
300
|
+
// Pointer is optional, test that it works without it
|
|
301
|
+
const params = createCommitParams();
|
|
302
|
+
const result = await createCommitTransaction(params);
|
|
303
|
+
|
|
304
|
+
expect(result).toBeDefined();
|
|
305
|
+
expect(result.commitAddress).toBeDefined();
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
describe('Network Support', () => {
|
|
310
|
+
test('creates mainnet commit address', async () => {
|
|
311
|
+
const params = createCommitParams({ network: 'mainnet' });
|
|
312
|
+
const result = await createCommitTransaction(params);
|
|
313
|
+
|
|
314
|
+
expect(result.commitAddress).toMatch(/^bc1p/);
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
test('creates testnet commit address', async () => {
|
|
318
|
+
const params = createCommitParams({ network: 'testnet' });
|
|
319
|
+
const result = await createCommitTransaction(params);
|
|
320
|
+
|
|
321
|
+
expect(result.commitAddress).toMatch(/^tb1p/);
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
test('creates signet commit address', async () => {
|
|
325
|
+
const params = createCommitParams({ network: 'signet' });
|
|
326
|
+
const result = await createCommitTransaction(params);
|
|
327
|
+
|
|
328
|
+
expect(result.commitAddress).toMatch(/^tb1p/);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
test('creates regtest commit address', async () => {
|
|
332
|
+
const params = createCommitParams({ network: 'regtest' });
|
|
333
|
+
const result = await createCommitTransaction(params);
|
|
334
|
+
|
|
335
|
+
// Regtest uses TEST_NETWORK which generates tb1p addresses
|
|
336
|
+
expect(result.commitAddress).toMatch(/^tb1p/);
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
describe('Error Handling', () => {
|
|
341
|
+
test('throws when no UTXOs provided', async () => {
|
|
342
|
+
const params = createCommitParams({ utxos: [] });
|
|
343
|
+
await expect(createCommitTransaction(params)).rejects.toThrow(/No UTXOs provided/);
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
test('throws when content is empty', async () => {
|
|
347
|
+
const params = createCommitParams({ content: Buffer.from([]) });
|
|
348
|
+
await expect(createCommitTransaction(params)).rejects.toThrow(/missing content/);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
test('throws when contentType is missing', async () => {
|
|
352
|
+
const params = createCommitParams({ contentType: '' });
|
|
353
|
+
await expect(createCommitTransaction(params)).rejects.toThrow(/missing content type/);
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
test('throws when changeAddress is missing', async () => {
|
|
357
|
+
const params = createCommitParams({ changeAddress: '' });
|
|
358
|
+
await expect(createCommitTransaction(params)).rejects.toThrow(/Change address is required/);
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
test('throws when feeRate is invalid', async () => {
|
|
362
|
+
const params = createCommitParams({ feeRate: 0 });
|
|
363
|
+
await expect(createCommitTransaction(params)).rejects.toThrow(/Invalid fee rate/);
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
test('throws when all UTXOs are missing scriptPubKey', async () => {
|
|
367
|
+
const invalidUtxo1: Utxo = {
|
|
368
|
+
txid: 'a'.repeat(64),
|
|
369
|
+
vout: 0,
|
|
370
|
+
value: 10000
|
|
371
|
+
// Missing scriptPubKey
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
const invalidUtxo2: Utxo = {
|
|
375
|
+
txid: 'b'.repeat(64),
|
|
376
|
+
vout: 1,
|
|
377
|
+
value: 10000
|
|
378
|
+
// Missing scriptPubKey
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
const params = createCommitParams({
|
|
382
|
+
utxos: [invalidUtxo1, invalidUtxo2]
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
// Should throw error because no valid UTXOs remain after filtering
|
|
386
|
+
await expect(createCommitTransaction(params)).rejects.toThrow(/No valid spendable UTXOs available/);
|
|
387
|
+
await expect(createCommitTransaction(params)).rejects.toThrow(/missing scriptPubKey/);
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
test('filters out invalid UTXOs and uses only valid ones', async () => {
|
|
391
|
+
const invalidUtxo: Utxo = {
|
|
392
|
+
txid: 'a'.repeat(64),
|
|
393
|
+
vout: 0,
|
|
394
|
+
value: 10000
|
|
395
|
+
// Missing scriptPubKey
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
const params = createCommitParams({
|
|
399
|
+
utxos: [invalidUtxo, createUtxo(50000, 1), createUtxo(50000, 2)]
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
// Should filter out the invalid UTXO and use only the valid ones
|
|
403
|
+
const result = await createCommitTransaction(params);
|
|
404
|
+
expect(result).toBeDefined();
|
|
405
|
+
// Should only use valid UTXOs
|
|
406
|
+
expect(result.selectedUtxos.every(u => u.scriptPubKey)).toBe(true);
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
describe('Dust Handling', () => {
|
|
411
|
+
test('respects minimum dust limit (546 sats)', async () => {
|
|
412
|
+
const params = createCommitParams({ minimumCommitAmount: 100 });
|
|
413
|
+
const result = await createCommitTransaction(params);
|
|
414
|
+
|
|
415
|
+
// Should use dust limit instead of 100
|
|
416
|
+
expect(result.commitAmount).toBeGreaterThanOrEqual(546);
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
test('uses custom minimum when above dust limit', async () => {
|
|
420
|
+
const params = createCommitParams({
|
|
421
|
+
minimumCommitAmount: 10000,
|
|
422
|
+
utxos: [createUtxo(15000, 0)] // Enough to cover 10000 + fees
|
|
423
|
+
});
|
|
424
|
+
const result = await createCommitTransaction(params);
|
|
425
|
+
|
|
426
|
+
expect(result.commitAmount).toBe(10000);
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
test('adds dust change to fee', async () => {
|
|
430
|
+
// Create scenario where change would be < 546 sats
|
|
431
|
+
const params = createCommitParams({
|
|
432
|
+
utxos: [createUtxo(1500, 0)],
|
|
433
|
+
minimumCommitAmount: 546,
|
|
434
|
+
feeRate: 5
|
|
435
|
+
});
|
|
436
|
+
const result = await createCommitTransaction(params);
|
|
437
|
+
|
|
438
|
+
// Should have only commit output (no change)
|
|
439
|
+
expect(result.commitPsbt.outputsLength).toBe(1);
|
|
440
|
+
});
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
describe('Consistency', () => {
|
|
444
|
+
test('generates different addresses for different content', async () => {
|
|
445
|
+
const params1 = createCommitParams({ content: Buffer.from('Content 1') });
|
|
446
|
+
const params2 = createCommitParams({ content: Buffer.from('Content 2') });
|
|
447
|
+
|
|
448
|
+
const result1 = await createCommitTransaction(params1);
|
|
449
|
+
const result2 = await createCommitTransaction(params2);
|
|
450
|
+
|
|
451
|
+
// Different content should generate different addresses
|
|
452
|
+
expect(result1.commitAddress).not.toBe(result2.commitAddress);
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
test('generates different addresses on each call (random keypair)', async () => {
|
|
456
|
+
const params = createCommitParams();
|
|
457
|
+
|
|
458
|
+
const result1 = await createCommitTransaction(params);
|
|
459
|
+
const result2 = await createCommitTransaction(params);
|
|
460
|
+
|
|
461
|
+
// Different reveal keypairs should generate different addresses
|
|
462
|
+
expect(result1.commitAddress).not.toBe(result2.commitAddress);
|
|
463
|
+
expect(result1.revealPrivateKey).not.toBe(result2.revealPrivateKey);
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
test('total value equals commit + change + fees', async () => {
|
|
467
|
+
const params = createCommitParams({
|
|
468
|
+
utxos: [createUtxo(100000, 0)]
|
|
469
|
+
});
|
|
470
|
+
const result = await createCommitTransaction(params);
|
|
471
|
+
|
|
472
|
+
const totalInput = result.selectedUtxos.reduce((sum, utxo) => sum + utxo.value, 0);
|
|
473
|
+
const totalOutput = result.commitAmount;
|
|
474
|
+
const fee = result.fees.commit;
|
|
475
|
+
|
|
476
|
+
// Get change amount from PSBT if it exists
|
|
477
|
+
let changeAmount = 0;
|
|
478
|
+
if (result.commitPsbt.outputsLength === 2) {
|
|
479
|
+
changeAmount = totalInput - totalOutput - fee;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
expect(totalInput).toBe(totalOutput + changeAmount + fee);
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
test('inputs always cover outputs (no negative change)', async () => {
|
|
486
|
+
// Test with various fee rates to ensure iterative selection works
|
|
487
|
+
const feeRates = [1, 5, 10, 20, 50];
|
|
488
|
+
|
|
489
|
+
for (const feeRate of feeRates) {
|
|
490
|
+
const params = createCommitParams({
|
|
491
|
+
utxos: [createUtxo(10000, 0), createUtxo(20000, 1), createUtxo(30000, 2)],
|
|
492
|
+
feeRate
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
const result = await createCommitTransaction(params);
|
|
496
|
+
|
|
497
|
+
const totalInput = result.selectedUtxos.reduce((sum, utxo) => sum + utxo.value, 0);
|
|
498
|
+
const totalOutput = result.commitAmount + result.fees.commit;
|
|
499
|
+
|
|
500
|
+
// Critical check: inputs must always be >= outputs
|
|
501
|
+
expect(totalInput).toBeGreaterThanOrEqual(totalOutput);
|
|
502
|
+
|
|
503
|
+
// Calculate actual change
|
|
504
|
+
const actualChange = totalInput - totalOutput;
|
|
505
|
+
expect(actualChange).toBeGreaterThanOrEqual(0);
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
describe('Iterative UTXO Selection', () => {
|
|
511
|
+
test('reselects UTXOs when fee increases after accurate calculation', async () => {
|
|
512
|
+
// Create scenario where 1 UTXO isn't enough after fee recalculation
|
|
513
|
+
const params = createCommitParams({
|
|
514
|
+
utxos: [
|
|
515
|
+
createUtxo(1500, 0), // Not enough alone
|
|
516
|
+
createUtxo(2000, 1), // Will need this one too
|
|
517
|
+
createUtxo(5000, 2) // May need this as well
|
|
518
|
+
],
|
|
519
|
+
minimumCommitAmount: 546,
|
|
520
|
+
feeRate: 10
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
const result = await createCommitTransaction(params);
|
|
524
|
+
|
|
525
|
+
// Should have selected enough UTXOs to cover commit + fees
|
|
526
|
+
const totalInput = result.selectedUtxos.reduce((sum, utxo) => sum + utxo.value, 0);
|
|
527
|
+
expect(totalInput).toBeGreaterThanOrEqual(result.commitAmount + result.fees.commit);
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
test('stops iteration when sufficient funds are found', async () => {
|
|
531
|
+
// Create scenario with plenty of UTXOs
|
|
532
|
+
const params = createCommitParams({
|
|
533
|
+
utxos: [
|
|
534
|
+
createUtxo(100000, 0), // This should be enough
|
|
535
|
+
createUtxo(100000, 1),
|
|
536
|
+
createUtxo(100000, 2)
|
|
537
|
+
],
|
|
538
|
+
feeRate: 10
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
const result = await createCommitTransaction(params);
|
|
542
|
+
|
|
543
|
+
// Should not need all UTXOs since first one is sufficient
|
|
544
|
+
expect(result.selectedUtxos.length).toBeLessThan(3);
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
test('throws error if max iterations reached without sufficient funds', async () => {
|
|
548
|
+
// Create scenario where UTXOs are just barely insufficient
|
|
549
|
+
// This would require many iterations if the algorithm isn't working
|
|
550
|
+
const params = createCommitParams({
|
|
551
|
+
utxos: [
|
|
552
|
+
createUtxo(500, 0),
|
|
553
|
+
createUtxo(500, 1)
|
|
554
|
+
],
|
|
555
|
+
minimumCommitAmount: 546,
|
|
556
|
+
feeRate: 50 // High fee rate makes it impossible
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
// Should throw after max iterations
|
|
560
|
+
await expect(createCommitTransaction(params)).rejects.toThrow(/Insufficient funds/);
|
|
561
|
+
});
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
describe('UTXO Validation', () => {
|
|
565
|
+
test('validates UTXO has txid', async () => {
|
|
566
|
+
const invalidUtxo: Utxo = {
|
|
567
|
+
txid: '', // Empty txid
|
|
568
|
+
vout: 0,
|
|
569
|
+
value: 10000,
|
|
570
|
+
scriptPubKey: '0014' + 'a'.repeat(40)
|
|
571
|
+
};
|
|
572
|
+
|
|
573
|
+
const params = createCommitParams({
|
|
574
|
+
utxos: [invalidUtxo]
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
await expect(createCommitTransaction(params)).rejects.toThrow(/No valid spendable UTXOs/);
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
test('validates UTXO has valid vout', async () => {
|
|
581
|
+
const invalidUtxo: any = {
|
|
582
|
+
txid: 'a'.repeat(64),
|
|
583
|
+
vout: 'invalid', // Invalid vout type
|
|
584
|
+
value: 10000,
|
|
585
|
+
scriptPubKey: '0014' + 'a'.repeat(40)
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
const params = createCommitParams({
|
|
589
|
+
utxos: [invalidUtxo]
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
await expect(createCommitTransaction(params)).rejects.toThrow(/No valid spendable UTXOs/);
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
test('validates UTXO has positive value', async () => {
|
|
596
|
+
const invalidUtxo: Utxo = {
|
|
597
|
+
txid: 'a'.repeat(64),
|
|
598
|
+
vout: 0,
|
|
599
|
+
value: 0, // Zero value
|
|
600
|
+
scriptPubKey: '0014' + 'a'.repeat(40)
|
|
601
|
+
};
|
|
602
|
+
|
|
603
|
+
const params = createCommitParams({
|
|
604
|
+
utxos: [invalidUtxo]
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
await expect(createCommitTransaction(params)).rejects.toThrow(/No valid spendable UTXOs/);
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
test('provides detailed error message for invalid UTXOs', async () => {
|
|
611
|
+
const invalidUtxos: Utxo[] = [
|
|
612
|
+
{
|
|
613
|
+
txid: 'a'.repeat(64),
|
|
614
|
+
vout: 0,
|
|
615
|
+
value: 10000
|
|
616
|
+
// Missing scriptPubKey
|
|
617
|
+
},
|
|
618
|
+
{
|
|
619
|
+
txid: '', // Missing txid
|
|
620
|
+
vout: 1,
|
|
621
|
+
value: 10000,
|
|
622
|
+
scriptPubKey: '0014' + 'a'.repeat(40)
|
|
623
|
+
},
|
|
624
|
+
{
|
|
625
|
+
txid: 'c'.repeat(64),
|
|
626
|
+
vout: 2,
|
|
627
|
+
value: 0, // Invalid value
|
|
628
|
+
scriptPubKey: '0014' + 'a'.repeat(40)
|
|
629
|
+
}
|
|
630
|
+
];
|
|
631
|
+
|
|
632
|
+
const params = createCommitParams({
|
|
633
|
+
utxos: invalidUtxos
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
try {
|
|
637
|
+
await createCommitTransaction(params);
|
|
638
|
+
throw new Error('Should have thrown');
|
|
639
|
+
} catch (error) {
|
|
640
|
+
expect(error).toBeInstanceOf(Error);
|
|
641
|
+
if (error instanceof Error) {
|
|
642
|
+
// Should contain detailed information about what's wrong
|
|
643
|
+
expect(error.message).toMatch(/No valid spendable UTXOs available/);
|
|
644
|
+
expect(error.message).toMatch(/3 UTXO.*provided but all are invalid/);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
});
|
|
648
|
+
});
|
|
649
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { describe, test, expect } from 'bun:test';
|
|
2
|
+
import { buildTransferTransaction } from '../../../src/bitcoin/transfer';
|
|
3
|
+
import { DUST_LIMIT_SATS, Utxo } from '../../../src/types';
|
|
4
|
+
|
|
5
|
+
describe('buildTransferTransaction', () => {
|
|
6
|
+
const utxo = (value: number, i: number = 0): Utxo => ({ txid: 't', vout: i, value });
|
|
7
|
+
|
|
8
|
+
test('creates tx with recipient output and change when above dust', () => {
|
|
9
|
+
const { tx, selection } = buildTransferTransaction([utxo(100_000)], 'bc1qto', 50_000, 1);
|
|
10
|
+
expect(tx.vout[0].address).toBe('bc1qto');
|
|
11
|
+
expect(tx.vout[0].value).toBe(50_000);
|
|
12
|
+
expect(selection.changeSats).toBeGreaterThanOrEqual(DUST_LIMIT_SATS);
|
|
13
|
+
// change output present when change >= dust
|
|
14
|
+
expect(tx.vout.length).toBe(2);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('suppresses change output when below dust threshold', () => {
|
|
18
|
+
const { tx, selection } = buildTransferTransaction([utxo(800)], 'addr', DUST_LIMIT_SATS, 1);
|
|
19
|
+
expect(selection.changeSats).toBe(0);
|
|
20
|
+
// only recipient output
|
|
21
|
+
expect(tx.vout.length).toBe(1);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('uses input address as default change address when provided', () => {
|
|
25
|
+
const inputWithAddr: Utxo = { txid: 't', vout: 0, value: 100000, address: 'bc1qchange' };
|
|
26
|
+
const { tx, selection } = buildTransferTransaction([inputWithAddr], 'bc1qto', 50000, 1);
|
|
27
|
+
expect(selection.changeSats).toBeGreaterThanOrEqual(DUST_LIMIT_SATS);
|
|
28
|
+
// change output address should be input address when not passed explicitly
|
|
29
|
+
expect(tx.vout[1].address).toBe('bc1qchange');
|
|
30
|
+
});
|
|
31
|
+
});
|