diff --git a/dist/api/classes/SendCurrency/SendCurrencyRequest.d.ts b/dist/api/classes/SendCurrency/SendCurrencyRequest.d.ts index c1c602e1..e35aa363 100644 --- a/dist/api/classes/SendCurrency/SendCurrencyRequest.d.ts +++ b/dist/api/classes/SendCurrency/SendCurrencyRequest.d.ts @@ -15,6 +15,7 @@ type output = { preconvert?: boolean; burn?: boolean; mintnew?: boolean; + vdxftag?: string; }; export declare class SendCurrencyRequest extends ApiRequest { fromaddress: string; diff --git a/dist/constants/deeplink.d.ts b/dist/constants/deeplink.d.ts new file mode 100644 index 00000000..9de6f765 --- /dev/null +++ b/dist/constants/deeplink.d.ts @@ -0,0 +1,2 @@ +export declare const DEEPLINK_PROTOCOL_URL_STRING = "verus"; +export declare const DEEPLINK_PROTOCOL_URL_CURRENT_VERSION: import("bn.js"); diff --git a/dist/constants/deeplink.js b/dist/constants/deeplink.js new file mode 100644 index 00000000..757276fc --- /dev/null +++ b/dist/constants/deeplink.js @@ -0,0 +1,6 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.DEEPLINK_PROTOCOL_URL_CURRENT_VERSION = exports.DEEPLINK_PROTOCOL_URL_STRING = void 0; +const bn_js_1 = require("bn.js"); +exports.DEEPLINK_PROTOCOL_URL_STRING = "verus"; +exports.DEEPLINK_PROTOCOL_URL_CURRENT_VERSION = new bn_js_1.BN(1, 10); diff --git a/dist/constants/ordinals/ordinals.d.ts b/dist/constants/ordinals/ordinals.d.ts new file mode 100644 index 00000000..5d930738 --- /dev/null +++ b/dist/constants/ordinals/ordinals.d.ts @@ -0,0 +1,15 @@ +export declare const VDXF_OBJECT_RESERVED_BYTE_I_ADDR: import("bn.js"); +export declare const VDXF_OBJECT_RESERVED_BYTE_VDXF_ID_STRING: import("bn.js"); +export declare const VDXF_OBJECT_RESERVED_BYTE_ID_OR_CURRENCY: import("bn.js"); +export declare const VDXF_ORDINAL_DATA_DESCRIPTOR: import("bn.js"); +export declare const VDXF_ORDINAL_VERUSPAY_INVOICE: import("bn.js"); +export declare const VDXF_ORDINAL_AUTHENTICATION_REQUEST: import("bn.js"); +export declare const VDXF_ORDINAL_AUTHENTICATION_RESPONSE: import("bn.js"); +export declare const VDXF_ORDINAL_IDENTITY_UPDATE_REQUEST: import("bn.js"); +export declare const VDXF_ORDINAL_IDENTITY_UPDATE_RESPONSE: import("bn.js"); +export declare const VDXF_ORDINAL_PROVISION_IDENTITY_DETAILS: import("bn.js"); +export declare const VDXF_ORDINAL_APP_ENCRYPTION_REQUEST: import("bn.js"); +export declare const VDXF_ORDINAL_APP_ENCRYPTION_RESPONSE: import("bn.js"); +export declare const VDXF_ORDINAL_USER_SPECIFIC_DATA_PACKET: import("bn.js"); +export declare const VDXF_ORDINAL_USER_DATA_REQUEST: import("bn.js"); +export declare const VDXF_ORDINAL_DATA_RESPONSE: import("bn.js"); diff --git a/dist/constants/ordinals/ordinals.js b/dist/constants/ordinals/ordinals.js new file mode 100644 index 00000000..377533af --- /dev/null +++ b/dist/constants/ordinals/ordinals.js @@ -0,0 +1,19 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.VDXF_ORDINAL_DATA_RESPONSE = exports.VDXF_ORDINAL_USER_DATA_REQUEST = exports.VDXF_ORDINAL_USER_SPECIFIC_DATA_PACKET = exports.VDXF_ORDINAL_APP_ENCRYPTION_RESPONSE = exports.VDXF_ORDINAL_APP_ENCRYPTION_REQUEST = exports.VDXF_ORDINAL_PROVISION_IDENTITY_DETAILS = exports.VDXF_ORDINAL_IDENTITY_UPDATE_RESPONSE = exports.VDXF_ORDINAL_IDENTITY_UPDATE_REQUEST = exports.VDXF_ORDINAL_AUTHENTICATION_RESPONSE = exports.VDXF_ORDINAL_AUTHENTICATION_REQUEST = exports.VDXF_ORDINAL_VERUSPAY_INVOICE = exports.VDXF_ORDINAL_DATA_DESCRIPTOR = exports.VDXF_OBJECT_RESERVED_BYTE_ID_OR_CURRENCY = exports.VDXF_OBJECT_RESERVED_BYTE_VDXF_ID_STRING = exports.VDXF_OBJECT_RESERVED_BYTE_I_ADDR = void 0; +const bn_js_1 = require("bn.js"); +exports.VDXF_OBJECT_RESERVED_BYTE_I_ADDR = new bn_js_1.BN(102, 10); +exports.VDXF_OBJECT_RESERVED_BYTE_VDXF_ID_STRING = new bn_js_1.BN(103, 10); +exports.VDXF_OBJECT_RESERVED_BYTE_ID_OR_CURRENCY = new bn_js_1.BN(104, 10); +exports.VDXF_ORDINAL_DATA_DESCRIPTOR = new bn_js_1.BN(0, 10); +exports.VDXF_ORDINAL_VERUSPAY_INVOICE = new bn_js_1.BN(1, 10); +exports.VDXF_ORDINAL_AUTHENTICATION_REQUEST = new bn_js_1.BN(2, 10); +exports.VDXF_ORDINAL_AUTHENTICATION_RESPONSE = new bn_js_1.BN(3, 10); +exports.VDXF_ORDINAL_IDENTITY_UPDATE_REQUEST = new bn_js_1.BN(4, 10); +exports.VDXF_ORDINAL_IDENTITY_UPDATE_RESPONSE = new bn_js_1.BN(5, 10); +exports.VDXF_ORDINAL_PROVISION_IDENTITY_DETAILS = new bn_js_1.BN(6, 10); +exports.VDXF_ORDINAL_APP_ENCRYPTION_REQUEST = new bn_js_1.BN(8, 10); +exports.VDXF_ORDINAL_APP_ENCRYPTION_RESPONSE = new bn_js_1.BN(9, 10); +exports.VDXF_ORDINAL_USER_SPECIFIC_DATA_PACKET = new bn_js_1.BN(10, 10); +exports.VDXF_ORDINAL_USER_DATA_REQUEST = new bn_js_1.BN(12, 10); +exports.VDXF_ORDINAL_DATA_RESPONSE = new bn_js_1.BN(13, 10); diff --git a/dist/constants/ordinals/register.d.ts b/dist/constants/ordinals/register.d.ts new file mode 100644 index 00000000..d3677b75 --- /dev/null +++ b/dist/constants/ordinals/register.d.ts @@ -0,0 +1 @@ +export declare const registerOrdinals: () => void; diff --git a/dist/constants/ordinals/register.js b/dist/constants/ordinals/register.js new file mode 100644 index 00000000..22b57de3 --- /dev/null +++ b/dist/constants/ordinals/register.js @@ -0,0 +1,37 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.registerOrdinals = void 0; +const vdxf_1 = require("../../vdxf"); +const AppEncryptionRequestOrdinalVDXFObject_1 = require("../../vdxf/classes/ordinals/AppEncryptionRequestOrdinalVDXFObject"); +const DataDescriptorOrdinalVDXFObject_1 = require("../../vdxf/classes/ordinals/DataDescriptorOrdinalVDXFObject"); +const DataPacketResponseOrdinalVDXFObject_1 = require("../../vdxf/classes/ordinals/DataPacketResponseOrdinalVDXFObject"); +const UserDataRequestOrdinalVDXFObject_1 = require("../../vdxf/classes/ordinals/UserDataRequestOrdinalVDXFObject"); +const UserSpecificDataPacketDetailsOrdinalVDXFObject_1 = require("../../vdxf/classes/ordinals/UserSpecificDataPacketDetailsOrdinalVDXFObject"); +const IdentityUpdateRequestOrdinalVDXFObject_1 = require("../../vdxf/classes/ordinals/IdentityUpdateRequestOrdinalVDXFObject"); +const IdentityUpdateResponseOrdinalVDXFObject_1 = require("../../vdxf/classes/ordinals/IdentityUpdateResponseOrdinalVDXFObject"); +const AuthenticationRequestOrdinalVDXFObject_1 = require("../../vdxf/classes/ordinals/AuthenticationRequestOrdinalVDXFObject"); +const AuthenticationResponseOrdinalVDXFObject_1 = require("../../vdxf/classes/ordinals/AuthenticationResponseOrdinalVDXFObject"); +const OrdinalVDXFObjectOrdinalMap_1 = require("../../vdxf/classes/ordinals/OrdinalVDXFObjectOrdinalMap"); +const ProvisionIdentityDetailsOrdinalVDXFObject_1 = require("../../vdxf/classes/ordinals/ProvisionIdentityDetailsOrdinalVDXFObject"); +const VerusPayInvoiceOrdinalVDXFObject_1 = require("../../vdxf/classes/ordinals/VerusPayInvoiceOrdinalVDXFObject"); +const ordinals_1 = require("./ordinals"); +const AppEncryptionResponseOrdinalVDXFObject_1 = require("../../vdxf/classes/ordinals/AppEncryptionResponseOrdinalVDXFObject"); +// This is where all ordinals are currently registered for ordinal VDXF objects. Standard naming convention for the VDXF keys is to +// include the word "response" at the end if it is a response and "request" at the end if it is a request. In case it isn't a request +// (an object expecting a response) or a response, you can use the world "details" at the end, but best not to mix request + details +// or response + details +const registerOrdinals = () => { + OrdinalVDXFObjectOrdinalMap_1.OrdinalVDXFObjectOrdinalMap.registerOrdinal(ordinals_1.VDXF_ORDINAL_DATA_DESCRIPTOR.toNumber(), vdxf_1.DATA_TYPE_OBJECT_DATADESCRIPTOR.vdxfid, DataDescriptorOrdinalVDXFObject_1.DataDescriptorOrdinalVDXFObject, false); + OrdinalVDXFObjectOrdinalMap_1.OrdinalVDXFObjectOrdinalMap.registerOrdinal(ordinals_1.VDXF_ORDINAL_VERUSPAY_INVOICE.toNumber(), vdxf_1.VERUSPAY_INVOICE_DETAILS_VDXF_KEY.vdxfid, VerusPayInvoiceOrdinalVDXFObject_1.VerusPayInvoiceOrdinalVDXFObject, false); + OrdinalVDXFObjectOrdinalMap_1.OrdinalVDXFObjectOrdinalMap.registerOrdinal(ordinals_1.VDXF_ORDINAL_AUTHENTICATION_REQUEST.toNumber(), vdxf_1.AUTHENTICATION_REQUEST_VDXF_KEY.vdxfid, AuthenticationRequestOrdinalVDXFObject_1.AuthenticationRequestOrdinalVDXFObject, false); + OrdinalVDXFObjectOrdinalMap_1.OrdinalVDXFObjectOrdinalMap.registerOrdinal(ordinals_1.VDXF_ORDINAL_AUTHENTICATION_RESPONSE.toNumber(), vdxf_1.AUTHENTICATION_RESPONSE_VDXF_KEY.vdxfid, AuthenticationResponseOrdinalVDXFObject_1.AuthenticationResponseOrdinalVDXFObject, false); + OrdinalVDXFObjectOrdinalMap_1.OrdinalVDXFObjectOrdinalMap.registerOrdinal(ordinals_1.VDXF_ORDINAL_IDENTITY_UPDATE_REQUEST.toNumber(), vdxf_1.IDENTITY_UPDATE_REQUEST_VDXF_KEY.vdxfid, IdentityUpdateRequestOrdinalVDXFObject_1.IdentityUpdateRequestOrdinalVDXFObject, false); + OrdinalVDXFObjectOrdinalMap_1.OrdinalVDXFObjectOrdinalMap.registerOrdinal(ordinals_1.VDXF_ORDINAL_IDENTITY_UPDATE_RESPONSE.toNumber(), vdxf_1.IDENTITY_UPDATE_RESPONSE_VDXF_KEY.vdxfid, IdentityUpdateResponseOrdinalVDXFObject_1.IdentityUpdateResponseOrdinalVDXFObject, false); + OrdinalVDXFObjectOrdinalMap_1.OrdinalVDXFObjectOrdinalMap.registerOrdinal(ordinals_1.VDXF_ORDINAL_PROVISION_IDENTITY_DETAILS.toNumber(), vdxf_1.PROVISION_IDENTITY_DETAILS_VDXF_KEY.vdxfid, ProvisionIdentityDetailsOrdinalVDXFObject_1.ProvisionIdentityDetailsOrdinalVDXFObject, false); + OrdinalVDXFObjectOrdinalMap_1.OrdinalVDXFObjectOrdinalMap.registerOrdinal(ordinals_1.VDXF_ORDINAL_APP_ENCRYPTION_REQUEST.toNumber(), vdxf_1.APP_ENCRYPTION_REQUEST_VDXF_KEY.vdxfid, AppEncryptionRequestOrdinalVDXFObject_1.AppEncryptionRequestOrdinalVDXFObject, false); + OrdinalVDXFObjectOrdinalMap_1.OrdinalVDXFObjectOrdinalMap.registerOrdinal(ordinals_1.VDXF_ORDINAL_DATA_RESPONSE.toNumber(), vdxf_1.DATA_RESPONSE_VDXF_KEY.vdxfid, DataPacketResponseOrdinalVDXFObject_1.DataPacketResponseOrdinalVDXFObject, false); + OrdinalVDXFObjectOrdinalMap_1.OrdinalVDXFObjectOrdinalMap.registerOrdinal(ordinals_1.VDXF_ORDINAL_USER_DATA_REQUEST.toNumber(), vdxf_1.USER_DATA_REQUEST_VDXF_KEY.vdxfid, UserDataRequestOrdinalVDXFObject_1.UserDataRequestOrdinalVDXFObject, false); + OrdinalVDXFObjectOrdinalMap_1.OrdinalVDXFObjectOrdinalMap.registerOrdinal(ordinals_1.VDXF_ORDINAL_USER_SPECIFIC_DATA_PACKET.toNumber(), vdxf_1.USER_SPECIFIC_DATA_PACKET_VDXF_KEY.vdxfid, UserSpecificDataPacketDetailsOrdinalVDXFObject_1.UserSpecificDataPacketDetailsOrdinalVDXFObject, false); + OrdinalVDXFObjectOrdinalMap_1.OrdinalVDXFObjectOrdinalMap.registerOrdinal(ordinals_1.VDXF_ORDINAL_APP_ENCRYPTION_RESPONSE.toNumber(), vdxf_1.APP_ENCRYPTION_RESPONSE_VDXF_KEY.vdxfid, AppEncryptionResponseOrdinalVDXFObject_1.AppEncryptionResponseOrdinalVDXFObject, false); +}; +exports.registerOrdinals = registerOrdinals; diff --git a/dist/constants/ordinals/types.d.ts b/dist/constants/ordinals/types.d.ts new file mode 100644 index 00000000..d51d39b2 --- /dev/null +++ b/dist/constants/ordinals/types.d.ts @@ -0,0 +1,6 @@ +import { DataDescriptor, DataDescriptorJson } from "../../pbaas"; +import { AppEncryptionRequestDetails, AppEncryptionRequestJson, IdentityUpdateRequestDetails, IdentityUpdateRequestDetailsJson, IdentityUpdateResponseDetails, IdentityUpdateResponseDetailsJson, AuthenticationRequestDetails, AuthenticationRequestDetailsJson, AuthenticationResponseDetails, AuthenticationResponseDetailsJson, ProvisionIdentityDetails, ProvisionIdentityDetailsJson, UserDataRequestDetails, UserDataRequestJson, UserSpecificDataPacketDetails, UserSpecificDataPacketDetailsJson, VerusPayInvoiceDetails, AppEncryptionResponseDetails, AppEncryptionResponseDetailsJson } from "../../vdxf/classes"; +import { VerusPayInvoiceDetailsJson } from "../../vdxf/classes/payment/VerusPayInvoiceDetails"; +import { DataPacketResponse, DataResponseJson } from "../../vdxf/classes/datapacket/DataPacketResponse"; +export type OrdinalVDXFObjectReservedData = DataDescriptor | VerusPayInvoiceDetails | IdentityUpdateRequestDetails | IdentityUpdateResponseDetails | AuthenticationRequestDetails | AuthenticationResponseDetails | ProvisionIdentityDetails | AppEncryptionRequestDetails | DataPacketResponse | UserDataRequestDetails | UserSpecificDataPacketDetails | AppEncryptionResponseDetails; +export type OrdinalVDXFObjectReservedDataJson = DataDescriptorJson | VerusPayInvoiceDetailsJson | IdentityUpdateRequestDetailsJson | IdentityUpdateResponseDetailsJson | AuthenticationRequestDetailsJson | AuthenticationResponseDetailsJson | ProvisionIdentityDetailsJson | AppEncryptionRequestJson | DataResponseJson | UserDataRequestJson | UserSpecificDataPacketDetailsJson | AppEncryptionResponseDetailsJson; diff --git a/dist/constants/ordinals/types.js b/dist/constants/ordinals/types.js new file mode 100644 index 00000000..c8ad2e54 --- /dev/null +++ b/dist/constants/ordinals/types.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/dist/constants/pbaas.d.ts b/dist/constants/pbaas.d.ts index 50f2cf94..456ac926 100644 --- a/dist/constants/pbaas.d.ts +++ b/dist/constants/pbaas.d.ts @@ -7,10 +7,12 @@ export declare const DATA_TYPE_HEX: import("bn.js"); export declare const DATA_TYPE_BASE64: import("bn.js"); export declare const DATA_TYPE_DATAHASH: import("bn.js"); export declare const DATA_TYPE_RAWSTRINGDATA: import("bn.js"); -export declare const HASH_TYPE_SHA256: import("bn.js"); -export declare const HASH_TYPE_SHA256D: import("bn.js"); +export declare const HASH_TYPE_INVALID: import("bn.js"); export declare const HASH_TYPE_BLAKE2B: import("bn.js"); +export declare const HASH_TYPE_BLAKE2BMMR2: import("bn.js"); export declare const HASH_TYPE_KECCAK256: import("bn.js"); +export declare const HASH_TYPE_SHA256D: import("bn.js"); +export declare const HASH_TYPE_SHA256: import("bn.js"); export declare const HASH_TYPE_SHA256_NAME = "sha256"; export declare const HASH_TYPE_SHA256D_NAME = "sha256D"; export declare const HASH_TYPE_BLAKE2B_NAME = "blake2b"; diff --git a/dist/constants/pbaas.js b/dist/constants/pbaas.js index 4ffc76d7..89594331 100644 --- a/dist/constants/pbaas.js +++ b/dist/constants/pbaas.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.NULL_I_ADDR = exports.KOMODO_ASSETCHAIN_MAXLEN = exports.DEFAULT_VERUS_CHAINNAME = exports.TESTNET_VERUS_CHAINID = exports.DEFAULT_VERUS_CHAINID = exports.UINT_256_LENGTH = exports.HASH_NAMES = exports.DEFAULT_HASH_TYPE_MMR = exports.DEFAULT_HASH_TYPE = exports.HASH_TYPE_KECCAK256_NAME = exports.HASH_TYPE_BLAKE2B_NAME = exports.HASH_TYPE_SHA256D_NAME = exports.HASH_TYPE_SHA256_NAME = exports.HASH_TYPE_KECCAK256 = exports.HASH_TYPE_BLAKE2B = exports.HASH_TYPE_SHA256D = exports.HASH_TYPE_SHA256 = exports.DATA_TYPE_RAWSTRINGDATA = exports.DATA_TYPE_DATAHASH = exports.DATA_TYPE_BASE64 = exports.DATA_TYPE_HEX = exports.DATA_TYPE_VDXFDATA = exports.DATA_TYPE_MESSAGE = exports.DATA_TYPE_FILENAME = exports.DATA_TYPE_MMRDATA = exports.DATA_TYPE_UNKNOWN = void 0; +exports.NULL_I_ADDR = exports.KOMODO_ASSETCHAIN_MAXLEN = exports.DEFAULT_VERUS_CHAINNAME = exports.TESTNET_VERUS_CHAINID = exports.DEFAULT_VERUS_CHAINID = exports.UINT_256_LENGTH = exports.HASH_NAMES = exports.DEFAULT_HASH_TYPE_MMR = exports.DEFAULT_HASH_TYPE = exports.HASH_TYPE_KECCAK256_NAME = exports.HASH_TYPE_BLAKE2B_NAME = exports.HASH_TYPE_SHA256D_NAME = exports.HASH_TYPE_SHA256_NAME = exports.HASH_TYPE_SHA256 = exports.HASH_TYPE_SHA256D = exports.HASH_TYPE_KECCAK256 = exports.HASH_TYPE_BLAKE2BMMR2 = exports.HASH_TYPE_BLAKE2B = exports.HASH_TYPE_INVALID = exports.DATA_TYPE_RAWSTRINGDATA = exports.DATA_TYPE_DATAHASH = exports.DATA_TYPE_BASE64 = exports.DATA_TYPE_HEX = exports.DATA_TYPE_VDXFDATA = exports.DATA_TYPE_MESSAGE = exports.DATA_TYPE_FILENAME = exports.DATA_TYPE_MMRDATA = exports.DATA_TYPE_UNKNOWN = void 0; const bn_js_1 = require("bn.js"); exports.DATA_TYPE_UNKNOWN = new bn_js_1.BN("0", 10); exports.DATA_TYPE_MMRDATA = new bn_js_1.BN("1", 10); @@ -11,10 +11,12 @@ exports.DATA_TYPE_HEX = new bn_js_1.BN("5", 10); exports.DATA_TYPE_BASE64 = new bn_js_1.BN("6", 10); exports.DATA_TYPE_DATAHASH = new bn_js_1.BN("7", 10); exports.DATA_TYPE_RAWSTRINGDATA = new bn_js_1.BN("8", 10); -exports.HASH_TYPE_SHA256 = new bn_js_1.BN("1", 10); -exports.HASH_TYPE_SHA256D = new bn_js_1.BN("2", 10); -exports.HASH_TYPE_BLAKE2B = new bn_js_1.BN("3", 10); -exports.HASH_TYPE_KECCAK256 = new bn_js_1.BN("4", 10); +exports.HASH_TYPE_INVALID = new bn_js_1.BN(0, 10); +exports.HASH_TYPE_BLAKE2B = new bn_js_1.BN(1, 10); +exports.HASH_TYPE_BLAKE2BMMR2 = new bn_js_1.BN(2, 10); +exports.HASH_TYPE_KECCAK256 = new bn_js_1.BN(3, 10); +exports.HASH_TYPE_SHA256D = new bn_js_1.BN(4, 10); +exports.HASH_TYPE_SHA256 = new bn_js_1.BN(5, 10); exports.HASH_TYPE_SHA256_NAME = "sha256"; exports.HASH_TYPE_SHA256D_NAME = "sha256D"; exports.HASH_TYPE_BLAKE2B_NAME = "blake2b"; diff --git a/dist/constants/vdxf.d.ts b/dist/constants/vdxf.d.ts index eb378139..583e1c8b 100644 --- a/dist/constants/vdxf.d.ts +++ b/dist/constants/vdxf.d.ts @@ -3,5 +3,6 @@ export declare const HASH160_BYTE_LENGTH = 20; export declare const HASH256_BYTE_LENGTH = 32; export declare const I_ADDR_VERSION = 102; export declare const R_ADDR_VERSION = 60; +export declare const X_ADDR_VERSION = 137; export declare const NULL_ADDRESS = "i3UXS5QPRQGNRDDqVnyWTnmFCTHDbzmsYk"; export declare const VERUS_DATA_SIGNATURE_PREFIX: Buffer; diff --git a/dist/constants/vdxf.js b/dist/constants/vdxf.js index 35cf2402..841f4172 100644 --- a/dist/constants/vdxf.js +++ b/dist/constants/vdxf.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.VERUS_DATA_SIGNATURE_PREFIX = exports.NULL_ADDRESS = exports.R_ADDR_VERSION = exports.I_ADDR_VERSION = exports.HASH256_BYTE_LENGTH = exports.HASH160_BYTE_LENGTH = exports.VDXF_OBJECT_DEFAULT_VERSION = void 0; +exports.VERUS_DATA_SIGNATURE_PREFIX = exports.NULL_ADDRESS = exports.X_ADDR_VERSION = exports.R_ADDR_VERSION = exports.I_ADDR_VERSION = exports.HASH256_BYTE_LENGTH = exports.HASH160_BYTE_LENGTH = exports.VDXF_OBJECT_DEFAULT_VERSION = void 0; const bn_js_1 = require("bn.js"); const bufferutils_1 = require("../utils/bufferutils"); exports.VDXF_OBJECT_DEFAULT_VERSION = new bn_js_1.BN(1, 10); @@ -8,6 +8,7 @@ exports.HASH160_BYTE_LENGTH = 20; exports.HASH256_BYTE_LENGTH = 32; exports.I_ADDR_VERSION = 102; exports.R_ADDR_VERSION = 60; +exports.X_ADDR_VERSION = 137; exports.NULL_ADDRESS = "i3UXS5QPRQGNRDDqVnyWTnmFCTHDbzmsYk"; const VERUS_DATA_SIGNATURE_PREFIX_STRING = "Verus signed data:\n"; var bufferWriter = new bufferutils_1.default.BufferWriter(Buffer.alloc(VERUS_DATA_SIGNATURE_PREFIX_STRING.length + 1)); diff --git a/dist/constants/vdxf/veruspay.d.ts b/dist/constants/vdxf/veruspay.d.ts new file mode 100644 index 00000000..23206769 --- /dev/null +++ b/dist/constants/vdxf/veruspay.d.ts @@ -0,0 +1,7 @@ +export declare const VERUSPAY_VERSION_3: import("bn.js"); +export declare const VERUSPAY_VERSION_4: import("bn.js"); +export declare const VERUSPAY_VERSION_CURRENT: import("bn.js"); +export declare const VERUSPAY_VERSION_FIRSTVALID: import("bn.js"); +export declare const VERUSPAY_VERSION_LASTVALID: import("bn.js"); +export declare const VERUSPAY_VERSION_SIGNED: import("bn.js"); +export declare const VERUSPAY_VERSION_MASK: import("bn.js"); diff --git a/dist/constants/vdxf/veruspay.js b/dist/constants/vdxf/veruspay.js new file mode 100644 index 00000000..229947cd --- /dev/null +++ b/dist/constants/vdxf/veruspay.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.VERUSPAY_VERSION_MASK = exports.VERUSPAY_VERSION_SIGNED = exports.VERUSPAY_VERSION_LASTVALID = exports.VERUSPAY_VERSION_FIRSTVALID = exports.VERUSPAY_VERSION_CURRENT = exports.VERUSPAY_VERSION_4 = exports.VERUSPAY_VERSION_3 = void 0; +const bn_js_1 = require("bn.js"); +exports.VERUSPAY_VERSION_3 = new bn_js_1.BN(3, 10); +exports.VERUSPAY_VERSION_4 = new bn_js_1.BN(4, 10); +exports.VERUSPAY_VERSION_CURRENT = new bn_js_1.BN(4, 10); +exports.VERUSPAY_VERSION_FIRSTVALID = new bn_js_1.BN(3, 10); +exports.VERUSPAY_VERSION_LASTVALID = new bn_js_1.BN(4, 10); +exports.VERUSPAY_VERSION_SIGNED = new bn_js_1.BN('80000000', 16); +exports.VERUSPAY_VERSION_MASK = exports.VERUSPAY_VERSION_SIGNED; diff --git a/dist/index.d.ts b/dist/index.d.ts index fcc438b8..ed7438fe 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -18,6 +18,12 @@ export * from './pbaas/PartialIdentity'; export * from './pbaas/PartialMMRData'; export * from './pbaas/PartialSignData'; export * from './constants/pbaas'; +export * from './constants/ordinals/register'; +export * from './constants/ordinals/ordinals'; +export * from './constants/ordinals/types'; +export * from './constants/vdxf/veruspay'; +export * from './constants/deeplink'; export * from './identity/IdentityDefinition'; export * from './currency/CurrencyDefinition'; +export * from './vdxf/classes'; export { BN as BigNumber } from 'bn.js'; diff --git a/dist/index.js b/dist/index.js index 8077d51f..c6d6f139 100644 --- a/dist/index.js +++ b/dist/index.js @@ -35,7 +35,13 @@ __exportStar(require("./pbaas/PartialIdentity"), exports); __exportStar(require("./pbaas/PartialMMRData"), exports); __exportStar(require("./pbaas/PartialSignData"), exports); __exportStar(require("./constants/pbaas"), exports); +__exportStar(require("./constants/ordinals/register"), exports); +__exportStar(require("./constants/ordinals/ordinals"), exports); +__exportStar(require("./constants/ordinals/types"), exports); +__exportStar(require("./constants/vdxf/veruspay"), exports); +__exportStar(require("./constants/deeplink"), exports); __exportStar(require("./identity/IdentityDefinition"), exports); __exportStar(require("./currency/CurrencyDefinition"), exports); +__exportStar(require("./vdxf/classes"), exports); var bn_js_1 = require("bn.js"); Object.defineProperty(exports, "BigNumber", { enumerable: true, get: function () { return bn_js_1.BN; } }); diff --git a/dist/pbaas/ContentMultiMapRemove.js b/dist/pbaas/ContentMultiMapRemove.js index b238983c..e8b2e9dc 100644 --- a/dist/pbaas/ContentMultiMapRemove.js +++ b/dist/pbaas/ContentMultiMapRemove.js @@ -19,9 +19,9 @@ class ContentMultiMapRemove { byteLength += varint_1.default.encodingLength(this.version); byteLength += varint_1.default.encodingLength(this.action); if (this.action != ContentMultiMapRemove.ACTION_CLEAR_MAP) { - byteLength += 20; + byteLength += vdxf_1.HASH160_BYTE_LENGTH; if (this.action != ContentMultiMapRemove.ACTION_REMOVE_ALL_KEY) { - byteLength += 32; + byteLength += vdxf_1.HASH256_BYTE_LENGTH; } } return byteLength; diff --git a/dist/pbaas/Credential.js b/dist/pbaas/Credential.js index 9aedd7ff..f62cf0b5 100644 --- a/dist/pbaas/Credential.js +++ b/dist/pbaas/Credential.js @@ -41,7 +41,7 @@ class Credential { let length = 0; length += varint_1.default.encodingLength(this.version); length += varint_1.default.encodingLength(this.flags); - length += 20; // Credential key + length += vdxf_1.HASH160_BYTE_LENGTH; // Credential key // Both the credential and scopes are serialized as JSON strings. const credStr = JSON.stringify(this.credential); const credentialLength = credStr.length; diff --git a/dist/pbaas/CurrencyValueMap.js b/dist/pbaas/CurrencyValueMap.js index dfeefe05..c1c62f6d 100644 --- a/dist/pbaas/CurrencyValueMap.js +++ b/dist/pbaas/CurrencyValueMap.js @@ -23,7 +23,7 @@ class CurrencyValueMap { byteLength += varuint_1.default.encodingLength(this.value_map.size); } for (const [key, value] of this.value_map) { - byteLength += 20; + byteLength += vdxf_1.HASH160_BYTE_LENGTH; byteLength += this.multivalue ? 8 : varint_1.default.encodingLength(value); } return byteLength; diff --git a/dist/pbaas/DataDescriptor.d.ts b/dist/pbaas/DataDescriptor.d.ts index 6f716166..d682dfe4 100644 --- a/dist/pbaas/DataDescriptor.d.ts +++ b/dist/pbaas/DataDescriptor.d.ts @@ -82,11 +82,11 @@ export declare class VDXFDataDescriptor extends BufferDataVdxfObject { SetFlags(): void; } export declare enum EHashTypes { - HASH_INVALID = 0, - HASH_BLAKE2BMMR = 1, - HASH_BLAKE2BMMR2 = 2, - HASH_KECCAK = 3, - HASH_SHA256D = 4, - HASH_SHA256 = 5, - HASH_LASTTYPE = 5 + HASH_INVALID, + HASH_BLAKE2BMMR, + HASH_BLAKE2BMMR2, + HASH_KECCAK, + HASH_SHA256D, + HASH_SHA256, + HASH_LASTTYPE } diff --git a/dist/pbaas/DataDescriptor.js b/dist/pbaas/DataDescriptor.js index 90465075..23c1a977 100644 --- a/dist/pbaas/DataDescriptor.js +++ b/dist/pbaas/DataDescriptor.js @@ -9,6 +9,7 @@ const { BufferReader, BufferWriter } = bufferutils_1.default; const _1 = require("."); const index_1 = require("../vdxf/index"); const VDXF_Data = require("../vdxf/vdxfdatakeys"); +const pbaas_1 = require("../constants/pbaas"); class DataDescriptor { constructor(data) { this.flags = new bn_js_1.BN(0); @@ -323,12 +324,12 @@ exports.VDXFDataDescriptor = VDXFDataDescriptor; ; var EHashTypes; (function (EHashTypes) { - EHashTypes[EHashTypes["HASH_INVALID"] = 0] = "HASH_INVALID"; - EHashTypes[EHashTypes["HASH_BLAKE2BMMR"] = 1] = "HASH_BLAKE2BMMR"; - EHashTypes[EHashTypes["HASH_BLAKE2BMMR2"] = 2] = "HASH_BLAKE2BMMR2"; - EHashTypes[EHashTypes["HASH_KECCAK"] = 3] = "HASH_KECCAK"; - EHashTypes[EHashTypes["HASH_SHA256D"] = 4] = "HASH_SHA256D"; - EHashTypes[EHashTypes["HASH_SHA256"] = 5] = "HASH_SHA256"; - EHashTypes[EHashTypes["HASH_LASTTYPE"] = 5] = "HASH_LASTTYPE"; + EHashTypes[EHashTypes["HASH_INVALID"] = pbaas_1.HASH_TYPE_INVALID.toNumber()] = "HASH_INVALID"; + EHashTypes[EHashTypes["HASH_BLAKE2BMMR"] = pbaas_1.HASH_TYPE_BLAKE2B.toNumber()] = "HASH_BLAKE2BMMR"; + EHashTypes[EHashTypes["HASH_BLAKE2BMMR2"] = pbaas_1.HASH_TYPE_BLAKE2BMMR2.toNumber()] = "HASH_BLAKE2BMMR2"; + EHashTypes[EHashTypes["HASH_KECCAK"] = pbaas_1.HASH_TYPE_KECCAK256.toNumber()] = "HASH_KECCAK"; + EHashTypes[EHashTypes["HASH_SHA256D"] = pbaas_1.HASH_TYPE_SHA256D.toNumber()] = "HASH_SHA256D"; + EHashTypes[EHashTypes["HASH_SHA256"] = pbaas_1.HASH_TYPE_SHA256.toNumber()] = "HASH_SHA256"; + EHashTypes[EHashTypes["HASH_LASTTYPE"] = pbaas_1.HASH_TYPE_SHA256.toNumber()] = "HASH_LASTTYPE"; })(EHashTypes || (exports.EHashTypes = EHashTypes = {})); ; diff --git a/dist/pbaas/EvidenceData.js b/dist/pbaas/EvidenceData.js index 05d7682c..c1a404eb 100644 --- a/dist/pbaas/EvidenceData.js +++ b/dist/pbaas/EvidenceData.js @@ -64,7 +64,7 @@ class EvidenceData { byteLength += this.md.getByteLength(); } else { - byteLength += 20; + byteLength += vdxf_1.HASH160_BYTE_LENGTH; } byteLength += varuint_1.default.encodingLength(this.data_vec.length); byteLength += this.data_vec.length; diff --git a/dist/pbaas/Identity.js b/dist/pbaas/Identity.js index 6532339a..a1348af7 100644 --- a/dist/pbaas/Identity.js +++ b/dist/pbaas/Identity.js @@ -95,14 +95,14 @@ class Identity extends Principal_1.Principal { if (this.version.lt(exports.IDENTITY_VERSION_PBAAS)) { length += varuint_1.default.encodingLength(this.content_map.size); for (const m of this.content_map.entries()) { - length += 20; //uint160 key - length += 32; //uint256 hash + length += vdxf_1.HASH160_BYTE_LENGTH; //uint160 key + length += vdxf_1.HASH256_BYTE_LENGTH; } } length += varuint_1.default.encodingLength(this.content_map.size); for (const m of this.content_map.entries()) { - length += 20; //uint160 key - length += 32; //uint256 hash + length += vdxf_1.HASH160_BYTE_LENGTH; //uint160 key + length += vdxf_1.HASH256_BYTE_LENGTH; //uint256 hash } } if (this.containsRevocation()) @@ -307,7 +307,7 @@ class Identity extends Principal_1.Principal { else if (unlockTime.gt(exports.IDENTITY_MAX_UNLOCK_DELAY)) { unlockAfter = exports.IDENTITY_MAX_UNLOCK_DELAY; } - this.flags = this.flags.xor(exports.IDENTITY_FLAG_LOCKED); + this.flags = this.flags.or(exports.IDENTITY_FLAG_LOCKED); this.unlock_after = unlockAfter; } unlock(height = new bn_js_1.BN(0), txExpiryHeight = new bn_js_1.BN(0)) { @@ -327,7 +327,7 @@ class Identity extends Principal_1.Principal { } } revoke() { - this.flags = this.flags.xor(exports.IDENTITY_FLAG_REVOKED); + this.flags = this.flags.or(exports.IDENTITY_FLAG_REVOKED); this.unlock(); } unrevoke() { diff --git a/dist/pbaas/IdentityMultimapRef.js b/dist/pbaas/IdentityMultimapRef.js index ff7526d4..ac6dd1eb 100644 --- a/dist/pbaas/IdentityMultimapRef.js +++ b/dist/pbaas/IdentityMultimapRef.js @@ -34,15 +34,15 @@ class IdentityMultimapRef { this.setFlags(); byteLength += varint_1.default.encodingLength(this.version); byteLength += varint_1.default.encodingLength(this.flags); - byteLength += 20; // id_ID uint160 - byteLength += 20; // key uint160 + byteLength += vdxf_1.HASH160_BYTE_LENGTH; // id_ID + byteLength += vdxf_1.HASH160_BYTE_LENGTH; // vdxfkey byteLength += varint_1.default.encodingLength(this.height_start); // height_start uint32 byteLength += varint_1.default.encodingLength(this.height_end); // height_end uint32 if (this.flags.and(IdentityMultimapRef.FLAG_HAS_DATAHASH).gt(new bn_js_1.BN(0))) { - byteLength += 32; + byteLength += vdxf_1.HASH256_BYTE_LENGTH; } if (this.flags.and(IdentityMultimapRef.FLAG_HAS_SYSTEM).gt(new bn_js_1.BN(0))) { - byteLength += 20; + byteLength += vdxf_1.HASH160_BYTE_LENGTH; } return byteLength; } diff --git a/dist/pbaas/PBaaSEvidenceRef.js b/dist/pbaas/PBaaSEvidenceRef.js index 43a25143..08afd9e2 100644 --- a/dist/pbaas/PBaaSEvidenceRef.js +++ b/dist/pbaas/PBaaSEvidenceRef.js @@ -34,7 +34,7 @@ class PBaaSEvidenceRef { byteLength += varint_1.default.encodingLength(this.object_num); byteLength += varint_1.default.encodingLength(this.sub_object); if (this.flags.and(PBaaSEvidenceRef.FLAG_HAS_SYSTEM).gt(new bn_js_1.BN(0))) { - byteLength += 20; + byteLength += vdxf_1.HASH160_BYTE_LENGTH; } return byteLength; } diff --git a/dist/pbaas/PartialSignData.d.ts b/dist/pbaas/PartialSignData.d.ts index 01076c18..44a583dd 100644 --- a/dist/pbaas/PartialSignData.d.ts +++ b/dist/pbaas/PartialSignData.d.ts @@ -9,15 +9,15 @@ import { VdxfUniValue, VdxfUniValueJson } from './VdxfUniValue'; export type PartialSignDataInitData = { flags?: BigNumber; address?: IdentityID | KeyID; - prefixstring?: Buffer; - vdxfkeys?: Array; - vdxfkeynames?: Array; - boundhashes?: Array; - hashtype?: BigNumber; - encrypttoaddress?: SaplingPaymentAddress; - createmmr?: boolean; + prefixString?: Buffer; + vdxfKeys?: Array; + vdxfKeyNames?: Array; + boundHashes?: Array; + hashType?: BigNumber; + encryptToAddress?: SaplingPaymentAddress; + createMMR?: boolean; signature?: Buffer; - datatype?: BigNumber; + dataType?: BigNumber; data?: Buffer | PartialMMRData | VdxfUniValue; }; export type PartialSignDataJson = { @@ -51,15 +51,15 @@ type SignDataKeys = { }; type BaseFields = { address?: string; - prefixstring?: string; - vdxfkeys?: Array; - vdxfkeynames?: Array; - boundhashes?: Array; - hashtype?: string; - encrypttoaddress?: string; - createmmr?: boolean; + prefixString?: string; + vdxfKeys?: Array; + vdxfKeyNames?: Array; + boundHashes?: Array; + hashType?: string; + encryptToAddress?: string; + createMMR?: boolean; signature?: string; - datatype?: string; + dataType?: string; data?: string; }; type MMRFields = { @@ -71,15 +71,15 @@ export type PartialSignDataCLIJson = ((AtLeastOne> export declare class PartialSignData implements SerializableEntity { flags: BigNumber; address?: IdentityID | KeyID; - prefixstring?: Buffer; - vdxfkeys?: Array; - vdxfkeynames?: Array; - boundhashes?: Array; - hashtype?: BigNumber; - encrypttoaddress?: SaplingPaymentAddress; - createmmr?: boolean; + prefixString?: Buffer; + vdxfKeys?: Array; + vdxfKeyNames?: Array; + boundHashes?: Array; + hashType?: BigNumber; + encryptToAddress?: SaplingPaymentAddress; + createMMR?: boolean; signature?: Buffer; - datatype?: BigNumber; + dataType?: BigNumber; data?: Buffer | PartialMMRData | VdxfUniValue; static CONTAINS_DATA: import("bn.js"); static CONTAINS_ADDRESS: import("bn.js"); diff --git a/dist/pbaas/PartialSignData.js b/dist/pbaas/PartialSignData.js index 80208de0..795f49e4 100644 --- a/dist/pbaas/PartialSignData.js +++ b/dist/pbaas/PartialSignData.js @@ -2,7 +2,6 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.PartialSignData = void 0; const bn_js_1 = require("bn.js"); -const varint_1 = require("../utils/varint"); const bufferutils_1 = require("../utils/bufferutils"); const IdentityID_1 = require("./IdentityID"); const KeyID_1 = require("./KeyID"); @@ -18,52 +17,52 @@ const { BufferReader, BufferWriter } = bufferutils_1.default; class PartialSignData { constructor(data) { this.flags = data && data.flags ? data.flags : new bn_js_1.BN("0"); - this.createmmr = data && data.createmmr ? data.createmmr : false; + this.createMMR = data && data.createMMR ? data.createMMR : false; if (data === null || data === void 0 ? void 0 : data.address) { if (!this.containsAddress()) this.toggleContainsAddress(); this.address = data.address; } - if (data === null || data === void 0 ? void 0 : data.prefixstring) { + if (data === null || data === void 0 ? void 0 : data.prefixString) { if (!this.containsPrefixString()) this.toggleContainsPrefixString(); - this.prefixstring = data.prefixstring; + this.prefixString = data.prefixString; } - if (data === null || data === void 0 ? void 0 : data.vdxfkeys) { + if (data === null || data === void 0 ? void 0 : data.vdxfKeys) { if (!this.containsVdxfKeys()) this.toggleContainsVdxfKeys(); - this.vdxfkeys = data.vdxfkeys; + this.vdxfKeys = data.vdxfKeys; } - if (data === null || data === void 0 ? void 0 : data.vdxfkeynames) { + if (data === null || data === void 0 ? void 0 : data.vdxfKeyNames) { if (!this.containsVdxfKeyNames()) this.toggleContainsVdxfKeyNames(); - this.vdxfkeynames = data.vdxfkeynames; + this.vdxfKeyNames = data.vdxfKeyNames; } - if (data === null || data === void 0 ? void 0 : data.hashtype) { - this.hashtype = data.hashtype; + if (data === null || data === void 0 ? void 0 : data.hashType) { + this.hashType = data.hashType; } else - this.hashtype = pbaas_1.DEFAULT_HASH_TYPE; - if (data === null || data === void 0 ? void 0 : data.boundhashes) { + this.hashType = pbaas_1.DEFAULT_HASH_TYPE; + if (data === null || data === void 0 ? void 0 : data.boundHashes) { if (!this.containsBoundhashes()) this.toggleContainsBoundHashes(); - this.boundhashes = data.boundhashes; + this.boundHashes = data.boundHashes; } - if (data === null || data === void 0 ? void 0 : data.encrypttoaddress) { + if (data === null || data === void 0 ? void 0 : data.encryptToAddress) { if (!this.containsEncrypttoAddress()) this.toggleContainsEncryptToAddress(); - this.encrypttoaddress = data.encrypttoaddress; + this.encryptToAddress = data.encryptToAddress; } if (data === null || data === void 0 ? void 0 : data.signature) { if (!this.containsCurrentSig()) this.toggleContainsCurrentSig(); this.signature = data.signature; } - if ((data === null || data === void 0 ? void 0 : data.datatype) && (data === null || data === void 0 ? void 0 : data.data)) { + if ((data === null || data === void 0 ? void 0 : data.dataType) && (data === null || data === void 0 ? void 0 : data.data)) { if (!this.containsData()) this.toggleContainsData(); this.data = data.data; - this.datatype = data.datatype; + this.dataType = data.dataType; } } containsData() { @@ -115,10 +114,10 @@ class PartialSignData { this.flags = this.flags.xor(PartialSignData.CONTAINS_BOUNDHASHES); } isMMRData() { - return this.datatype && this.datatype.eq(pbaas_1.DATA_TYPE_MMRDATA); + return this.dataType && this.dataType.eq(pbaas_1.DATA_TYPE_MMRDATA); } isVdxfData() { - return this.datatype && this.datatype.eq(pbaas_1.DATA_TYPE_VDXFDATA); + return this.dataType && this.dataType.eq(pbaas_1.DATA_TYPE_VDXFDATA); } getPartialSignDataByteLength() { function calculateVectorLength(items, getItemLength, varlength = true) { @@ -133,30 +132,30 @@ class PartialSignData { return totalLength; } let length = 0; - length += varint_1.default.encodingLength(this.flags); + length += varuint_1.default.encodingLength(this.flags.toNumber()); if (this.containsAddress()) length += this.address.getByteLength(); if (this.containsPrefixString()) { - const prefixLen = this.prefixstring.length; + const prefixLen = this.prefixString.length; length += varuint_1.default.encodingLength(prefixLen); length += prefixLen; } if (this.containsVdxfKeys()) { - length += calculateVectorLength(this.vdxfkeys, (vdxfkey) => vdxfkey.getByteLength(), false); + length += calculateVectorLength(this.vdxfKeys, (vdxfkey) => vdxfkey.getByteLength(), false); } if (this.containsVdxfKeyNames()) { - length += calculateVectorLength(this.vdxfkeynames, (vdxfname) => vdxfname.length); + length += calculateVectorLength(this.vdxfKeyNames, (vdxfname) => vdxfname.length); } - length += varint_1.default.encodingLength(this.hashtype); + length += varuint_1.default.encodingLength(this.hashType.toNumber()); if (this.containsBoundhashes()) { - length += calculateVectorLength(this.boundhashes, (hash) => hash.length); + length += calculateVectorLength(this.boundHashes, (hash) => hash.length); } if (this.containsEncrypttoAddress()) { - length += this.encrypttoaddress.getByteLength(); + length += this.encryptToAddress.getByteLength(); } length += 1; // Createmmr boolean value if (this.containsData()) { - length += varint_1.default.encodingLength(this.datatype); + length += varuint_1.default.encodingLength(this.dataType.toNumber()); if (this.isMMRData()) { length += this.data.getByteLength(); } @@ -178,7 +177,7 @@ class PartialSignData { } fromBuffer(buffer, offset = 0) { const reader = new BufferReader(buffer, offset); - this.flags = reader.readVarInt(); + this.flags = new bn_js_1.BN(reader.readCompactSize()); if (this.containsAddress()) { const hash160 = new Hash160_1.Hash160SerEnt(); hash160.fromBuffer(reader.readSlice(vdxf_1.HASH160_BYTE_LENGTH)); @@ -192,33 +191,33 @@ class PartialSignData { throw new Error("Unrecognized address version"); } if (this.containsPrefixString()) { - this.prefixstring = reader.readVarSlice(); + this.prefixString = reader.readVarSlice(); } if (this.containsVdxfKeys()) { const count = reader.readCompactSize(); - this.vdxfkeys = []; + this.vdxfKeys = []; for (let i = 0; i < count; i++) { const varSlice = reader.readSlice(vdxf_1.HASH160_BYTE_LENGTH); const idId = new IdentityID_1.IdentityID(); idId.fromBuffer(varSlice); - this.vdxfkeys.push(idId); + this.vdxfKeys.push(idId); } } if (this.containsVdxfKeyNames()) { - this.vdxfkeynames = reader.readVector(); + this.vdxfKeyNames = reader.readVector(); } - this.hashtype = reader.readVarInt(); + this.hashType = new bn_js_1.BN(reader.readCompactSize()); if (this.containsBoundhashes()) { - this.boundhashes = reader.readVector(); + this.boundHashes = reader.readVector(); } if (this.containsEncrypttoAddress()) { const saplingAddr = new SaplingPaymentAddress_1.SaplingPaymentAddress(); reader.offset = saplingAddr.fromBuffer(reader.buffer, reader.offset); - this.encrypttoaddress = saplingAddr; + this.encryptToAddress = saplingAddr; } - this.createmmr = !!reader.readUInt8(); + this.createMMR = !!reader.readUInt8(); if (this.containsData()) { - this.datatype = reader.readVarInt(); + this.dataType = new bn_js_1.BN(reader.readCompactSize()); if (this.isMMRData()) { const partialMMRData = new PartialMMRData_1.PartialMMRData(); reader.offset = partialMMRData.fromBuffer(reader.buffer, reader.offset); @@ -241,7 +240,7 @@ class PartialSignData { // Make sure getPartialSignDataByteLength() accounts for all fields in your updated model. const writer = new BufferWriter(Buffer.alloc(this.getPartialSignDataByteLength())); // Serialize flags - writer.writeVarInt(this.flags); + writer.writeCompactSize(this.flags.toNumber()); // Address if (this.containsAddress()) { if (!this.address) { @@ -251,51 +250,51 @@ class PartialSignData { } // Prefix string if (this.containsPrefixString()) { - if (!this.prefixstring) { + if (!this.prefixString) { throw new Error("Prefix string is required but not provided"); } - writer.writeVarSlice(this.prefixstring); + writer.writeVarSlice(this.prefixString); } // VDXF keys if (this.containsVdxfKeys()) { - if (!this.vdxfkeys) { + if (!this.vdxfKeys) { throw new Error("VDXF keys are required but not provided"); } - writer.writeCompactSize(this.vdxfkeys.length); - for (const vdxfkey of this.vdxfkeys) { + writer.writeCompactSize(this.vdxfKeys.length); + for (const vdxfkey of this.vdxfKeys) { writer.writeSlice(vdxfkey.toBuffer()); } } // VDXF key names if (this.containsVdxfKeyNames()) { - if (!this.vdxfkeynames) { + if (!this.vdxfKeyNames) { throw new Error("VDXF key names are required but not provided"); } - writer.writeVector(this.vdxfkeynames); + writer.writeVector(this.vdxfKeyNames); } - writer.writeVarInt(this.hashtype); + writer.writeCompactSize(this.hashType.toNumber()); // Bound hashes if (this.containsBoundhashes()) { - if (!this.boundhashes) { + if (!this.boundHashes) { throw new Error("Bound hashes are required but not provided"); } - writer.writeVector(this.boundhashes); + writer.writeVector(this.boundHashes); } // Encrypt-to address (Sapling) if (this.containsEncrypttoAddress()) { - if (!this.encrypttoaddress || !(this.encrypttoaddress instanceof SaplingPaymentAddress_1.SaplingPaymentAddress)) { + if (!this.encryptToAddress || !(this.encryptToAddress instanceof SaplingPaymentAddress_1.SaplingPaymentAddress)) { throw new Error("Sapling payment address is required but not provided"); } - writer.writeSlice(this.encrypttoaddress.toBuffer()); + writer.writeSlice(this.encryptToAddress.toBuffer()); } - // createmmr (boolean) - writer.writeUInt8(this.createmmr ? 1 : 0); + // createMMR (boolean) + writer.writeUInt8(this.createMMR ? 1 : 0); // Data if (this.containsData()) { - if (!this.data || !this.datatype) { + if (!this.data || !this.dataType) { throw new Error("Data is required but not provided"); } - writer.writeVarInt(this.datatype); + writer.writeCompactSize(this.dataType.toNumber()); if (this.isMMRData()) { const mmrData = this.data; writer.writeSlice(mmrData.toBuffer()); @@ -314,15 +313,15 @@ class PartialSignData { return { flags: this.flags ? this.flags.toString(10) : undefined, address: this.address ? this.address.toAddress() : undefined, - prefixstring: this.prefixstring ? this.prefixstring.toString('utf-8') : undefined, - vdxfkeys: this.vdxfkeys ? this.vdxfkeys.map(x => x.toAddress()) : undefined, - vdxfkeynames: this.vdxfkeynames ? this.vdxfkeynames.map(x => x.toString('utf-8')) : undefined, - boundhashes: this.boundhashes ? this.boundhashes.map(x => x.toString('hex')) : undefined, - hashtype: this.hashtype ? this.hashtype.toString(10) : undefined, - encrypttoaddress: this.encrypttoaddress ? this.encrypttoaddress.toAddressString() : undefined, - createmmr: this.createmmr, + prefixstring: this.prefixString ? this.prefixString.toString('utf-8') : undefined, + vdxfkeys: this.vdxfKeys ? this.vdxfKeys.map(x => x.toAddress()) : undefined, + vdxfkeynames: this.vdxfKeyNames ? this.vdxfKeyNames.map(x => x.toString('utf-8')) : undefined, + boundhashes: this.boundHashes ? this.boundHashes.map(x => x.toString('hex')) : undefined, + hashtype: this.hashType ? this.hashType.toString(10) : undefined, + encrypttoaddress: this.encryptToAddress ? this.encryptToAddress.toAddressString() : undefined, + createmmr: this.createMMR, signature: this.signature ? this.signature.toString('base64') : undefined, - datatype: this.datatype ? this.datatype.toString(10) : undefined, + datatype: this.dataType ? this.dataType.toString(10) : undefined, data: this.data ? this.data instanceof PartialMMRData_1.PartialMMRData ? this.data.toJson() : this.data.toString('hex') : undefined }; } @@ -339,24 +338,24 @@ class PartialSignData { else throw new Error("Unrecognized address version"); } - const datatype = json.datatype ? new bn_js_1.BN(json.datatype, 10) : undefined; + const dataType = json.datatype ? new bn_js_1.BN(json.datatype, 10) : undefined; return new PartialSignData({ flags: json.flags ? new bn_js_1.BN(json.flags, 10) : undefined, address: addr, - prefixstring: json.prefixstring ? Buffer.from(json.prefixstring, 'utf-8') : undefined, - vdxfkeys: json.vdxfkeys ? json.vdxfkeys.map(x => IdentityID_1.IdentityID.fromAddress(x)) : undefined, - vdxfkeynames: json.vdxfkeynames ? json.vdxfkeynames.map(x => Buffer.from(x, 'utf-8')) : undefined, - boundhashes: json.boundhashes ? json.boundhashes.map(x => Buffer.from(x, 'hex')) : undefined, - hashtype: json.hashtype ? new bn_js_1.BN(json.hashtype, 10) : undefined, - encrypttoaddress: json.encrypttoaddress ? SaplingPaymentAddress_1.SaplingPaymentAddress.fromAddressString(json.encrypttoaddress) : undefined, - createmmr: json.createmmr, + prefixString: json.prefixstring ? Buffer.from(json.prefixstring, 'utf-8') : undefined, + vdxfKeys: json.vdxfkeys ? json.vdxfkeys.map(x => IdentityID_1.IdentityID.fromAddress(x)) : undefined, + vdxfKeyNames: json.vdxfkeynames ? json.vdxfkeynames.map(x => Buffer.from(x, 'utf-8')) : undefined, + boundHashes: json.boundhashes ? json.boundhashes.map(x => Buffer.from(x, 'hex')) : undefined, + hashType: json.hashtype ? new bn_js_1.BN(json.hashtype, 10) : undefined, + encryptToAddress: json.encrypttoaddress ? SaplingPaymentAddress_1.SaplingPaymentAddress.fromAddressString(json.encrypttoaddress) : undefined, + createMMR: json.createmmr, signature: json.signature ? Buffer.from(json.signature, 'base64') : undefined, - datatype: json.datatype ? new bn_js_1.BN(json.datatype, 10) : undefined, + dataType: json.datatype ? new bn_js_1.BN(json.datatype, 10) : undefined, data: json.data ? typeof json.data === 'string' ? Buffer.from(json.data, 'hex') : - datatype && datatype.eq(pbaas_1.DATA_TYPE_MMRDATA) ? + dataType && dataType.eq(pbaas_1.DATA_TYPE_MMRDATA) ? PartialMMRData_1.PartialMMRData.fromJson(json.data) : VdxfUniValue_1.VdxfUniValue.fromJson(json.data) @@ -367,23 +366,23 @@ class PartialSignData { toCLIJson() { const ret = { address: this.address ? this.address.toAddress() : undefined, - prefixstring: this.prefixstring ? this.prefixstring.toString('utf-8') : undefined, - vdxfkeys: this.vdxfkeys ? this.vdxfkeys.map(x => x.toAddress()) : undefined, - vdxfkeynames: this.vdxfkeynames ? this.vdxfkeynames.map(x => x.toString('utf-8')) : undefined, - boundhashes: this.boundhashes ? this.boundhashes.map(x => x.toString('hex')) : undefined, - encrypttoaddress: this.encrypttoaddress ? this.encrypttoaddress.toAddressString() : undefined, - createmmr: this.createmmr, + prefixString: this.prefixString ? this.prefixString.toString('utf-8') : undefined, + vdxfKeys: this.vdxfKeys ? this.vdxfKeys.map(x => x.toAddress()) : undefined, + vdxfKeyNames: this.vdxfKeyNames ? this.vdxfKeyNames.map(x => x.toString('utf-8')) : undefined, + boundHashes: this.boundHashes ? this.boundHashes.map(x => x.toString('hex')) : undefined, + encryptToAddress: this.encryptToAddress ? this.encryptToAddress.toAddressString() : undefined, + createMMR: this.createMMR, signature: this.signature ? this.signature.toString('base64') : undefined }; - if (this.containsData() && this.data && this.datatype) { - if (this.datatype.eq(pbaas_1.DATA_TYPE_MMRDATA)) { + if (this.containsData() && this.data && this.dataType) { + if (this.dataType.eq(pbaas_1.DATA_TYPE_MMRDATA)) { const mmrCLIJson = this.data.toCLIJson(); ret['mmrdata'] = mmrCLIJson.mmrdata; ret['mmrsalt'] = mmrCLIJson.mmrsalt; ret['mmrhashtype'] = mmrCLIJson.mmrhashtype; ret['priormmr'] = mmrCLIJson.priormmr; } - else if (this.datatype.eq(pbaas_1.DATA_TYPE_VDXFDATA)) { + else if (this.dataType.eq(pbaas_1.DATA_TYPE_VDXFDATA)) { const uniJson = this.data.toJson(); if (Array.isArray(uniJson)) throw new Error("VDXF univalue arrays not supported as sign data param"); @@ -391,36 +390,36 @@ class PartialSignData { } else { const dataBuf = this.data; - if (this.datatype.eq(pbaas_1.DATA_TYPE_FILENAME)) { + if (this.dataType.eq(pbaas_1.DATA_TYPE_FILENAME)) { ret['filename'] = dataBuf.toString('utf-8'); } - else if (this.datatype.eq(pbaas_1.DATA_TYPE_MESSAGE)) { + else if (this.dataType.eq(pbaas_1.DATA_TYPE_MESSAGE)) { ret['message'] = dataBuf.toString('utf-8'); } - else if (this.datatype.eq(pbaas_1.DATA_TYPE_HEX)) { + else if (this.dataType.eq(pbaas_1.DATA_TYPE_HEX)) { ret['messagehex'] = dataBuf.toString('hex'); } - else if (this.datatype.eq(pbaas_1.DATA_TYPE_BASE64)) { + else if (this.dataType.eq(pbaas_1.DATA_TYPE_BASE64)) { ret['messagebase64'] = dataBuf.toString('base64'); } - else if (this.datatype.eq(pbaas_1.DATA_TYPE_DATAHASH)) { + else if (this.dataType.eq(pbaas_1.DATA_TYPE_DATAHASH)) { ret['datahash'] = dataBuf.toString('hex'); } else - throw new Error("Unrecognized datatype"); + throw new Error("Unrecognized dataType"); } } - if (this.hashtype.eq(pbaas_1.HASH_TYPE_SHA256)) { - ret['hashtype'] = pbaas_1.HASH_TYPE_SHA256_NAME; + if (this.hashType.eq(pbaas_1.HASH_TYPE_SHA256)) { + ret['hashType'] = pbaas_1.HASH_TYPE_SHA256_NAME; } - else if (this.hashtype.eq(pbaas_1.HASH_TYPE_SHA256D)) { - ret['hashtype'] = pbaas_1.HASH_TYPE_SHA256D_NAME; + else if (this.hashType.eq(pbaas_1.HASH_TYPE_SHA256D)) { + ret['hashType'] = pbaas_1.HASH_TYPE_SHA256D_NAME; } - else if (this.hashtype.eq(pbaas_1.HASH_TYPE_BLAKE2B)) { - ret['hashtype'] = pbaas_1.HASH_TYPE_BLAKE2B_NAME; + else if (this.hashType.eq(pbaas_1.HASH_TYPE_BLAKE2B)) { + ret['hashType'] = pbaas_1.HASH_TYPE_BLAKE2B_NAME; } - else if (this.hashtype.eq(pbaas_1.HASH_TYPE_KECCAK256)) { - ret['hashtype'] = pbaas_1.HASH_TYPE_KECCAK256_NAME; + else if (this.hashType.eq(pbaas_1.HASH_TYPE_KECCAK256)) { + ret['hashType'] = pbaas_1.HASH_TYPE_KECCAK256_NAME; } else throw new Error("Unrecognized hash type"); @@ -445,12 +444,12 @@ class PartialSignData { } const config = { address: addr, - prefixstring: json.prefixstring ? Buffer.from(json.prefixstring, 'utf-8') : undefined, - vdxfkeys: json.vdxfkeys ? json.vdxfkeys.map(x => IdentityID_1.IdentityID.fromAddress(x)) : undefined, - vdxfkeynames: json.vdxfkeynames ? json.vdxfkeynames.map(x => Buffer.from(x, 'utf-8')) : undefined, - boundhashes: json.boundhashes ? json.boundhashes.map(x => Buffer.from(x, 'hex')) : undefined, - encrypttoaddress: json.encrypttoaddress ? SaplingPaymentAddress_1.SaplingPaymentAddress.fromAddressString(json.encrypttoaddress) : undefined, - createmmr: json.createmmr, + prefixString: json.prefixString ? Buffer.from(json.prefixString, 'utf-8') : undefined, + vdxfKeys: json.vdxfKeys ? json.vdxfKeys.map(x => IdentityID_1.IdentityID.fromAddress(x)) : undefined, + vdxfKeyNames: json.vdxfKeyNames ? json.vdxfKeyNames.map(x => Buffer.from(x, 'utf-8')) : undefined, + boundHashes: json.boundHashes ? json.boundHashes.map(x => Buffer.from(x, 'hex')) : undefined, + encryptToAddress: json.encryptToAddress ? SaplingPaymentAddress_1.SaplingPaymentAddress.fromAddressString(json.encryptToAddress) : undefined, + createMMR: json.createMMR, signature: json.signature ? Buffer.from(json.signature, 'base64') : undefined }; if ('mmrdata' in json) { @@ -461,45 +460,45 @@ class PartialSignData { priormmr: json.priormmr }); config.data = pmd; - config.datatype = pbaas_1.DATA_TYPE_MMRDATA; + config.dataType = pbaas_1.DATA_TYPE_MMRDATA; } else if (json.filename) { config.data = Buffer.from(json.filename, 'utf-8'); - config.datatype = pbaas_1.DATA_TYPE_FILENAME; + config.dataType = pbaas_1.DATA_TYPE_FILENAME; } else if (json.message) { config.data = Buffer.from(json.message, 'utf-8'); - config.datatype = pbaas_1.DATA_TYPE_MESSAGE; + config.dataType = pbaas_1.DATA_TYPE_MESSAGE; } else if (json.vdxfdata) { config.data = VdxfUniValue_1.VdxfUniValue.fromJson(json.vdxfdata); - config.datatype = pbaas_1.DATA_TYPE_VDXFDATA; + config.dataType = pbaas_1.DATA_TYPE_VDXFDATA; } else if (json.messagehex) { config.data = Buffer.from(json.messagehex, 'hex'); - config.datatype = pbaas_1.DATA_TYPE_HEX; + config.dataType = pbaas_1.DATA_TYPE_HEX; } else if (json.messagebase64) { config.data = Buffer.from(json.messagebase64, 'base64'); - config.datatype = pbaas_1.DATA_TYPE_BASE64; + config.dataType = pbaas_1.DATA_TYPE_BASE64; } else if (json.datahash) { config.data = Buffer.from(json.datahash, 'hex'); - config.datatype = pbaas_1.DATA_TYPE_DATAHASH; + config.dataType = pbaas_1.DATA_TYPE_DATAHASH; } - if (json.hashtype) { - switch (json.hashtype) { + if (json.hashType) { + switch (json.hashType) { case pbaas_1.HASH_TYPE_SHA256_NAME: - config.hashtype = pbaas_1.HASH_TYPE_SHA256; + config.hashType = pbaas_1.HASH_TYPE_SHA256; break; case pbaas_1.HASH_TYPE_SHA256D_NAME: - config.hashtype = pbaas_1.HASH_TYPE_SHA256D; + config.hashType = pbaas_1.HASH_TYPE_SHA256D; break; case pbaas_1.HASH_TYPE_BLAKE2B_NAME: - config.hashtype = pbaas_1.HASH_TYPE_BLAKE2B; + config.hashType = pbaas_1.HASH_TYPE_BLAKE2B; break; case pbaas_1.HASH_TYPE_KECCAK256_NAME: - config.hashtype = pbaas_1.HASH_TYPE_KECCAK256; + config.hashType = pbaas_1.HASH_TYPE_KECCAK256; break; default: throw new Error("Unrecognized hash type"); diff --git a/dist/pbaas/Rating.js b/dist/pbaas/Rating.js index f823c0ec..b315273d 100644 --- a/dist/pbaas/Rating.js +++ b/dist/pbaas/Rating.js @@ -19,7 +19,7 @@ class Rating { byteLength += 1; // trust_level uint8 byteLength += varuint_1.default.encodingLength(this.ratings.size); for (const [key, value] of this.ratings) { - byteLength += 20; + byteLength += vdxf_1.HASH160_BYTE_LENGTH; byteLength += varuint_1.default.encodingLength(value.length); byteLength += value.length; } diff --git a/dist/pbaas/SaltedData.js b/dist/pbaas/SaltedData.js index cc685204..0a73a8e7 100644 --- a/dist/pbaas/SaltedData.js +++ b/dist/pbaas/SaltedData.js @@ -40,7 +40,7 @@ class SaltedData extends index_1.VDXFData { } getByteLength() { let byteLength = 0; - byteLength += 20; //key + byteLength += vdxf_1.HASH160_BYTE_LENGTH; // vdxfkey byteLength += varint_1.default.encodingLength(this.version); byteLength += varuint_1.default.encodingLength(this.data.length + this.salt.length); byteLength += this.data.length + this.salt.length; diff --git a/dist/pbaas/SaplingExtendedSpendingKey.d.ts b/dist/pbaas/SaplingExtendedSpendingKey.d.ts new file mode 100644 index 00000000..1e081f99 --- /dev/null +++ b/dist/pbaas/SaplingExtendedSpendingKey.d.ts @@ -0,0 +1,26 @@ +import { SerializableEntity } from '../utils/types/SerializableEntity'; +export declare class SaplingExtendedSpendingKey implements SerializableEntity { + depth: number; + parentFVKTag: Buffer; + childIndex: Buffer; + chainCode: Buffer; + ask: Buffer; + nsk: Buffer; + ovk: Buffer; + dk: Buffer; + constructor(data?: { + depth?: number; + parentFVKTag?: Buffer; + childIndex?: Buffer; + chainCode?: Buffer; + ask?: Buffer; + nsk?: Buffer; + ovk?: Buffer; + dk?: Buffer; + }); + getByteLength(): number; + toBuffer(): Buffer; + fromBuffer(buffer: Buffer, offset?: number): number; + static fromKeyString(key: string): SaplingExtendedSpendingKey; + toKeyString(testnet?: boolean): string; +} diff --git a/dist/pbaas/SaplingExtendedSpendingKey.js b/dist/pbaas/SaplingExtendedSpendingKey.js new file mode 100644 index 00000000..3790a4cf --- /dev/null +++ b/dist/pbaas/SaplingExtendedSpendingKey.js @@ -0,0 +1,65 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.SaplingExtendedSpendingKey = void 0; +const bufferutils_1 = require("../utils/bufferutils"); +const sapling_1 = require("../utils/sapling"); +const { BufferReader, BufferWriter } = bufferutils_1.default; +class SaplingExtendedSpendingKey { + constructor(data) { + var _a, _b, _c, _d, _e, _f, _g, _h; + if (data != null) { + this.depth = (_a = data.depth) !== null && _a !== void 0 ? _a : 0; + this.parentFVKTag = (_b = data.parentFVKTag) !== null && _b !== void 0 ? _b : Buffer.alloc(4); + this.childIndex = (_c = data.childIndex) !== null && _c !== void 0 ? _c : Buffer.alloc(4); + this.chainCode = (_d = data.chainCode) !== null && _d !== void 0 ? _d : Buffer.alloc(32); + this.ask = (_e = data.ask) !== null && _e !== void 0 ? _e : Buffer.alloc(32); + this.nsk = (_f = data.nsk) !== null && _f !== void 0 ? _f : Buffer.alloc(32); + this.ovk = (_g = data.ovk) !== null && _g !== void 0 ? _g : Buffer.alloc(32); + this.dk = (_h = data.dk) !== null && _h !== void 0 ? _h : Buffer.alloc(32); + } + } + getByteLength() { + return 1 + 4 + 4 + 32 + 32 + 32 + 32 + 32; // 169 bytes total + } + toBuffer() { + const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); + writer.writeUInt8(this.depth); + writer.writeSlice(this.parentFVKTag); + writer.writeSlice(this.childIndex); + writer.writeSlice(this.chainCode); + writer.writeSlice(this.ask); + writer.writeSlice(this.nsk); + writer.writeSlice(this.ovk); + writer.writeSlice(this.dk); + return writer.buffer; + } + fromBuffer(buffer, offset = 0) { + const reader = new BufferReader(buffer, offset); + this.depth = reader.readUInt8(); + this.parentFVKTag = reader.readSlice(4); + this.childIndex = reader.readSlice(4); + this.chainCode = reader.readSlice(32); + this.ask = reader.readSlice(32); + this.nsk = reader.readSlice(32); + this.ovk = reader.readSlice(32); + this.dk = reader.readSlice(32); + return reader.offset; + } + static fromKeyString(key) { + const decoded = (0, sapling_1.decodeSaplingExtendedSpendingKey)(key); + return new SaplingExtendedSpendingKey(decoded); + } + toKeyString(testnet = false) { + return (0, sapling_1.encodeSaplingExtendedSpendingKey)({ + depth: this.depth, + parentFVKTag: this.parentFVKTag, + childIndex: this.childIndex, + chainCode: this.chainCode, + ask: this.ask, + nsk: this.nsk, + ovk: this.ovk, + dk: this.dk + }, testnet); + } +} +exports.SaplingExtendedSpendingKey = SaplingExtendedSpendingKey; diff --git a/dist/pbaas/SaplingExtendedViewingKey.d.ts b/dist/pbaas/SaplingExtendedViewingKey.d.ts new file mode 100644 index 00000000..c834b5d7 --- /dev/null +++ b/dist/pbaas/SaplingExtendedViewingKey.d.ts @@ -0,0 +1,26 @@ +import { SerializableEntity } from '../utils/types/SerializableEntity'; +export declare class SaplingExtendedViewingKey implements SerializableEntity { + depth: number; + parentFVKTag: Buffer; + childIndex: Buffer; + chainCode: Buffer; + ak: Buffer; + nk: Buffer; + ovk: Buffer; + dk: Buffer; + constructor(data?: { + depth?: number; + parentFVKTag?: Buffer; + childIndex?: Buffer; + chainCode?: Buffer; + ak?: Buffer; + nk?: Buffer; + ovk?: Buffer; + dk?: Buffer; + }); + getByteLength(): number; + toBuffer(): Buffer; + fromBuffer(buffer: Buffer, offset?: number): number; + static fromKeyString(key: string): SaplingExtendedViewingKey; + toKeyString(testnet?: boolean): string; +} diff --git a/dist/pbaas/SaplingExtendedViewingKey.js b/dist/pbaas/SaplingExtendedViewingKey.js new file mode 100644 index 00000000..3e3efa77 --- /dev/null +++ b/dist/pbaas/SaplingExtendedViewingKey.js @@ -0,0 +1,65 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.SaplingExtendedViewingKey = void 0; +const bufferutils_1 = require("../utils/bufferutils"); +const sapling_1 = require("../utils/sapling"); +const { BufferReader, BufferWriter } = bufferutils_1.default; +class SaplingExtendedViewingKey { + constructor(data) { + var _a, _b, _c, _d, _e, _f, _g, _h; + if (data != null) { + this.depth = (_a = data.depth) !== null && _a !== void 0 ? _a : 0; + this.parentFVKTag = (_b = data.parentFVKTag) !== null && _b !== void 0 ? _b : Buffer.alloc(4); + this.childIndex = (_c = data.childIndex) !== null && _c !== void 0 ? _c : Buffer.alloc(4); + this.chainCode = (_d = data.chainCode) !== null && _d !== void 0 ? _d : Buffer.alloc(32); + this.ak = (_e = data.ak) !== null && _e !== void 0 ? _e : Buffer.alloc(32); + this.nk = (_f = data.nk) !== null && _f !== void 0 ? _f : Buffer.alloc(32); + this.ovk = (_g = data.ovk) !== null && _g !== void 0 ? _g : Buffer.alloc(32); + this.dk = (_h = data.dk) !== null && _h !== void 0 ? _h : Buffer.alloc(32); + } + } + getByteLength() { + return 1 + 4 + 4 + 32 + 32 + 32 + 32 + 32; // 169 bytes total + } + toBuffer() { + const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); + writer.writeUInt8(this.depth); + writer.writeSlice(this.parentFVKTag); + writer.writeSlice(this.childIndex); + writer.writeSlice(this.chainCode); + writer.writeSlice(this.ak); + writer.writeSlice(this.nk); + writer.writeSlice(this.ovk); + writer.writeSlice(this.dk); + return writer.buffer; + } + fromBuffer(buffer, offset = 0) { + const reader = new BufferReader(buffer, offset); + this.depth = reader.readUInt8(); + this.parentFVKTag = reader.readSlice(4); + this.childIndex = reader.readSlice(4); + this.chainCode = reader.readSlice(32); + this.ak = reader.readSlice(32); + this.nk = reader.readSlice(32); + this.ovk = reader.readSlice(32); + this.dk = reader.readSlice(32); + return reader.offset; + } + static fromKeyString(key) { + const decoded = (0, sapling_1.decodeSaplingExtendedViewingKey)(key); + return new SaplingExtendedViewingKey(decoded); + } + toKeyString(testnet = false) { + return (0, sapling_1.encodeSaplingExtendedViewingKey)({ + depth: this.depth, + parentFVKTag: this.parentFVKTag, + childIndex: this.childIndex, + chainCode: this.chainCode, + ak: this.ak, + nk: this.nk, + ovk: this.ovk, + dk: this.dk + }, testnet); + } +} +exports.SaplingExtendedViewingKey = SaplingExtendedViewingKey; diff --git a/dist/pbaas/SignatureData.d.ts b/dist/pbaas/SignatureData.d.ts index d6439d58..3bbd7ece 100644 --- a/dist/pbaas/SignatureData.d.ts +++ b/dist/pbaas/SignatureData.d.ts @@ -1,5 +1,6 @@ import { BigNumber } from '../utils/types/BigNumber'; import { SerializableEntity } from '../utils/types/SerializableEntity'; +import { EHashTypes } from './DataDescriptor'; export interface SignatureJsonDataInterface { version: number; systemid: string; @@ -55,7 +56,7 @@ export declare class SignatureData implements SerializableEntity { * introduces a new hash type. For all other versions, the default hash type * is `EHashTypes.HASH_SHA256`. */ - static getSignatureHashType(input: Buffer): number; + static getSignatureHashType(input: Buffer): number | EHashTypes.HASH_SHA256; getByteLength(): number; toBuffer(): Buffer; fromBuffer(buffer: Buffer, offset?: number): number; @@ -65,5 +66,5 @@ export declare class SignatureData implements SerializableEntity { version: number; hash_type: number; height: number; - }): any; + }): Buffer; } diff --git a/dist/pbaas/SignatureData.js b/dist/pbaas/SignatureData.js index 3b711564..5574cf65 100644 --- a/dist/pbaas/SignatureData.js +++ b/dist/pbaas/SignatureData.js @@ -73,11 +73,11 @@ class SignatureData { getByteLength() { let byteLength = 0; byteLength += varint_1.default.encodingLength(this.version); - byteLength += 20; // system_ID uint160 + byteLength += vdxf_1.HASH160_BYTE_LENGTH; // system_ID uint160 byteLength += varint_1.default.encodingLength(this.hash_type); byteLength += varuint_1.default.encodingLength(this.signature_hash.length); byteLength += this.signature_hash.length; - byteLength += 20; // identity_ID uint160 + byteLength += vdxf_1.HASH160_BYTE_LENGTH; // identity_ID uint160 byteLength += varint_1.default.encodingLength(this.sig_type); byteLength += varuint_1.default.encodingLength(this.vdxf_keys.length); byteLength += this.vdxf_keys.length * 20; @@ -173,6 +173,7 @@ class SignatureData { } return returnObj; } + // To fully implement, refer to VerusCoin/src/pbaas/crosschainrpc.cpp line 337, IdentitySignatureHash getIdentityHash(sigObject) { var heightBuffer = Buffer.allocUnsafe(4); heightBuffer.writeUInt32LE(sigObject.height); diff --git a/dist/pbaas/URLRef.js b/dist/pbaas/URLRef.js index b554b34a..8b4d5723 100644 --- a/dist/pbaas/URLRef.js +++ b/dist/pbaas/URLRef.js @@ -5,6 +5,7 @@ const varint_1 = require("../utils/varint"); const varuint_1 = require("../utils/varuint"); const bufferutils_1 = require("../utils/bufferutils"); const bn_js_1 = require("bn.js"); +const vdxf_1 = require("../constants/vdxf"); const { BufferReader, BufferWriter } = bufferutils_1.default; class URLRef { constructor(data) { @@ -24,7 +25,7 @@ class URLRef { byteLength += varint_1.default.encodingLength(this.flags); if (this.flags.and(URLRef.FLAG_HAS_HASH).eq(URLRef.FLAG_HAS_HASH)) { // If the FLAG_HAS_HASH is set, we include the data hash - byteLength += 32; // 32 bytes for the hash + byteLength += vdxf_1.HASH256_BYTE_LENGTH; // 32 bytes for the hash } } byteLength += varuint_1.default.encodingLength(Buffer.from(this.url, 'utf8').length); diff --git a/dist/pbaas/UTXORef.js b/dist/pbaas/UTXORef.js index 45799a5c..88e3b585 100644 --- a/dist/pbaas/UTXORef.js +++ b/dist/pbaas/UTXORef.js @@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.UTXORef = void 0; const bufferutils_1 = require("../utils/bufferutils"); const bn_js_1 = require("bn.js"); +const vdxf_1 = require("../constants/vdxf"); const { BufferReader, BufferWriter } = bufferutils_1.default; class UTXORef { constructor(data) { @@ -11,7 +12,7 @@ class UTXORef { } getByteLength() { let byteLength = 0; - byteLength += 32; // hash uint256 + byteLength += vdxf_1.HASH256_BYTE_LENGTH; // hash uint256 byteLength += 4; // n uint32 return byteLength; } diff --git a/dist/utils/address.d.ts b/dist/utils/address.d.ts index c8982881..be5e8cfc 100644 --- a/dist/utils/address.d.ts +++ b/dist/utils/address.d.ts @@ -3,9 +3,12 @@ export declare const fromBase58Check: (address: string) => { hash: Buffer; }; export declare const toBase58Check: (hash: Buffer, version: number) => string; +export declare const nameAndParentAddrToAddr: (name: string, parentIAddr?: string, version?: number) => string; export declare const nameAndParentAddrToIAddr: (name: string, parentIAddr?: string) => string; +export declare const fqnToAddress: (fullyqualifiedname: string, rootSystemName?: string, version?: number) => string; export declare const toIAddress: (fullyqualifiedname: string, rootSystemName?: string) => string; -export declare function getDataKey(keyName: string, nameSpaceID?: string, verusChainId?: string): { +export declare const toXAddress: (fullyqualifiedname: string, rootSystemName?: string) => string; +export declare function getDataKey(keyName: string, nameSpaceID?: string, verusChainId?: string, version?: number): { id: string; namespace: string; }; diff --git a/dist/utils/address.js b/dist/utils/address.js index 315f980e..2b72e536 100644 --- a/dist/utils/address.js +++ b/dist/utils/address.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.decodeEthDestination = exports.decodeDestination = exports.toIAddress = exports.nameAndParentAddrToIAddr = exports.toBase58Check = exports.fromBase58Check = void 0; +exports.decodeEthDestination = exports.decodeDestination = exports.toXAddress = exports.toIAddress = exports.fqnToAddress = exports.nameAndParentAddrToIAddr = exports.nameAndParentAddrToAddr = exports.toBase58Check = exports.fromBase58Check = void 0; exports.getDataKey = getDataKey; const pbaas_1 = require("../constants/pbaas"); const vdxf_1 = require("../constants/vdxf"); @@ -37,7 +37,7 @@ const toBase58Check = (hash, version) => { return bs58check.encode(payload); }; exports.toBase58Check = toBase58Check; -const nameAndParentAddrToIAddr = (name, parentIAddr) => { +const nameAndParentAddrToAddr = (name, parentIAddr, version = vdxf_1.I_ADDR_VERSION) => { let idHash; const nameBuffer = Buffer.from((0, tolower_1.toLowerCaseCLocale)(name), "utf8"); if (parentIAddr == null) { @@ -47,10 +47,14 @@ const nameAndParentAddrToIAddr = (name, parentIAddr) => { idHash = (0, hash_1.hash)(nameBuffer); idHash = (0, hash_1.hash)((0, exports.fromBase58Check)(parentIAddr).hash, idHash); } - return (0, exports.toBase58Check)((0, hash_1.hash160)(idHash), 102); + return (0, exports.toBase58Check)((0, hash_1.hash160)(idHash), version); +}; +exports.nameAndParentAddrToAddr = nameAndParentAddrToAddr; +const nameAndParentAddrToIAddr = (name, parentIAddr) => { + return (0, exports.nameAndParentAddrToAddr)(name, parentIAddr, vdxf_1.I_ADDR_VERSION); }; exports.nameAndParentAddrToIAddr = nameAndParentAddrToIAddr; -const toIAddress = (fullyqualifiedname, rootSystemName = "") => { +const fqnToAddress = (fullyqualifiedname, rootSystemName = "", version = vdxf_1.I_ADDR_VERSION) => { const splitFqnAt = fullyqualifiedname.split("@").filter(x => x.length > 0); if (splitFqnAt.length !== 1) throw new Error("Invalid name"); @@ -85,9 +89,17 @@ const toIAddress = (fullyqualifiedname, rootSystemName = "") => { idHash = (0, hash_1.hash)(nameBuffer); idHash = (0, hash_1.hash)(Parent, idHash); } - return (0, exports.toBase58Check)((0, hash_1.hash160)(idHash), 102); + return (0, exports.toBase58Check)((0, hash_1.hash160)(idHash), version); +}; +exports.fqnToAddress = fqnToAddress; +const toIAddress = (fullyqualifiedname, rootSystemName = "") => { + return (0, exports.fqnToAddress)(fullyqualifiedname, rootSystemName, vdxf_1.I_ADDR_VERSION); }; exports.toIAddress = toIAddress; +const toXAddress = (fullyqualifiedname, rootSystemName = "") => { + return (0, exports.fqnToAddress)(fullyqualifiedname, rootSystemName, vdxf_1.X_ADDR_VERSION); +}; +exports.toXAddress = toXAddress; function trimSpaces(name, removeDuals) { // Unicode "dual spaces" — visually space-like but potentially problematic const dualSpaces = [ @@ -216,13 +228,13 @@ function cleanName(name, parent, removeDuals = false, verusChainName = pbaas_1.D } return { name: subNames[0], parent: newParent ? (0, exports.toBase58Check)(newParent, vdxf_1.I_ADDR_VERSION) : null }; } -function getID(name, parent, verusChainName = pbaas_1.DEFAULT_VERUS_CHAINNAME) { +function getID(name, parent, verusChainName = pbaas_1.DEFAULT_VERUS_CHAINNAME, version = vdxf_1.I_ADDR_VERSION) { const _cleanName = name === "::" ? { name, parent } : cleanName(name, parent, false, verusChainName); if (_cleanName.name.length == 0) return pbaas_1.NULL_I_ADDR; - return (0, exports.nameAndParentAddrToIAddr)(_cleanName.name, _cleanName.parent); + return (0, exports.nameAndParentAddrToAddr)(_cleanName.name, _cleanName.parent, version); } -function getDataKey(keyName, nameSpaceID, verusChainId = pbaas_1.DEFAULT_VERUS_CHAINID) { +function getDataKey(keyName, nameSpaceID, verusChainId = pbaas_1.DEFAULT_VERUS_CHAINID, version = vdxf_1.I_ADDR_VERSION) { let keyCopy = keyName; const addressParts = keyName.split(":"); // If the first part of the address is a namespace, it is followed by a double colon @@ -237,8 +249,8 @@ function getDataKey(keyName, nameSpaceID, verusChainId = pbaas_1.DEFAULT_VERUS_C if (!nameSpaceID) { nameSpaceID = verusChainId; } - const parent = getID("::", nameSpaceID); - return { id: getID(keyCopy, parent), namespace: nameSpaceID }; + const parent = getID("::", nameSpaceID, undefined, version); + return { id: getID(keyCopy, parent, undefined, version), namespace: nameSpaceID }; } const decodeDestination = (destination) => { try { diff --git a/dist/utils/sapling.d.ts b/dist/utils/sapling.d.ts index 7c365cba..bb4fd722 100644 --- a/dist/utils/sapling.d.ts +++ b/dist/utils/sapling.d.ts @@ -13,3 +13,27 @@ export declare const encodeSaplingAddress: (data: { d: Buffer; pk_d: Buffer; }) => string; +export interface SaplingExtendedSpendingKeyData { + depth: number; + parentFVKTag: Buffer; + childIndex: Buffer; + chainCode: Buffer; + ask: Buffer; + nsk: Buffer; + ovk: Buffer; + dk: Buffer; +} +export interface SaplingExtendedViewingKeyData { + depth: number; + parentFVKTag: Buffer; + childIndex: Buffer; + chainCode: Buffer; + ak: Buffer; + nk: Buffer; + ovk: Buffer; + dk: Buffer; +} +export declare function decodeSaplingExtendedSpendingKey(encoded: string): SaplingExtendedSpendingKeyData; +export declare function encodeSaplingExtendedSpendingKey(data: SaplingExtendedSpendingKeyData, testnet?: boolean): string; +export declare function decodeSaplingExtendedViewingKey(encoded: string): SaplingExtendedViewingKeyData; +export declare function encodeSaplingExtendedViewingKey(data: SaplingExtendedViewingKeyData, testnet?: boolean): string; diff --git a/dist/utils/sapling.js b/dist/utils/sapling.js index 535e8928..2ef0e258 100644 --- a/dist/utils/sapling.js +++ b/dist/utils/sapling.js @@ -1,9 +1,13 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.encodeSaplingAddress = exports.decodeSaplingAddress = exports.convertBits = exports.toBech32 = exports.fromBech32 = void 0; +exports.decodeSaplingExtendedSpendingKey = decodeSaplingExtendedSpendingKey; +exports.encodeSaplingExtendedSpendingKey = encodeSaplingExtendedSpendingKey; +exports.decodeSaplingExtendedViewingKey = decodeSaplingExtendedViewingKey; +exports.encodeSaplingExtendedViewingKey = encodeSaplingExtendedViewingKey; const bech32_1 = require("bech32"); const fromBech32 = (address) => { - var result = bech32_1.bech32.decode(address); + var result = bech32_1.bech32.decode(address, 1000); // Allow longer strings like extended keys var data = bech32_1.bech32.fromWords(result.words); return { version: result.words[0], @@ -14,7 +18,7 @@ const fromBech32 = (address) => { exports.fromBech32 = fromBech32; const toBech32 = (prefix, data) => { const words = bech32_1.bech32.toWords(data); - var result = bech32_1.bech32.encode(prefix, words); + var result = bech32_1.bech32.encode(prefix, words, 1000); // Allow longer strings like extended keys return result; }; exports.toBech32 = toBech32; @@ -63,3 +67,75 @@ const encodeSaplingAddress = (data) => { return (0, exports.toBech32)('zs', buffer); }; exports.encodeSaplingAddress = encodeSaplingAddress; +function decodeSaplingExtendedSpendingKey(encoded) { + const result = (0, exports.fromBech32)(encoded); + // Verify prefix is for extended spending key + if (!result.prefix.startsWith('secret-extended-key-')) { + throw new Error('Invalid Sapling extended spending key prefix'); + } + // Data should be 169 bytes: 1 (depth) + 4 (parent) + 4 (child) + 32*4 (keys) + if (result.data.length !== 169) { + throw new Error(`Invalid Sapling extended spending key length: expected 169, got ${result.data.length}`); + } + let offset = 0; + return { + depth: result.data.readUInt8(offset++), + parentFVKTag: Buffer.from(result.data.subarray(offset, offset += 4)), + childIndex: Buffer.from(result.data.subarray(offset, offset += 4)), + chainCode: Buffer.from(result.data.subarray(offset, offset += 32)), + ask: Buffer.from(result.data.subarray(offset, offset += 32)), + nsk: Buffer.from(result.data.subarray(offset, offset += 32)), + ovk: Buffer.from(result.data.subarray(offset, offset += 32)), + dk: Buffer.from(result.data.subarray(offset, offset += 32)) + }; +} +function encodeSaplingExtendedSpendingKey(data, testnet = false) { + const prefix = testnet ? 'secret-extended-key-test' : 'secret-extended-key-main'; + const buffer = Buffer.concat([ + Buffer.from([data.depth]), + data.parentFVKTag, + data.childIndex, + data.chainCode, + data.ask, + data.nsk, + data.ovk, + data.dk + ]); + return (0, exports.toBech32)(prefix, buffer); +} +function decodeSaplingExtendedViewingKey(encoded) { + const result = (0, exports.fromBech32)(encoded); + // Verify prefix is for extended viewing key + if (!result.prefix.startsWith('zxview')) { + throw new Error('Invalid Sapling extended viewing key prefix'); + } + // Data should be 169 bytes: 1 (depth) + 4 (parent) + 4 (child) + 32*5 (keys) + if (result.data.length !== 169) { + throw new Error('Invalid Sapling extended viewing key length'); + } + let offset = 0; + return { + depth: result.data.readUInt8(offset++), + parentFVKTag: Buffer.from(result.data.subarray(offset, offset += 4)), + childIndex: Buffer.from(result.data.subarray(offset, offset += 4)), + chainCode: Buffer.from(result.data.subarray(offset, offset += 32)), + ak: Buffer.from(result.data.subarray(offset, offset += 32)), + nk: Buffer.from(result.data.subarray(offset, offset += 32)), + ovk: Buffer.from(result.data.subarray(offset, offset += 32)), + dk: Buffer.from(result.data.subarray(offset, offset += 32)) + }; +} +function encodeSaplingExtendedViewingKey(data, testnet = false) { + const prefix = testnet ? 'zxviewtestsapling' : 'zxviews'; + const buffer = Buffer.concat([ + Buffer.from([data.depth]), + data.parentFVKTag, + data.childIndex, + data.chainCode, + data.ak, + data.nk, + data.ovk, + data.dk + ]); + return (0, exports.toBech32)(prefix, buffer); +} diff --git a/dist/utils/types/SerializableEntity.d.ts b/dist/utils/types/SerializableEntity.d.ts index f9ec16a5..e68f8d9a 100644 --- a/dist/utils/types/SerializableEntity.d.ts +++ b/dist/utils/types/SerializableEntity.d.ts @@ -3,3 +3,8 @@ export interface SerializableEntity { fromBuffer(buffer: Buffer, offset?: number): number; getByteLength(): number; } +export interface SerializableDataEntity { + getDataByteLength(): number; + toDataBuffer(): Buffer; + fromDataBuffer(buffer: Buffer): void; +} diff --git a/dist/vdxf/classes/CompactAddressObject.d.ts b/dist/vdxf/classes/CompactAddressObject.d.ts new file mode 100644 index 00000000..afd22bf9 --- /dev/null +++ b/dist/vdxf/classes/CompactAddressObject.d.ts @@ -0,0 +1,69 @@ +/** + * CompactIdentityObject - Class representing an id in the smallest possible format + * + * This class is used to represent an identity or address in a compact format, allowing for efficient + * storage and transmission. The compact id can be represented either as a fully qualified name (FQN) + * or as an identity address (iaddress) or as an x address (tag/index). The class includes methods for serialization, deserialization, + * and validation of the compact id object. + */ +import { BigNumber } from '../../utils/types/BigNumber'; +import { SerializableEntity } from '../../utils/types/SerializableEntity'; +export interface CompactAddressObjectJson { + version: number; + type: number; + address: string; + rootsystemname: string; + namespace?: string; +} +export interface CompactAddressObjectInterface { + version?: BigNumber; + type: BigNumber; + address: string; + rootSystemName?: string; + nameSpace?: string; +} +export type CompactAddressIVariant = "COMPACT_ADDR_I_VARIANT"; +export type CompactAddressXVariant = "COMPACT_ADDR_X_VARIANT"; +export type CompactAddressVariantName = CompactAddressIVariant | CompactAddressXVariant; +export type CompactAddressVariantAllowedType = T extends CompactAddressIVariant ? `${1 | 2}` : T extends CompactAddressXVariant ? `${1 | 3}` : never; +export declare class CompactAddressObject implements SerializableEntity { + static VERSION_INVALID: import("bn.js"); + static FIRST_VERSION: import("bn.js"); + static LAST_VERSION: import("bn.js"); + static DEFAULT_VERSION: import("bn.js"); + static TYPE_FQN: import("bn.js"); + static TYPE_I_ADDRESS: import("bn.js"); + static TYPE_X_ADDRESS: import("bn.js"); + version: BigNumber; + type: CompactAddressVariantAllowedType; + address: string; + rootSystemName: string; + nameSpace: string; + constructor(data?: CompactAddressObjectInterface); + get BNType(): import("bn.js"); + set setType(type: BigNumber); + isFQN(): boolean; + isIaddress(): boolean; + isXaddress(): boolean; + isValid(): boolean; + toIAddress(): string; + toXAddress(): string; + toString(): string; + static fromIAddress(iaddr: string): CompactAddressObject; + static fromXAddress(xaddr: string, nameSpace?: string): CompactAddressObject; + getByteLength(): number; + toBuffer(): Buffer; + fromBuffer(buffer: Buffer, offset?: number): number; + toJson(): CompactAddressObjectJson; + static fromJson(json: any): CompactAddressObject; +} +export declare class CompactXAddressObject extends CompactAddressObject { + static fromAddress(xaddr: string, nameSpace?: string): CompactXAddressObject; + toAddress(): string; + static fromCompactAddressObjectJson(json: any): CompactXAddressObject; +} +export declare class CompactIAddressObject extends CompactAddressObject { + static fromAddress(iaddr: string, nameSpace?: string): CompactIAddressObject; + toAddress(): string; + static fromCompactAddressObjectJson(json: any): CompactIAddressObject; +} diff --git a/dist/vdxf/classes/CompactAddressObject.js b/dist/vdxf/classes/CompactAddressObject.js new file mode 100644 index 00000000..7af899c7 --- /dev/null +++ b/dist/vdxf/classes/CompactAddressObject.js @@ -0,0 +1,197 @@ +"use strict"; +/** + * CompactIdentityObject - Class representing an id in the smallest possible format + * + * This class is used to represent an identity or address in a compact format, allowing for efficient + * storage and transmission. The compact id can be represented either as a fully qualified name (FQN) + * or as an identity address (iaddress) or as an x address (tag/index). The class includes methods for serialization, deserialization, + * and validation of the compact id object. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.CompactIAddressObject = exports.CompactXAddressObject = exports.CompactAddressObject = void 0; +const bn_js_1 = require("bn.js"); +const bufferutils_1 = require("../../utils/bufferutils"); +const { BufferReader, BufferWriter } = bufferutils_1.default; +const varuint_1 = require("../../utils/varuint"); +const address_1 = require("../../utils/address"); +const vdxf_1 = require("../../constants/vdxf"); +const pbaas_1 = require("../../constants/pbaas"); +class CompactAddressObject { + constructor(data) { + this.version = (data === null || data === void 0 ? void 0 : data.version) || new bn_js_1.BN(CompactAddressObject.DEFAULT_VERSION); + this.type = (data === null || data === void 0 ? void 0 : data.type.toString()) || "1"; + this.address = (data === null || data === void 0 ? void 0 : data.address) || ''; + this.rootSystemName = (data === null || data === void 0 ? void 0 : data.rootSystemName) || 'VRSC'; + this.nameSpace = (data === null || data === void 0 ? void 0 : data.nameSpace) || (0, address_1.toIAddress)(this.rootSystemName); + } + get BNType() { + return new bn_js_1.BN(this.type); + } + set setType(type) { + this.type = type.toString(); + } + isFQN() { + return (this.BNType.eq(CompactAddressObject.TYPE_FQN)); + } + isIaddress() { + return (this.BNType.eq(CompactAddressObject.TYPE_I_ADDRESS)); + } + isXaddress() { + return (this.BNType.eq(CompactAddressObject.TYPE_X_ADDRESS)); + } + isValid() { + return this.address != null; + } + toIAddress() { + if (this.isXaddress()) + throw new Error("Cannot convert I to X address"); + else if (this.isIaddress()) + return this.address; + else if (this.isFQN()) { + if (this.address.includes("::")) { + return (0, address_1.getDataKey)(this.address, this.nameSpace, (0, address_1.toIAddress)(this.rootSystemName), vdxf_1.I_ADDR_VERSION).id; + } + else { + return (0, address_1.toIAddress)(this.address, this.rootSystemName); + } + } + else + throw new Error("Unknown type"); + } + toXAddress() { + if (this.isIaddress()) + throw new Error("Cannot convert X to I address"); + else if (this.isXaddress()) + return this.address; + else if (this.isFQN()) { + if (this.address.includes("::")) { + return (0, address_1.getDataKey)(this.address, this.nameSpace, (0, address_1.toIAddress)(this.rootSystemName), vdxf_1.X_ADDR_VERSION).id; + } + else { + return (0, address_1.toXAddress)(this.address, this.rootSystemName); + } + } + else + throw new Error("Unknown type"); + } + toString() { + if (this.isIaddress()) { + return this.toIAddress(); + } + else if (this.isXaddress()) { + return this.toXAddress(); + } + else + return this.address; + } + static fromIAddress(iaddr) { + return new CompactAddressObject({ + address: iaddr, + type: CompactAddressObject.TYPE_I_ADDRESS + }); + } + static fromXAddress(xaddr, nameSpace = pbaas_1.DEFAULT_VERUS_CHAINID) { + return new CompactAddressObject({ + address: xaddr, + nameSpace: nameSpace, + type: CompactAddressObject.TYPE_X_ADDRESS + }); + } + getByteLength() { + let length = 0; + length += varuint_1.default.encodingLength(this.version.toNumber()); + length += varuint_1.default.encodingLength(this.BNType.toNumber()); + if (this.isIaddress() || this.isXaddress()) { + length += vdxf_1.HASH160_BYTE_LENGTH; // identityuint160 + } + else { + const addrLen = Buffer.from(this.address, 'utf8').byteLength; + length += varuint_1.default.encodingLength(addrLen) + addrLen; + } + return length; + } + toBuffer() { + const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); + writer.writeCompactSize(this.version.toNumber()); + writer.writeCompactSize(this.BNType.toNumber()); + if (this.isIaddress() || this.isXaddress()) { + writer.writeSlice((0, address_1.fromBase58Check)(this.address).hash); + } + else { + writer.writeVarSlice(Buffer.from(this.address, 'utf8')); + } + return writer.buffer; + } + fromBuffer(buffer, offset) { + const reader = new BufferReader(buffer, offset); + this.version = new bn_js_1.BN(reader.readCompactSize()); + this.type = new bn_js_1.BN(reader.readCompactSize()).toString(); + if (this.isIaddress() || this.isXaddress()) { + this.address = (0, address_1.toBase58Check)(reader.readSlice(20), this.isIaddress() ? vdxf_1.I_ADDR_VERSION : vdxf_1.X_ADDR_VERSION); + } + else { + this.address = reader.readVarSlice().toString('utf8'); + } + return reader.offset; + } + toJson() { + return { + version: this.version.toNumber(), + type: this.BNType.toNumber(), + address: this.address, + rootsystemname: this.rootSystemName, + }; + } + static fromJson(json) { + const instance = new CompactAddressObject(); + instance.version = new bn_js_1.BN(json.version); + instance.type = new bn_js_1.BN(json.type).toString(); + instance.address = json.address; + instance.rootSystemName = json.rootsystemname; + return instance; + } +} +exports.CompactAddressObject = CompactAddressObject; +CompactAddressObject.VERSION_INVALID = new bn_js_1.BN(0); +CompactAddressObject.FIRST_VERSION = new bn_js_1.BN(1); +CompactAddressObject.LAST_VERSION = new bn_js_1.BN(1); +CompactAddressObject.DEFAULT_VERSION = new bn_js_1.BN(1); +CompactAddressObject.TYPE_FQN = new bn_js_1.BN(1); +CompactAddressObject.TYPE_I_ADDRESS = new bn_js_1.BN(2); +CompactAddressObject.TYPE_X_ADDRESS = new bn_js_1.BN(3); +class CompactXAddressObject extends CompactAddressObject { + static fromAddress(xaddr, nameSpace = pbaas_1.DEFAULT_VERUS_CHAINID) { + return new CompactXAddressObject({ + address: xaddr, + nameSpace: nameSpace, + type: CompactAddressObject.TYPE_X_ADDRESS + }); + } + toAddress() { + return this.toXAddress(); + } + static fromCompactAddressObjectJson(json) { + const inst = CompactAddressObject.fromJson(json); + return inst; + } +} +exports.CompactXAddressObject = CompactXAddressObject; +; +class CompactIAddressObject extends CompactAddressObject { + static fromAddress(iaddr, nameSpace = pbaas_1.DEFAULT_VERUS_CHAINID) { + return new CompactIAddressObject({ + address: iaddr, + nameSpace: nameSpace, + type: CompactAddressObject.TYPE_I_ADDRESS + }); + } + toAddress() { + return this.toIAddress(); + } + static fromCompactAddressObjectJson(json) { + const inst = CompactAddressObject.fromJson(json); + return inst; + } +} +exports.CompactIAddressObject = CompactIAddressObject; +; diff --git a/dist/vdxf/classes/ResponseUri.d.ts b/dist/vdxf/classes/ResponseURI.d.ts similarity index 76% rename from dist/vdxf/classes/ResponseUri.d.ts rename to dist/vdxf/classes/ResponseURI.d.ts index 3997ddfe..0ba995f8 100644 --- a/dist/vdxf/classes/ResponseUri.d.ts +++ b/dist/vdxf/classes/ResponseURI.d.ts @@ -1,10 +1,10 @@ import { BigNumber } from "../../utils/types/BigNumber"; import { SerializableEntity } from "../../utils/types/SerializableEntity"; -export type ResponseUriJson = { +export type ResponseURIJson = { type: string; uri: string; }; -export declare class ResponseUri implements SerializableEntity { +export declare class ResponseURI implements SerializableEntity { uri: Buffer; type: BigNumber; static TYPE_INVALID: import("bn.js"); @@ -15,10 +15,10 @@ export declare class ResponseUri implements SerializableEntity { type?: BigNumber; }); getUriString(): string; - static fromUriString(str: string, type?: BigNumber): ResponseUri; + static fromUriString(str: string, type?: BigNumber): ResponseURI; getByteLength(): number; toBuffer(): Buffer; fromBuffer(buffer: Buffer, offset?: number): number; - toJson(): ResponseUriJson; - static fromJson(json: ResponseUriJson): ResponseUri; + toJson(): ResponseURIJson; + static fromJson(json: ResponseURIJson): ResponseURI; } diff --git a/dist/vdxf/classes/ResponseUri.js b/dist/vdxf/classes/ResponseURI.js similarity index 66% rename from dist/vdxf/classes/ResponseUri.js rename to dist/vdxf/classes/ResponseURI.js index 05c63ad4..16810a0e 100644 --- a/dist/vdxf/classes/ResponseUri.js +++ b/dist/vdxf/classes/ResponseURI.js @@ -1,11 +1,12 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.ResponseUri = void 0; +exports.ResponseURI = void 0; const bn_js_1 = require("bn.js"); -const varint_1 = require("../../utils/varint"); const varuint_1 = require("../../utils/varuint"); const bufferutils_1 = require("../../utils/bufferutils"); -class ResponseUri { +class ResponseURI { + // TODO: Add TYPE_Z_ADDR_REF where response is encrypted and sent to encoded sapling address, + // with optional amount specified constructor(data) { if (data) { if (data.uri != null) { @@ -19,12 +20,12 @@ class ResponseUri { getUriString() { return this.uri.toString('utf-8'); } - static fromUriString(str, type = ResponseUri.TYPE_REDIRECT) { - return new ResponseUri({ uri: Buffer.from(str, 'utf-8'), type }); + static fromUriString(str, type = ResponseURI.TYPE_REDIRECT) { + return new ResponseURI({ uri: Buffer.from(str, 'utf-8'), type }); } getByteLength() { let length = 0; - length += varint_1.default.encodingLength(this.type); + length += varuint_1.default.encodingLength(this.type.toNumber()); let uriBufLen = this.uri.length; length += varuint_1.default.encodingLength(uriBufLen); length += uriBufLen; @@ -32,13 +33,13 @@ class ResponseUri { } toBuffer() { const writer = new bufferutils_1.default.BufferWriter(Buffer.alloc(this.getByteLength())); - writer.writeVarInt(this.type); + writer.writeCompactSize(this.type.toNumber()); writer.writeVarSlice(this.uri); return writer.buffer; } fromBuffer(buffer, offset) { const reader = new bufferutils_1.default.BufferReader(buffer, offset); - this.type = reader.readVarInt(); + this.type = new bn_js_1.BN(reader.readCompactSize()); this.uri = reader.readVarSlice(); return reader.offset; } @@ -49,13 +50,13 @@ class ResponseUri { }; } static fromJson(json) { - return new ResponseUri({ + return new ResponseURI({ type: new bn_js_1.BN(json.type, 10), uri: Buffer.from(json.uri, 'utf-8') }); } } -exports.ResponseUri = ResponseUri; -ResponseUri.TYPE_INVALID = new bn_js_1.BN(0, 10); -ResponseUri.TYPE_REDIRECT = new bn_js_1.BN(1, 10); -ResponseUri.TYPE_POST = new bn_js_1.BN(2, 10); +exports.ResponseURI = ResponseURI; +ResponseURI.TYPE_INVALID = new bn_js_1.BN(0, 10); +ResponseURI.TYPE_REDIRECT = new bn_js_1.BN(1, 10); +ResponseURI.TYPE_POST = new bn_js_1.BN(2, 10); diff --git a/dist/vdxf/classes/SaltedData.js b/dist/vdxf/classes/SaltedData.js index 7a2d015d..3c08d231 100644 --- a/dist/vdxf/classes/SaltedData.js +++ b/dist/vdxf/classes/SaltedData.js @@ -39,7 +39,7 @@ class SaltedData extends __1.VDXFData { } getByteLength() { let byteLength = 0; - byteLength += 20; //key + byteLength += vdxf_1.HASH160_BYTE_LENGTH; byteLength += varint_1.default.encodingLength(this.version); byteLength += varuint_1.default.encodingLength(this.data.length + this.salt.length); byteLength += this.data.length + this.salt.length; diff --git a/dist/vdxf/classes/VerifiableSignatureData.d.ts b/dist/vdxf/classes/VerifiableSignatureData.d.ts new file mode 100644 index 00000000..8a8520fa --- /dev/null +++ b/dist/vdxf/classes/VerifiableSignatureData.d.ts @@ -0,0 +1,92 @@ +import { BigNumber } from '../../utils/types/BigNumber'; +import { SerializableEntity } from '../../utils/types/SerializableEntity'; +import { CompactIAddressObject, CompactAddressObjectJson } from './CompactAddressObject'; +import { SignatureData, SignatureJsonDataInterface } from '../../pbaas'; +export interface VerifiableSignatureDataJson { + version: number; + flags: number; + signatureversion: number; + hashtype: number; + systemid: CompactAddressObjectJson; + identityid: CompactAddressObjectJson; + vdxfkeys?: Array; + vdxfkeynames?: Array; + boundhashes?: Array; + statements?: Array; + signature: string; +} +export interface VerifiableSignatureDataInterface { + version?: BigNumber; + flags?: BigNumber; + signatureVersion?: BigNumber; + hashType?: BigNumber; + systemID?: CompactIAddressObject; + identityID: CompactIAddressObject; + vdxfKeys?: Array; + vdxfKeyNames?: Array; + boundHashes?: Array; + statements?: Array; + signatureAsVch?: Buffer; +} +export interface CliSignatureData { + signaturedata: SignatureJsonDataInterface; + system: string; + systemid: string; + hashtype: string; + hash: string; + identity: string; + canonicalname: string; + address: string; + signatureheight: number; + signature: string; + signatureversion: number; + vdxfkeys?: Array; + vdxfkeynames?: Array; + boundhashes?: Array; +} +export declare class VerifiableSignatureData implements SerializableEntity { + version: BigNumber; + flags: BigNumber; + signatureVersion: BigNumber; + hashType: BigNumber; + identityID: CompactIAddressObject; + systemID: CompactIAddressObject; + vdxfKeys?: Array; + vdxfKeyNames?: Array; + boundHashes?: Array; + statements?: Array; + signatureAsVch: Buffer; + static VERSION_INVALID: import("bn.js"); + static FIRST_VERSION: import("bn.js"); + static LAST_VERSION: import("bn.js"); + static DEFAULT_VERSION: import("bn.js"); + static TYPE_VERUSID_DEFAULT: import("bn.js"); + static FLAG_HAS_VDXF_KEYS: import("bn.js"); + static FLAG_HAS_VDXF_KEY_NAMES: import("bn.js"); + static FLAG_HAS_BOUND_HASHES: import("bn.js"); + static FLAG_HAS_STATEMENTS: import("bn.js"); + constructor(data?: VerifiableSignatureDataInterface); + private hasFlag; + private setFlag; + hasVdxfKeys(): boolean; + hasVdxfKeyNames(): boolean; + hasBoundHashes(): boolean; + hasStatements(): boolean; + setHasVdxfKeys(): void; + setHasVdxfKeyNames(): void; + setHasBoundHashes(): void; + setHasStatements(): void; + calcFlags(): BigNumber; + setFlags(): void; + private getBufferEncodingLength; + private getExtraHashDataByteLength; + private getExtraHashData; + getByteLength(): number; + toBuffer(): Buffer; + fromBuffer(buffer: Buffer, offset?: number): number; + getIdentityHash(height: number, sigHash: Buffer): Buffer; + toSignatureData(sigHash: Buffer): SignatureData; + toJson(): VerifiableSignatureDataJson; + static fromJson(json: VerifiableSignatureDataJson): VerifiableSignatureData; + static fromCLIJson(json: CliSignatureData, rootSystemName?: string): VerifiableSignatureData; +} diff --git a/dist/vdxf/classes/VerifiableSignatureData.js b/dist/vdxf/classes/VerifiableSignatureData.js new file mode 100644 index 00000000..ac4086af --- /dev/null +++ b/dist/vdxf/classes/VerifiableSignatureData.js @@ -0,0 +1,324 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.VerifiableSignatureData = void 0; +const varuint_1 = require("../../utils/varuint"); +const address_1 = require("../../utils/address"); +const bufferutils_1 = require("../../utils/bufferutils"); +const bn_js_1 = require("bn.js"); +const vdxf_1 = require("../../constants/vdxf"); +const DataDescriptor_1 = require("../../pbaas/DataDescriptor"); +const { BufferReader, BufferWriter } = bufferutils_1.default; +const createHash = require("create-hash"); +const vdxf_2 = require("../../constants/vdxf"); +const CompactAddressObject_1 = require("./CompactAddressObject"); +const pbaas_1 = require("../../constants/pbaas"); +const varint_1 = require("../../utils/varint"); +const pbaas_2 = require("../../pbaas"); +class VerifiableSignatureData { + constructor(data) { + this.version = data && data.version ? data.version : new bn_js_1.BN(0); + this.flags = data && data.flags ? data.flags : new bn_js_1.BN(0); + this.signatureVersion = data && data.signatureVersion ? data.signatureVersion : new bn_js_1.BN(2, 10); + this.systemID = data && data.systemID ? data.systemID : new CompactAddressObject_1.CompactIAddressObject({ type: CompactAddressObject_1.CompactIAddressObject.TYPE_FQN, address: pbaas_1.DEFAULT_VERUS_CHAINNAME }); + this.hashType = data && data.hashType ? data.hashType : pbaas_1.HASH_TYPE_SHA256; + this.identityID = data ? data.identityID : undefined; + this.vdxfKeys = data ? data.vdxfKeys : undefined; + this.vdxfKeyNames = data ? data.vdxfKeyNames : undefined; + this.boundHashes = data ? data.boundHashes : undefined; + this.statements = data ? data.statements : undefined; + this.signatureAsVch = data && data.signatureAsVch ? data.signatureAsVch : Buffer.alloc(0); + this.setFlags(); + } + hasFlag(flag) { + return !!(this.flags.and(flag).toNumber()); + } + setFlag(flag) { + this.flags = this.flags.or(flag); + } + hasVdxfKeys() { + return this.hasFlag(VerifiableSignatureData.FLAG_HAS_VDXF_KEYS); + } + hasVdxfKeyNames() { + return this.hasFlag(VerifiableSignatureData.FLAG_HAS_VDXF_KEY_NAMES); + } + hasBoundHashes() { + return this.hasFlag(VerifiableSignatureData.FLAG_HAS_BOUND_HASHES); + } + hasStatements() { + return this.hasFlag(VerifiableSignatureData.FLAG_HAS_STATEMENTS); + } + setHasVdxfKeys() { + this.setFlag(VerifiableSignatureData.FLAG_HAS_VDXF_KEYS); + } + setHasVdxfKeyNames() { + this.setFlag(VerifiableSignatureData.FLAG_HAS_VDXF_KEY_NAMES); + } + setHasBoundHashes() { + this.setFlag(VerifiableSignatureData.FLAG_HAS_BOUND_HASHES); + } + setHasStatements() { + this.setFlag(VerifiableSignatureData.FLAG_HAS_STATEMENTS); + } + calcFlags() { + let flags = new bn_js_1.BN(0); + if (this.hasVdxfKeys()) + flags = flags.or(VerifiableSignatureData.FLAG_HAS_VDXF_KEYS); + if (this.hasVdxfKeyNames()) + flags = flags.or(VerifiableSignatureData.FLAG_HAS_VDXF_KEY_NAMES); + if (this.hasBoundHashes()) + flags = flags.or(VerifiableSignatureData.FLAG_HAS_BOUND_HASHES); + if (this.hasStatements()) + flags = flags.or(VerifiableSignatureData.FLAG_HAS_STATEMENTS); + return flags; + } + setFlags() { + if (this.vdxfKeys) + this.setHasVdxfKeys(); + if (this.vdxfKeyNames) + this.setHasVdxfKeyNames(); + if (this.boundHashes) + this.setHasBoundHashes(); + if (this.statements) + this.setHasStatements(); + } + getBufferEncodingLength(buf) { + const bufLen = buf.byteLength; + return varuint_1.default.encodingLength(bufLen) + bufLen; + } + getExtraHashDataByteLength() { + let byteLength = 0; + if (this.vdxfKeys && this.vdxfKeys.length > 0) { + byteLength += varuint_1.default.encodingLength(this.vdxfKeys.length); + byteLength += this.vdxfKeys.length * vdxf_1.HASH160_BYTE_LENGTH; + } + if (this.vdxfKeyNames && this.vdxfKeyNames.length > 0) { + byteLength += varuint_1.default.encodingLength(this.vdxfKeyNames.length); + for (const name of this.vdxfKeyNames) { + byteLength += this.getBufferEncodingLength(Buffer.from(name, 'utf8')); + } + } + if (this.boundHashes && this.boundHashes.length > 0) { + byteLength += varuint_1.default.encodingLength(this.boundHashes.length); + byteLength += this.boundHashes.length * vdxf_1.HASH256_BYTE_LENGTH; + } + return byteLength; + } + getExtraHashData() { + const byteLength = this.getExtraHashDataByteLength(); + if (byteLength === 0) { + return Buffer.alloc(0); + } + const bufferWriter = new BufferWriter(Buffer.alloc(byteLength)); + if (this.vdxfKeys && this.vdxfKeys.length > 0) { + // Sort vdxfKeys by their 20-byte buffer values before writing + const keyBuffers = this.vdxfKeys.map(x => (0, address_1.fromBase58Check)(x).hash); + const sortedBuffers = keyBuffers.sort(Buffer.compare); + bufferWriter.writeArray(sortedBuffers); + } + if (this.vdxfKeyNames && this.vdxfKeyNames.length > 0) { + // Sort vdxfKeyNames before writing + const sortedNames = [...this.vdxfKeyNames].sort(); + bufferWriter.writeVector(sortedNames.map(x => Buffer.from(x, 'utf8'))); + } + if (this.boundHashes && this.boundHashes.length > 0) { + // Sort boundHashes before writing + const sortedHashes = [...this.boundHashes].sort(Buffer.compare); + bufferWriter.writeArray(sortedHashes); + } + return bufferWriter.buffer; + } + getByteLength() { + let byteLength = 0; + byteLength += varint_1.default.encodingLength(this.version); + byteLength += varuint_1.default.encodingLength(this.flags.toNumber()); + byteLength += varuint_1.default.encodingLength(this.signatureVersion.toNumber()); + byteLength += varuint_1.default.encodingLength(this.hashType.toNumber()); + byteLength += this.systemID.getByteLength(); + byteLength += this.identityID.getByteLength(); + if (this.hasVdxfKeys()) { + byteLength += varuint_1.default.encodingLength(this.vdxfKeys.length); + for (const key of this.vdxfKeys) { + byteLength += vdxf_1.HASH160_BYTE_LENGTH; + } + } + if (this.hasVdxfKeyNames()) { + byteLength += varuint_1.default.encodingLength(this.vdxfKeyNames.length); + for (const key of this.vdxfKeyNames) { + byteLength += this.getBufferEncodingLength(Buffer.from(key, 'utf8')); + } + } + if (this.hasBoundHashes()) { + byteLength += varuint_1.default.encodingLength(this.boundHashes.length); + for (const hash of this.boundHashes) { + byteLength += this.getBufferEncodingLength(hash); + } + } + if (this.hasStatements()) { + byteLength += varuint_1.default.encodingLength(this.statements.length); + for (const statement of this.statements) { + byteLength += this.getBufferEncodingLength(statement); + } + } + byteLength += this.getBufferEncodingLength(this.signatureAsVch); + return byteLength; + } + toBuffer() { + const bufferWriter = new BufferWriter(Buffer.alloc(this.getByteLength())); + bufferWriter.writeVarInt(this.version); + bufferWriter.writeCompactSize(this.flags.toNumber()); + bufferWriter.writeCompactSize(this.signatureVersion.toNumber()); + bufferWriter.writeCompactSize(this.hashType.toNumber()); + bufferWriter.writeSlice(this.systemID.toBuffer()); + bufferWriter.writeSlice(this.identityID.toBuffer()); + if (this.hasVdxfKeys()) { + bufferWriter.writeArray(this.vdxfKeys.map(x => (0, address_1.fromBase58Check)(x).hash)); + } + if (this.hasVdxfKeyNames()) { + bufferWriter.writeVector(this.vdxfKeyNames.map(x => Buffer.from(x, 'utf8'))); + } + if (this.hasBoundHashes()) { + bufferWriter.writeVector(this.boundHashes); + } + if (this.hasStatements()) { + bufferWriter.writeVector(this.statements); + } + bufferWriter.writeVarSlice(this.signatureAsVch); + return bufferWriter.buffer; + } + fromBuffer(buffer, offset = 0) { + const bufferReader = new BufferReader(buffer, offset); + this.version = bufferReader.readVarInt(); + this.flags = new bn_js_1.BN(bufferReader.readCompactSize()); + this.signatureVersion = new bn_js_1.BN(bufferReader.readCompactSize()); + this.hashType = new bn_js_1.BN(bufferReader.readCompactSize()); + this.systemID = new CompactAddressObject_1.CompactIAddressObject(); + this.identityID = new CompactAddressObject_1.CompactIAddressObject(); + bufferReader.offset = this.systemID.fromBuffer(bufferReader.buffer, bufferReader.offset); + bufferReader.offset = this.identityID.fromBuffer(bufferReader.buffer, bufferReader.offset); + if (this.hasVdxfKeys()) { + this.vdxfKeys = bufferReader.readArray(vdxf_1.HASH160_BYTE_LENGTH).map(x => (0, address_1.toBase58Check)(x, vdxf_1.I_ADDR_VERSION)); + } + if (this.hasVdxfKeyNames()) { + this.vdxfKeyNames = bufferReader.readVector().map((x) => x.toString('utf8')); + } + if (this.hasBoundHashes()) { + this.boundHashes = bufferReader.readVector(); + } + if (this.hasStatements()) { + this.statements = bufferReader.readVector(); + } + this.signatureAsVch = bufferReader.readVarSlice(); + return bufferReader.offset; + } + // To fully implement, refer to VerusCoin/src/pbaas/crosschainrpc.cpp line 337, IdentitySignatureHash + getIdentityHash(height, sigHash) { + var heightBuffer = Buffer.allocUnsafe(4); + heightBuffer.writeUInt32LE(height); + if (!this.hashType.eq(new bn_js_1.BN(DataDescriptor_1.EHashTypes.HASH_SHA256))) { + throw new Error("Only SHA256 hash type is currently supported."); + } + if (this.signatureVersion.eq(new bn_js_1.BN(0))) { + throw new Error("Invalid sig data version"); + } + else if (this.signatureVersion.eq(new bn_js_1.BN(1))) { + return createHash("sha256") + .update(vdxf_2.VERUS_DATA_SIGNATURE_PREFIX) + .update((0, address_1.fromBase58Check)(this.systemID.toIAddress()).hash) + .update(heightBuffer) + .update((0, address_1.fromBase58Check)(this.identityID.toIAddress()).hash) + .update(sigHash) + .digest(); + } + else if (this.signatureVersion.eq(new bn_js_1.BN(2))) { + const extraHashData = this.getExtraHashData(); + const hash = createHash("sha256"); + if (extraHashData.length > 0) { + hash.update(extraHashData); + } + return hash + .update((0, address_1.fromBase58Check)(this.systemID.toIAddress()).hash) + .update(heightBuffer) + .update((0, address_1.fromBase58Check)(this.identityID.toIAddress()).hash) + .update(vdxf_2.VERUS_DATA_SIGNATURE_PREFIX) + .update(sigHash) + .digest(); + } + else { + throw new Error("Unrecognized sig data version"); + } + } + toSignatureData(sigHash) { + return new pbaas_2.SignatureData({ + version: this.version, + system_ID: this.systemID.toIAddress(), + hash_type: this.hashType, + signature_hash: sigHash, + identity_ID: this.identityID.toIAddress(), + sig_type: pbaas_2.SignatureData.TYPE_VERUSID_DEFAULT, + vdxf_keys: this.vdxfKeys, + vdxf_key_names: this.vdxfKeyNames, + bound_hashes: this.boundHashes, + signature_as_vch: this.signatureAsVch + }); + } + toJson() { + var _a, _b; + const flags = this.calcFlags(); + return { + version: this.version.toNumber(), + flags: flags.toNumber(), + signatureversion: this.signatureVersion.toNumber(), + hashtype: this.hashType.toNumber(), + systemid: this.systemID.toJson(), + identityid: this.identityID.toJson(), + vdxfkeys: this.vdxfKeys, + vdxfkeynames: this.vdxfKeyNames, + boundhashes: (_a = this.boundHashes) === null || _a === void 0 ? void 0 : _a.map(x => x.toString('hex')), + statements: (_b = this.statements) === null || _b === void 0 ? void 0 : _b.map(x => x.toString('hex')), + signature: this.signatureAsVch.toString('hex') + }; + } + static fromJson(json) { + var _a, _b; + const instance = new VerifiableSignatureData(); + instance.version = new bn_js_1.BN(json.version); + instance.flags = new bn_js_1.BN(json.flags); + instance.signatureVersion = new bn_js_1.BN(json.signatureversion); + instance.hashType = new bn_js_1.BN(json.hashtype); + instance.systemID = CompactAddressObject_1.CompactIAddressObject.fromCompactAddressObjectJson(json.systemid); + instance.identityID = CompactAddressObject_1.CompactIAddressObject.fromCompactAddressObjectJson(json.identityid); + instance.vdxfKeys = json === null || json === void 0 ? void 0 : json.vdxfkeys; + instance.vdxfKeyNames = json === null || json === void 0 ? void 0 : json.vdxfkeynames; + instance.boundHashes = (_a = json.boundhashes) === null || _a === void 0 ? void 0 : _a.map(x => Buffer.from(x, 'hex')); + instance.statements = (_b = json.statements) === null || _b === void 0 ? void 0 : _b.map(x => Buffer.from(x, 'hex')); + instance.signatureAsVch = Buffer.from(json.signature, 'hex'); + return instance; + } + static fromCLIJson(json, rootSystemName = 'VRSC') { + var _a; + const instance = new VerifiableSignatureData(); + instance.version = new bn_js_1.BN(VerifiableSignatureData.TYPE_VERUSID_DEFAULT); + instance.hashType = new bn_js_1.BN(json.signaturedata.hashtype); + instance.signatureVersion = new bn_js_1.BN(json.signatureversion); //default Signature Version + instance.systemID = CompactAddressObject_1.CompactIAddressObject.fromAddress(json.systemid, rootSystemName); + instance.identityID = CompactAddressObject_1.CompactIAddressObject.fromAddress(json.address, rootSystemName); + // Set optional fields + instance.vdxfKeys = json.vdxfkeys; + instance.vdxfKeyNames = json.vdxfkeynames; + instance.boundHashes = (_a = json.boundhashes) === null || _a === void 0 ? void 0 : _a.map(x => Buffer.from(x, 'hex')); + // Store the full signature (from daemon in base64 format) + instance.signatureAsVch = Buffer.from(json.signature, 'base64'); + instance.setFlags(); + return instance; + } +} +exports.VerifiableSignatureData = VerifiableSignatureData; +VerifiableSignatureData.VERSION_INVALID = new bn_js_1.BN(0); +VerifiableSignatureData.FIRST_VERSION = new bn_js_1.BN(1); +VerifiableSignatureData.LAST_VERSION = new bn_js_1.BN(1); +VerifiableSignatureData.DEFAULT_VERSION = new bn_js_1.BN(1); +VerifiableSignatureData.TYPE_VERUSID_DEFAULT = new bn_js_1.BN(1); +VerifiableSignatureData.FLAG_HAS_VDXF_KEYS = new bn_js_1.BN(1); +VerifiableSignatureData.FLAG_HAS_VDXF_KEY_NAMES = new bn_js_1.BN(2); +VerifiableSignatureData.FLAG_HAS_BOUND_HASHES = new bn_js_1.BN(4); +VerifiableSignatureData.FLAG_HAS_STATEMENTS = new bn_js_1.BN(8); diff --git a/dist/vdxf/classes/appencryption/AppEncryptionRequestDetails.d.ts b/dist/vdxf/classes/appencryption/AppEncryptionRequestDetails.d.ts new file mode 100644 index 00000000..60ffa21d --- /dev/null +++ b/dist/vdxf/classes/appencryption/AppEncryptionRequestDetails.d.ts @@ -0,0 +1,70 @@ +/** + * AppEncryptionRequestDetails - Class for handling application requests for encrypted derived seeds + * + * This class is used when an application is requesting an encrypted derived seed from the user's master seed, + * using specific parameters passed by the application. The request includes: + * - App or delegated ID making the request (mandatory) + * - A target encryption key (zaddress format) for encrypting the reply + * - Derivation number for seed generation + * - Optional derivation ID (defaults to Z-address from ID signing if not present) + * - Optional request ID for tracking + * + * The user's wallet can use these parameters to derive a specific seed from their master seed + * and encrypt it using the provided encryption key, ensuring the application receives only + * the specific derived seed it needs without exposing the master seed. + * + * The RETURN_ESK flag can be set to signal that the Extended Spending Key should be returned. + */ +import { BigNumber } from '../../../utils/types/BigNumber'; +import { SerializableEntity } from '../../../utils/types/SerializableEntity'; +import { CompactIAddressObject, CompactAddressObjectJson } from '../CompactAddressObject'; +export interface AppEncryptionRequestInterface { + version?: BigNumber; + flags: BigNumber; + encryptToZAddress: string; + derivationNumber: BigNumber; + derivationID?: CompactIAddressObject; + requestID?: string; +} +export interface AppEncryptionRequestJson { + version: number; + flags: number; + encrypttozaddress: string; + derivationnumber: number; + derivationid?: CompactAddressObjectJson; + requestid?: string; +} +/** + * Checks if a string is a valid hexadecimal address + * @param flags - Optional flags for the request + * @flag HAS_REQUEST_ID - Indicates if a request ID is included + * + * @param encryptToZAddress - The encryption key to use for encrypting to + * @param derivationNumber - The derivation number to validate + */ +export declare class AppEncryptionRequestDetails implements SerializableEntity { + static VERSION_INVALID: import("bn.js"); + static FIRST_VERSION: import("bn.js"); + static LAST_VERSION: import("bn.js"); + static DEFAULT_VERSION: import("bn.js"); + static HAS_DERIVATION_ID: import("bn.js"); + static HAS_REQUEST_ID: import("bn.js"); + static RETURN_ESK: import("bn.js"); + version: BigNumber; + flags: BigNumber; + encryptToZAddress: string; + derivationNumber: BigNumber; + derivationID?: CompactIAddressObject; + requestID?: string; + constructor(data?: AppEncryptionRequestInterface); + setFlags(): void; + calcFlags(): BigNumber; + isValid(): boolean; + hasDerivationID(flags?: BigNumber): boolean; + hasRequestID(flags?: BigNumber): boolean; + getByteLength(): number; + toBuffer(): Buffer; + fromBuffer(buffer: Buffer, offset?: number): number; + toJson(): AppEncryptionRequestJson; + static fromJson(json: AppEncryptionRequestJson): AppEncryptionRequestDetails; +} diff --git a/dist/vdxf/classes/appencryption/AppEncryptionRequestDetails.js b/dist/vdxf/classes/appencryption/AppEncryptionRequestDetails.js new file mode 100644 index 00000000..d0c98e09 --- /dev/null +++ b/dist/vdxf/classes/appencryption/AppEncryptionRequestDetails.js @@ -0,0 +1,159 @@ +"use strict"; +/** + * AppEncryptionRequestDetails - Class for handling application requests for encrypted derived seeds + * + * This class is used when an application is requesting an encrypted derived seed from the user's master seed, + * using specific parameters passed by the application. The request includes: + * - App or delegated ID making the request (mandatory) + * - A target encryption key (zaddress format) for encrypting the reply + * - Derivation number for seed generation + * - Optional derivation ID (defaults to Z-address from ID signing if not present) + * - Optional request ID for tracking + * + * The user's wallet can use these parameters to derive a specific seed from their master seed + * and encrypt it using the provided encryption key, ensuring the application receives only + * the specific derived seed it needs without exposing the master seed. + * + * The RETURN_ESK flag can be set to signal that the Extended Spending Key should be returned. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AppEncryptionRequestDetails = void 0; +const bn_js_1 = require("bn.js"); +const bufferutils_1 = require("../../../utils/bufferutils"); +const { BufferReader, BufferWriter } = bufferutils_1.default; +const sapling_1 = require("../../../utils/sapling"); +const CompactAddressObject_1 = require("../CompactAddressObject"); +const varuint_1 = require("../../../utils/varuint"); +const address_1 = require("../../../utils/address"); +const vdxf_1 = require("../../../constants/vdxf"); +/** + * Checks if a string is a valid hexadecimal address + * @param flags - Optional flags for the request + * @flag HAS_REQUEST_ID - Indicates if a request ID is included + * + * @param encryptToZAddress - The encryption key to use for encrypting to + * @param derivationNumber - The derivation number to validate + */ +class AppEncryptionRequestDetails { + constructor(data) { + this.version = (data === null || data === void 0 ? void 0 : data.version) || AppEncryptionRequestDetails.DEFAULT_VERSION; + this.flags = (data === null || data === void 0 ? void 0 : data.flags) || new bn_js_1.BN(0); + this.encryptToZAddress = (data === null || data === void 0 ? void 0 : data.encryptToZAddress) || ''; + this.derivationNumber = (data === null || data === void 0 ? void 0 : data.derivationNumber) || new bn_js_1.BN(0); + this.derivationID = data === null || data === void 0 ? void 0 : data.derivationID; + this.requestID = data === null || data === void 0 ? void 0 : data.requestID; + this.setFlags(); + } + setFlags() { + this.flags = this.calcFlags(); + } + calcFlags() { + let flags = new bn_js_1.BN(0); + if (this.derivationID != null) { + flags = flags.or(AppEncryptionRequestDetails.HAS_DERIVATION_ID); + } + if (this.requestID != null) { + flags = flags.or(AppEncryptionRequestDetails.HAS_REQUEST_ID); + } + return flags; + } + isValid() { + let valid = true; + valid && (valid = this.encryptToZAddress != null && this.encryptToZAddress.length > 0); + valid && (valid = this.derivationNumber != null && this.derivationNumber.gte(new bn_js_1.BN(0))); + return valid; + } + hasDerivationID(flags = this.flags) { + return flags.and(AppEncryptionRequestDetails.HAS_DERIVATION_ID).gt(new bn_js_1.BN(0)); + } + hasRequestID(flags = this.flags) { + return flags.and(AppEncryptionRequestDetails.HAS_REQUEST_ID).gt(new bn_js_1.BN(0)); + } + getByteLength() { + const flags = this.calcFlags(); + let length = 0; + length += varuint_1.default.encodingLength(flags.toNumber()); + // encryptToKey - zaddress encoding (43 bytes for sapling address data) + length += 43; // Sapling address decoded data (11 + 32 bytes) + length += varuint_1.default.encodingLength(this.derivationNumber.toNumber()); + if (this.hasDerivationID(flags)) { + length += this.derivationID.getByteLength(); + } + if (this.hasRequestID(flags)) { + length += vdxf_1.HASH160_BYTE_LENGTH; + } + return length; + } + toBuffer() { + const flags = this.calcFlags(); + const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); + // Write flags + writer.writeCompactSize(flags.toNumber()); + // Write encryptToAddress as decoded sapling address data + const saplingData = (0, sapling_1.decodeSaplingAddress)(this.encryptToZAddress); + writer.writeSlice(Buffer.concat([saplingData.d, saplingData.pk_d])); + // Write mandatory derivation number + writer.writeVarInt(this.derivationNumber); + if (this.hasDerivationID(flags)) { + writer.writeSlice(this.derivationID.toBuffer()); + } + if (this.hasRequestID(flags)) { + writer.writeSlice((0, address_1.fromBase58Check)(this.requestID).hash); + } + return writer.buffer; + } + fromBuffer(buffer, offset) { + const reader = new BufferReader(buffer, offset); + // Read flags + this.flags = new bn_js_1.BN(reader.readCompactSize()); + // Read encryptToAddress as 43-byte sapling data and encode as sapling address + const saplingData = reader.readSlice(43); + this.encryptToZAddress = (0, sapling_1.toBech32)('zs', saplingData); + // Read mandatory derivation number + this.derivationNumber = reader.readVarInt(); + if (this.hasDerivationID()) { + const derivationIDObj = new CompactAddressObject_1.CompactIAddressObject(); + reader.offset = derivationIDObj.fromBuffer(reader.buffer, reader.offset); + this.derivationID = derivationIDObj; + } + if (this.hasRequestID()) { + this.requestID = (0, address_1.toBase58Check)(reader.readSlice(20), vdxf_1.I_ADDR_VERSION); + } + return reader.offset; + } + toJson() { + var _a; + // Set flags before serialization + const flags = this.calcFlags(); + return { + version: this.version.toNumber(), + flags: flags.toNumber(), + encrypttozaddress: this.encryptToZAddress, + derivationnumber: this.derivationNumber.toNumber(), + derivationid: (_a = this.derivationID) === null || _a === void 0 ? void 0 : _a.toJson(), + requestid: this.requestID + }; + } + static fromJson(json) { + const instance = new AppEncryptionRequestDetails(); + instance.version = new bn_js_1.BN(json.version); + instance.flags = new bn_js_1.BN(json.flags); + instance.encryptToZAddress = json.encrypttozaddress; + instance.derivationNumber = new bn_js_1.BN(json.derivationnumber); + if (instance.hasDerivationID()) { + instance.derivationID = CompactAddressObject_1.CompactIAddressObject.fromCompactAddressObjectJson(json === null || json === void 0 ? void 0 : json.derivationid); + } + if (instance.hasRequestID()) { + instance.requestID = json === null || json === void 0 ? void 0 : json.requestid; + } + return instance; + } +} +exports.AppEncryptionRequestDetails = AppEncryptionRequestDetails; +AppEncryptionRequestDetails.VERSION_INVALID = new bn_js_1.BN(0); +AppEncryptionRequestDetails.FIRST_VERSION = new bn_js_1.BN(1); +AppEncryptionRequestDetails.LAST_VERSION = new bn_js_1.BN(1); +AppEncryptionRequestDetails.DEFAULT_VERSION = new bn_js_1.BN(1); +AppEncryptionRequestDetails.HAS_DERIVATION_ID = new bn_js_1.BN(1); +AppEncryptionRequestDetails.HAS_REQUEST_ID = new bn_js_1.BN(2); +AppEncryptionRequestDetails.RETURN_ESK = new bn_js_1.BN(4); //flag to signal to return the Extended Spending Key diff --git a/dist/vdxf/classes/appencryption/AppEncryptionResponseDetails.d.ts b/dist/vdxf/classes/appencryption/AppEncryptionResponseDetails.d.ts new file mode 100644 index 00000000..b9ba93c6 --- /dev/null +++ b/dist/vdxf/classes/appencryption/AppEncryptionResponseDetails.d.ts @@ -0,0 +1,45 @@ +import { BigNumber } from '../../../utils/types/BigNumber'; +import { SerializableEntity } from '../../../utils/types/SerializableEntity'; +import { SaplingPaymentAddress } from '../../../pbaas'; +import { SaplingExtendedSpendingKey } from '../../../pbaas/SaplingExtendedSpendingKey'; +import { SaplingExtendedViewingKey } from '../../../pbaas/SaplingExtendedViewingKey'; +export interface AppEncryptionResponseDetailsInterface { + version: BigNumber; + flags?: BigNumber; + requestID?: string; + incomingViewingKey: Buffer; + extendedViewingKey: SaplingExtendedViewingKey; + address: SaplingPaymentAddress; + extendedSpendingKey?: SaplingExtendedSpendingKey; +} +export interface AppEncryptionResponseDetailsJson { + version: number; + flags?: number; + requestid?: string; + incomingviewingkey: string; + extendedviewingkey: string; + address: string; + extendedspendingkey?: string; +} +export declare class AppEncryptionResponseDetails implements SerializableEntity { + version: BigNumber; + flags: BigNumber; + requestID?: string; + incomingViewingKey: Buffer; + extendedViewingKey: SaplingExtendedViewingKey; + address: SaplingPaymentAddress; + extendedSpendingKey?: SaplingExtendedSpendingKey; + static RESPONSE_CONTAINS_REQUEST_ID: import("bn.js"); + static RESPONSE_CONTAINS_EXTENDED_SPENDING_KEY: import("bn.js"); + constructor(data?: AppEncryptionResponseDetailsInterface); + containsRequestID(): boolean; + toggleContainsRequestID(): void; + containsExtendedSpendingKey(): boolean; + toggleContainsExtendedSpendingKey(): void; + toSha256(): Buffer; + getByteLength(): number; + toBuffer(): Buffer; + fromBuffer(buffer: Buffer, offset?: number): number; + toJson(): AppEncryptionResponseDetailsJson; + static fromJson(json: AppEncryptionResponseDetailsJson): AppEncryptionResponseDetails; +} diff --git a/dist/vdxf/classes/appencryption/AppEncryptionResponseDetails.js b/dist/vdxf/classes/appencryption/AppEncryptionResponseDetails.js new file mode 100644 index 00000000..9e1f08ed --- /dev/null +++ b/dist/vdxf/classes/appencryption/AppEncryptionResponseDetails.js @@ -0,0 +1,119 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AppEncryptionResponseDetails = void 0; +const bn_js_1 = require("bn.js"); +const varint_1 = require("../../../utils/varint"); +const bufferutils_1 = require("../../../utils/bufferutils"); +const { BufferReader, BufferWriter } = bufferutils_1.default; +const address_1 = require("../../../utils/address"); +const vdxf_1 = require("../../../constants/vdxf"); +const pbaas_1 = require("../../../pbaas"); +const createHash = require("create-hash"); +const SaplingExtendedSpendingKey_1 = require("../../../pbaas/SaplingExtendedSpendingKey"); +const SaplingExtendedViewingKey_1 = require("../../../pbaas/SaplingExtendedViewingKey"); +class AppEncryptionResponseDetails { + constructor(data) { + var _a, _b, _c, _d, _e; + this.version = (_a = data === null || data === void 0 ? void 0 : data.version) !== null && _a !== void 0 ? _a : new bn_js_1.BN(1); + this.flags = (_b = data === null || data === void 0 ? void 0 : data.flags) !== null && _b !== void 0 ? _b : new bn_js_1.BN(0, 10); + this.incomingViewingKey = (_c = data === null || data === void 0 ? void 0 : data.incomingViewingKey) !== null && _c !== void 0 ? _c : Buffer.alloc(32); + this.extendedViewingKey = (_d = data === null || data === void 0 ? void 0 : data.extendedViewingKey) !== null && _d !== void 0 ? _d : new SaplingExtendedViewingKey_1.SaplingExtendedViewingKey(); + this.address = (_e = data === null || data === void 0 ? void 0 : data.address) !== null && _e !== void 0 ? _e : new pbaas_1.SaplingPaymentAddress(); + if (data === null || data === void 0 ? void 0 : data.requestID) { + if (!this.containsRequestID()) + this.toggleContainsRequestID(); + this.requestID = data.requestID; + } + if (data === null || data === void 0 ? void 0 : data.extendedSpendingKey) { + if (!this.containsExtendedSpendingKey()) + this.toggleContainsExtendedSpendingKey(); + this.extendedSpendingKey = data.extendedSpendingKey; + } + } + containsRequestID() { + return !!(this.flags.and(AppEncryptionResponseDetails.RESPONSE_CONTAINS_REQUEST_ID).toNumber()); + } + toggleContainsRequestID() { + this.flags = this.flags.xor(AppEncryptionResponseDetails.RESPONSE_CONTAINS_REQUEST_ID); + } + containsExtendedSpendingKey() { + return !!(this.flags.and(AppEncryptionResponseDetails.RESPONSE_CONTAINS_EXTENDED_SPENDING_KEY).toNumber()); + } + toggleContainsExtendedSpendingKey() { + this.flags = this.flags.xor(AppEncryptionResponseDetails.RESPONSE_CONTAINS_EXTENDED_SPENDING_KEY); + } + toSha256() { + return createHash("sha256").update(this.toBuffer()).digest(); + } + getByteLength() { + let length = 0; + length += varint_1.default.encodingLength(this.flags); + if (this.containsRequestID()) { + length += vdxf_1.HASH160_BYTE_LENGTH; + } + length += 32; // incomingViewingKey + length += this.extendedViewingKey.getByteLength(); + length += this.address.getByteLength(); + if (this.containsExtendedSpendingKey()) { + length += this.extendedSpendingKey.getByteLength(); + } + return length; + } + toBuffer() { + const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); + writer.writeVarInt(this.flags); + if (this.containsRequestID()) { + writer.writeSlice((0, address_1.fromBase58Check)(this.requestID).hash); + } + writer.writeSlice(this.incomingViewingKey); + writer.writeSlice(this.extendedViewingKey.toBuffer()); + writer.writeSlice(this.address.toBuffer()); + if (this.containsExtendedSpendingKey()) { + writer.writeSlice(this.extendedSpendingKey.toBuffer()); + } + return writer.buffer; + } + fromBuffer(buffer, offset = 0) { + const reader = new BufferReader(buffer, offset); + this.flags = reader.readVarInt(); + if (this.containsRequestID()) { + this.requestID = (0, address_1.toBase58Check)(reader.readSlice(vdxf_1.HASH160_BYTE_LENGTH), vdxf_1.I_ADDR_VERSION); + } + this.incomingViewingKey = reader.readSlice(32); + this.extendedViewingKey = new SaplingExtendedViewingKey_1.SaplingExtendedViewingKey(); + reader.offset = this.extendedViewingKey.fromBuffer(reader.buffer, reader.offset); + this.address = new pbaas_1.SaplingPaymentAddress(); + reader.offset = this.address.fromBuffer(reader.buffer, reader.offset); + if (this.containsExtendedSpendingKey()) { + this.extendedSpendingKey = new SaplingExtendedSpendingKey_1.SaplingExtendedSpendingKey(); + reader.offset = this.extendedSpendingKey.fromBuffer(reader.buffer, reader.offset); + } + return reader.offset; + } + toJson() { + return { + version: this.version.toNumber(), + flags: this.flags.toNumber(), + requestid: this.containsRequestID() ? this.requestID : undefined, + incomingviewingkey: this.incomingViewingKey.toString('hex'), + extendedviewingkey: this.extendedViewingKey.toKeyString(), + address: this.address.toAddressString(), + extendedspendingkey: this.containsExtendedSpendingKey() ? this.extendedSpendingKey.toKeyString() : undefined + }; + } + static fromJson(json) { + var _a; + return new AppEncryptionResponseDetails({ + version: new bn_js_1.BN(json.version, 10), + flags: new bn_js_1.BN((_a = json.flags) !== null && _a !== void 0 ? _a : 0, 10), + requestID: json.requestid, + incomingViewingKey: Buffer.from(json.incomingviewingkey, 'hex'), + extendedViewingKey: SaplingExtendedViewingKey_1.SaplingExtendedViewingKey.fromKeyString(json.extendedviewingkey), + address: pbaas_1.SaplingPaymentAddress.fromAddressString(json.address), + extendedSpendingKey: json.extendedspendingkey ? SaplingExtendedSpendingKey_1.SaplingExtendedSpendingKey.fromKeyString(json.extendedspendingkey) : undefined + }); + } +} +exports.AppEncryptionResponseDetails = AppEncryptionResponseDetails; +AppEncryptionResponseDetails.RESPONSE_CONTAINS_REQUEST_ID = new bn_js_1.BN(1, 10); +AppEncryptionResponseDetails.RESPONSE_CONTAINS_EXTENDED_SPENDING_KEY = new bn_js_1.BN(2, 10); diff --git a/dist/vdxf/classes/attestation/AttestationDetails.d.ts b/dist/vdxf/classes/attestation/AttestationDetails.d.ts deleted file mode 100644 index 259e6559..00000000 --- a/dist/vdxf/classes/attestation/AttestationDetails.d.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { BigNumber } from '../../../utils/types/BigNumber'; -import { MMRDescriptor, MMRDescriptorJson } from '../../../pbaas/MMRDescriptor'; -import { SignatureData, SignatureJsonDataInterface } from '../../../pbaas/SignatureData'; -import { SerializableEntity } from '../../../utils/types/SerializableEntity'; -export interface AttestationPairJson { - mmrdescriptor: MMRDescriptorJson; - signaturedata: SignatureJsonDataInterface; -} -export interface AttestationDetailsJson { - version: number; - flags?: number; - label?: string; - id?: string; - timestamp?: number; - attestations: AttestationPairJson[]; -} -export declare class AttestationPair implements SerializableEntity { - mmrDescriptor: MMRDescriptor; - signatureData: SignatureData; - constructor(data?: { - mmrDescriptor?: MMRDescriptor; - signatureData?: SignatureData; - }); - static fromJson(data: AttestationPairJson): AttestationPair; - getByteLength(): number; - toBuffer(): Buffer; - fromBuffer(buffer: Buffer, offset?: number): number; - toJson(): AttestationPairJson; -} -export declare class AttestationDetails implements SerializableEntity { - static VERSION_INVALID: import("bn.js"); - static FIRST_VERSION: import("bn.js"); - static LAST_VERSION: import("bn.js"); - static DEFAULT_VERSION: import("bn.js"); - static FLAG_LABEL: number; - static FLAG_ID: number; - static FLAG_TIMESTAMP: number; - version: BigNumber; - flags: BigNumber; - label?: string; - id?: string; - timestamp?: BigNumber; - attestations: AttestationPair[]; - constructor(data?: { - version?: BigNumber; - flags?: BigNumber; - label?: string; - id?: string; - timestamp?: BigNumber; - attestations?: AttestationPair[]; - }); - static fromJson(data: AttestationDetailsJson): AttestationDetails; - /** - * Create AttestationDetails from a single Verus node response - * @param nodeResponse - The JSON object from Verus node: {"signaturedata": ..., "mmrdescriptor": ...} - * @param options - Optional metadata (label, id, timestamp) - */ - static fromNodeResponse(nodeResponse: { - signaturedata: any; - mmrdescriptor: any; - }, options?: { - label?: string; - id?: string; - timestamp?: number; - }): AttestationDetails; - /** - * Create AttestationDetails from multiple Verus node responses - * @param nodeResponses - Array of JSON objects from Verus node - * @param options - Optional metadata (label, id, timestamp) - */ - static fromNodeResponses(nodeResponses: Array<{ - signaturedata: any; - mmrdescriptor: any; - }>, options?: { - label?: string; - id?: string; - timestamp?: number; - }): AttestationDetails; - hasLabel(): boolean; - hasId(): boolean; - hasTimestamp(): boolean; - setLabel(label: string): void; - setId(id: string): void; - setTimestamp(timestamp: BigNumber): void; - /** - * Calculate flags based on the presence of optional fields - */ - calcFlags(): BigNumber; - /** - * Set the flags based on calculated values from present fields - */ - setFlags(): void; - /** - * Add a new attestation from a Verus node response - * @param nodeResponse - The JSON object from Verus node: {"signaturedata": ..., "mmrdescriptor": ...} - */ - addAttestation(nodeResponse: { - signaturedata: any; - mmrdescriptor: any; - }): void; - /** - * Add multiple attestations from Verus node responses - * @param nodeResponses - Array of JSON objects from Verus node - */ - addAttestations(nodeResponses: Array<{ - signaturedata: any; - mmrdescriptor: any; - }>): void; - /** - * Add an existing AttestationPair to this collection - * @param attestationPair - The AttestationPair to add - */ - addAttestationPair(attestationPair: AttestationPair): void; - /** - * Get the number of attestations in this collection - */ - getAttestationCount(): number; - getByteLength(): number; - toBuffer(): Buffer; - fromBuffer(buffer: Buffer, offset?: number): number; - isValid(): boolean; - toJson(): AttestationDetailsJson; -} diff --git a/dist/vdxf/classes/attestation/AttestationDetails.js b/dist/vdxf/classes/attestation/AttestationDetails.js deleted file mode 100644 index 12fcf266..00000000 --- a/dist/vdxf/classes/attestation/AttestationDetails.js +++ /dev/null @@ -1,317 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.AttestationDetails = exports.AttestationPair = void 0; -const bn_js_1 = require("bn.js"); -const varint_1 = require("../../../utils/varint"); -const varuint_1 = require("../../../utils/varuint"); -const bufferutils_1 = require("../../../utils/bufferutils"); -const { BufferReader, BufferWriter } = bufferutils_1.default; -const MMRDescriptor_1 = require("../../../pbaas/MMRDescriptor"); -const SignatureData_1 = require("../../../pbaas/SignatureData"); -class AttestationPair { - constructor(data) { - if (data) { - this.mmrDescriptor = data.mmrDescriptor || new MMRDescriptor_1.MMRDescriptor(); - this.signatureData = data.signatureData || new SignatureData_1.SignatureData(); - } - else { - this.mmrDescriptor = new MMRDescriptor_1.MMRDescriptor(); - this.signatureData = new SignatureData_1.SignatureData(); - } - } - static fromJson(data) { - return new AttestationPair({ - mmrDescriptor: MMRDescriptor_1.MMRDescriptor.fromJson(data.mmrdescriptor), - signatureData: SignatureData_1.SignatureData.fromJson(data.signaturedata) - }); - } - getByteLength() { - return this.mmrDescriptor.getByteLength() + this.signatureData.getByteLength(); - } - toBuffer() { - const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); - writer.writeSlice(this.mmrDescriptor.toBuffer()); - writer.writeSlice(this.signatureData.toBuffer()); - return writer.buffer; - } - fromBuffer(buffer, offset) { - const reader = new BufferReader(buffer, offset); - this.mmrDescriptor = new MMRDescriptor_1.MMRDescriptor(); - reader.offset = this.mmrDescriptor.fromBuffer(reader.buffer, reader.offset); - this.signatureData = new SignatureData_1.SignatureData(); - reader.offset = this.signatureData.fromBuffer(reader.buffer, reader.offset); - return reader.offset; - } - toJson() { - return { - mmrdescriptor: this.mmrDescriptor.toJson(), - signaturedata: this.signatureData.toJson() - }; - } -} -exports.AttestationPair = AttestationPair; -class AttestationDetails { - constructor(data) { - if (data) { - this.version = data.version || AttestationDetails.DEFAULT_VERSION; - this.flags = data.flags || new bn_js_1.BN(0); - this.label = data.label; - this.id = data.id; - this.timestamp = data.timestamp; - this.attestations = data.attestations || []; - } - else { - this.version = AttestationDetails.DEFAULT_VERSION; - this.flags = new bn_js_1.BN(0); - this.attestations = []; - } - } - static fromJson(data) { - const newAttestationDetails = new AttestationDetails(); - if (data) { - if (data.version) - newAttestationDetails.version = new bn_js_1.BN(data.version); - if (data.flags !== undefined) - newAttestationDetails.flags = new bn_js_1.BN(data.flags); - if (data.label) - newAttestationDetails.label = data.label; - if (data.id) - newAttestationDetails.id = data.id; - if (data.timestamp) - newAttestationDetails.timestamp = new bn_js_1.BN(data.timestamp); - if (data.attestations) { - newAttestationDetails.attestations = data.attestations.map(attestation => AttestationPair.fromJson(attestation)); - } - } - return newAttestationDetails; - } - /** - * Create AttestationDetails from a single Verus node response - * @param nodeResponse - The JSON object from Verus node: {"signaturedata": ..., "mmrdescriptor": ...} - * @param options - Optional metadata (label, id, timestamp) - */ - static fromNodeResponse(nodeResponse, options) { - const attestationPair = new AttestationPair({ - mmrDescriptor: MMRDescriptor_1.MMRDescriptor.fromJson(nodeResponse.mmrdescriptor), - signatureData: SignatureData_1.SignatureData.fromJson(nodeResponse.signaturedata) - }); - const attestationDetails = new AttestationDetails({ - attestations: [attestationPair] - }); - // Set optional metadata - if (options === null || options === void 0 ? void 0 : options.label) { - attestationDetails.setLabel(options.label); - } - if (options === null || options === void 0 ? void 0 : options.id) { - attestationDetails.setId(options.id); - } - if (options === null || options === void 0 ? void 0 : options.timestamp) { - attestationDetails.setTimestamp(new bn_js_1.BN(options.timestamp)); - } - // Update flags based on set metadata - attestationDetails.setFlags(); - return attestationDetails; - } - /** - * Create AttestationDetails from multiple Verus node responses - * @param nodeResponses - Array of JSON objects from Verus node - * @param options - Optional metadata (label, id, timestamp) - */ - static fromNodeResponses(nodeResponses, options) { - const attestationPairs = nodeResponses.map(response => new AttestationPair({ - mmrDescriptor: MMRDescriptor_1.MMRDescriptor.fromJson(response.mmrdescriptor), - signatureData: SignatureData_1.SignatureData.fromJson(response.signaturedata) - })); - const attestationDetails = new AttestationDetails({ - attestations: attestationPairs - }); - // Set optional metadata - if (options === null || options === void 0 ? void 0 : options.label) { - attestationDetails.setLabel(options.label); - } - if (options === null || options === void 0 ? void 0 : options.id) { - attestationDetails.setId(options.id); - } - if (options === null || options === void 0 ? void 0 : options.timestamp) { - attestationDetails.setTimestamp(new bn_js_1.BN(options.timestamp)); - } - // Update flags based on set metadata - attestationDetails.setFlags(); - return attestationDetails; - } - hasLabel() { - return (this.flags.toNumber() & AttestationDetails.FLAG_LABEL) !== 0; - } - hasId() { - return (this.flags.toNumber() & AttestationDetails.FLAG_ID) !== 0; - } - hasTimestamp() { - return (this.flags.toNumber() & AttestationDetails.FLAG_TIMESTAMP) !== 0; - } - setLabel(label) { - this.label = label; - } - setId(id) { - this.id = id; - } - setTimestamp(timestamp) { - this.timestamp = timestamp; - } - /** - * Calculate flags based on the presence of optional fields - */ - calcFlags() { - let flags = new bn_js_1.BN(0); - if (this.label && this.label.length > 0) { - flags = flags.or(new bn_js_1.BN(AttestationDetails.FLAG_LABEL)); - } - if (this.id && this.id.length > 0) { - flags = flags.or(new bn_js_1.BN(AttestationDetails.FLAG_ID)); - } - if (this.timestamp) { - flags = flags.or(new bn_js_1.BN(AttestationDetails.FLAG_TIMESTAMP)); - } - return flags; - } - /** - * Set the flags based on calculated values from present fields - */ - setFlags() { - this.flags = this.calcFlags(); - } - /** - * Add a new attestation from a Verus node response - * @param nodeResponse - The JSON object from Verus node: {"signaturedata": ..., "mmrdescriptor": ...} - */ - addAttestation(nodeResponse) { - const attestationPair = new AttestationPair({ - mmrDescriptor: MMRDescriptor_1.MMRDescriptor.fromJson(nodeResponse.mmrdescriptor), - signatureData: SignatureData_1.SignatureData.fromJson(nodeResponse.signaturedata) - }); - this.attestations.push(attestationPair); - } - /** - * Add multiple attestations from Verus node responses - * @param nodeResponses - Array of JSON objects from Verus node - */ - addAttestations(nodeResponses) { - const attestationPairs = nodeResponses.map(response => new AttestationPair({ - mmrDescriptor: MMRDescriptor_1.MMRDescriptor.fromJson(response.mmrdescriptor), - signatureData: SignatureData_1.SignatureData.fromJson(response.signaturedata) - })); - this.attestations.push(...attestationPairs); - } - /** - * Add an existing AttestationPair to this collection - * @param attestationPair - The AttestationPair to add - */ - addAttestationPair(attestationPair) { - this.attestations.push(attestationPair); - } - /** - * Get the number of attestations in this collection - */ - getAttestationCount() { - return this.attestations.length; - } - getByteLength() { - this.setFlags(); - let length = 0; - length += varint_1.default.encodingLength(this.version); - length += varint_1.default.encodingLength(this.flags); - if (this.hasLabel() && this.label) { - const labelBuffer = Buffer.from(this.label, 'utf8'); - length += varuint_1.default.encodingLength(labelBuffer.length); - length += labelBuffer.length; - } - if (this.hasId() && this.id) { - const idBuffer = Buffer.from(this.id, 'utf8'); - length += varuint_1.default.encodingLength(idBuffer.length); - length += idBuffer.length; - } - if (this.hasTimestamp() && this.timestamp) { - length += varint_1.default.encodingLength(this.timestamp); - } - length += varuint_1.default.encodingLength(this.attestations.length); - this.attestations.forEach((attestation) => { - length += attestation.getByteLength(); - }); - return length; - } - toBuffer() { - const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); - writer.writeVarInt(this.version); - writer.writeVarInt(this.flags); - if (this.hasLabel() && this.label) { - const labelBuffer = Buffer.from(this.label, 'utf8'); - writer.writeVarSlice(labelBuffer); - } - if (this.hasId() && this.id) { - const idBuffer = Buffer.from(this.id, 'utf8'); - writer.writeVarSlice(idBuffer); - } - if (this.hasTimestamp() && this.timestamp) { - writer.writeVarInt(this.timestamp); - } - writer.writeCompactSize(this.attestations.length); - this.attestations.forEach((attestation) => { - writer.writeSlice(attestation.toBuffer()); - }); - return writer.buffer; - } - fromBuffer(buffer, offset) { - const reader = new BufferReader(buffer, offset); - this.version = reader.readVarInt(); - this.flags = reader.readVarInt(); - if (this.hasLabel()) { - this.label = reader.readVarSlice().toString('utf8'); - } - if (this.hasId()) { - this.id = reader.readVarSlice().toString('utf8'); - } - if (this.hasTimestamp()) { - this.timestamp = reader.readVarInt(); - } - const attestationsLength = reader.readCompactSize(); - this.attestations = []; - for (let i = 0; i < attestationsLength; i++) { - const attestation = new AttestationPair(); - reader.offset = attestation.fromBuffer(reader.buffer, reader.offset); - this.attestations.push(attestation); - } - return reader.offset; - } - isValid() { - return this.version.gte(AttestationDetails.FIRST_VERSION) && - this.version.lte(AttestationDetails.LAST_VERSION) && - this.attestations.length > 0; - } - toJson() { - const retval = { - version: this.version.toNumber(), - attestations: this.attestations.map((attestation) => attestation.toJson()) - }; - if (this.flags.gt(new bn_js_1.BN(0))) { - retval.flags = this.flags.toNumber(); - } - if (this.hasLabel() && this.label) { - retval.label = this.label; - } - if (this.hasId() && this.id) { - retval.id = this.id; - } - if (this.hasTimestamp() && this.timestamp) { - retval.timestamp = this.timestamp.toNumber(); - } - return retval; - } -} -exports.AttestationDetails = AttestationDetails; -AttestationDetails.VERSION_INVALID = new bn_js_1.BN(0); -AttestationDetails.FIRST_VERSION = new bn_js_1.BN(1); -AttestationDetails.LAST_VERSION = new bn_js_1.BN(1); -AttestationDetails.DEFAULT_VERSION = new bn_js_1.BN(1); -// Flags -AttestationDetails.FLAG_LABEL = 1; -AttestationDetails.FLAG_ID = 2; -AttestationDetails.FLAG_TIMESTAMP = 4; diff --git a/dist/vdxf/classes/datapacket/DataPacketResponse.d.ts b/dist/vdxf/classes/datapacket/DataPacketResponse.d.ts new file mode 100644 index 00000000..b2484e17 --- /dev/null +++ b/dist/vdxf/classes/datapacket/DataPacketResponse.d.ts @@ -0,0 +1,68 @@ +/** + * DataPacketResponse - Class for providing structured responses to various request types + * + * This class serves as a universal response mechanism that can be used to reply to multiple + * types of requests. It packages response data within a DataDescriptor along with metadata + * for request tracking and timestamping. + * + * USAGE AS RESPONSE TO DIFFERENT REQUEST TYPES: + * + * 1. AppEncryptionRequestDetails Response: + * - The DataDescriptor 'data' field contains the encrypted derived seed + * - The requestID references the original AppEncryptionRequestDetails.requestID + * - Enables secure delivery of application-specific encrypted keys + * + * 2. UserDataRequestDetails Response: + * - The DataDescriptor 'data' field contains requested user data/attestations + * - The requestID references the original UserDataRequestDetails.requestID + * - Allows selective disclosure of personal information + * + * 3. UserSpecificDataPacketDetails Response: + * - The DataDescriptor 'data' field contains the response data or signed content + * - The requestID references the original UserSpecificDataPacketDetails.requestID + * - Supports bidirectional data exchange with signatures and statements + * + * REQUEST-RESPONSE CORRELATION: + * Each of the above request types includes its own requestID field. This response object's + * requestID field can be used to match responses back to their originating requests, enabling + * proper request-response correlation in asynchronous communication flows. + * + * GENERAL DATA REPLIES: + * This response format can also be used for other general data replies where: + * - Structured data needs to be transmitted via DataDescriptor + * - Request tracking through requestID is desired + * - Timestamp metadata (createdAt) is needed for the response + * - Response validation and integrity checking via SHA-256 is required + */ +import { BigNumber } from '../../../utils/types/BigNumber'; +import { SerializableEntity } from '../../../utils/types/SerializableEntity'; +import { DataDescriptor, DataDescriptorJson } from '../../../pbaas'; +export interface DataResponseInterface { + flags?: BigNumber; + requestID?: string; + data: DataDescriptor; +} +export interface DataResponseJson { + flags?: number; + requestid?: string; + data: DataDescriptorJson; +} +export declare class DataPacketResponse implements SerializableEntity { + flags?: BigNumber; + requestID?: string; + data: DataDescriptor; + static RESPONSE_CONTAINS_REQUEST_ID: import("bn.js"); + constructor(initialData?: { + flags?: BigNumber; + requestID?: string; + data: DataDescriptor; + }); + containsRequestID(): boolean; + toggleContainsRequestID(): void; + toSha256(): Buffer; + getByteLength(): number; + toBuffer(): Buffer; + fromBuffer(buffer: Buffer, offset?: number): number; + toJson(): DataResponseJson; + static fromJson(json: DataResponseJson): DataPacketResponse; +} diff --git a/dist/vdxf/classes/datapacket/DataPacketResponse.js b/dist/vdxf/classes/datapacket/DataPacketResponse.js new file mode 100644 index 00000000..e5aca09d --- /dev/null +++ b/dist/vdxf/classes/datapacket/DataPacketResponse.js @@ -0,0 +1,112 @@ +"use strict"; +/** + * DataPacketResponse - Class for providing structured responses to various request types + * + * This class serves as a universal response mechanism that can be used to reply to multiple + * types of requests. It packages response data within a DataDescriptor along with metadata + * for request tracking and timestamping. + * + * USAGE AS RESPONSE TO DIFFERENT REQUEST TYPES: + * + * 1. AppEncryptionRequestDetails Response: + * - The DataDescriptor 'data' field contains the encrypted derived seed + * - The requestID references the original AppEncryptionRequestDetails.requestID + * - Enables secure delivery of application-specific encrypted keys + * + * 2. UserDataRequestDetails Response: + * - The DataDescriptor 'data' field contains requested user data/attestations + * - The requestID references the original UserDataRequestDetails.requestID + * - Allows selective disclosure of personal information + * + * 3. UserSpecificDataPacketDetails Response: + * - The DataDescriptor 'data' field contains the response data or signed content + * - The requestID references the original UserSpecificDataPacketDetails.requestID + * - Supports bidirectional data exchange with signatures and statements + * + * REQUEST-RESPONSE CORRELATION: + * Each of the above request types includes its own requestID field. This response object's + * requestID field can be used to match responses back to their originating requests, enabling + * proper request-response correlation in asynchronous communication flows. + * + * GENERAL DATA REPLIES: + * This response format can also be used for other general data replies where: + * - Structured data needs to be transmitted via DataDescriptor + * - Request tracking through requestID is desired + * - Timestamp metadata (createdAt) is needed for the response + * - Response validation and integrity checking via SHA-256 is required + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.DataPacketResponse = void 0; +const bn_js_1 = require("bn.js"); +const varint_1 = require("../../../utils/varint"); +const bufferutils_1 = require("../../../utils/bufferutils"); +const { BufferReader, BufferWriter } = bufferutils_1.default; +const address_1 = require("../../../utils/address"); +const vdxf_1 = require("../../../constants/vdxf"); +const pbaas_1 = require("../../../pbaas"); +const createHash = require("create-hash"); +class DataPacketResponse { + constructor(initialData) { + this.flags = initialData && initialData.flags ? initialData.flags : new bn_js_1.BN("0", 10); + if (initialData === null || initialData === void 0 ? void 0 : initialData.requestID) { + if (!this.containsRequestID()) + this.toggleContainsRequestID(); + this.requestID = initialData.requestID; + } + this.data = initialData && initialData.data ? initialData.data : new pbaas_1.DataDescriptor(); + } + containsRequestID() { + return !!(this.flags.and(DataPacketResponse.RESPONSE_CONTAINS_REQUEST_ID).toNumber()); + } + toggleContainsRequestID() { + this.flags = this.flags.xor(DataPacketResponse.RESPONSE_CONTAINS_REQUEST_ID); + } + toSha256() { + return createHash("sha256").update(this.toBuffer()).digest(); + } + getByteLength() { + let length = 0; + length += varint_1.default.encodingLength(this.flags); + if (this.containsRequestID()) { + length += vdxf_1.HASH160_BYTE_LENGTH; + } + length += this.data.getByteLength(); + return length; + } + toBuffer() { + const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); + writer.writeVarInt(this.flags); + if (this.containsRequestID()) { + writer.writeSlice((0, address_1.fromBase58Check)(this.requestID).hash); + } + writer.writeSlice(this.data.toBuffer()); + return writer.buffer; + } + fromBuffer(buffer, offset = 0) { + const reader = new BufferReader(buffer, offset); + this.flags = reader.readVarInt(); + if (this.containsRequestID()) { + this.requestID = (0, address_1.toBase58Check)(reader.readSlice(vdxf_1.HASH160_BYTE_LENGTH), vdxf_1.I_ADDR_VERSION); + } + this.data = new pbaas_1.DataDescriptor(); + this.data.fromBuffer(reader.buffer, reader.offset); + reader.offset += this.data.getByteLength(); + return reader.offset; + } + toJson() { + return { + flags: this.flags.toNumber(), + requestid: this.containsRequestID() ? this.requestID : undefined, + data: this.data.toJson() + }; + } + static fromJson(json) { + return new DataPacketResponse({ + flags: new bn_js_1.BN(json.flags, 10), + requestID: json.requestid, + data: pbaas_1.DataDescriptor.fromJson(json.data) + }); + } +} +exports.DataPacketResponse = DataPacketResponse; +DataPacketResponse.RESPONSE_CONTAINS_REQUEST_ID = new bn_js_1.BN(1, 10); diff --git a/dist/vdxf/classes/envelope/GenericEnvelope.d.ts b/dist/vdxf/classes/envelope/GenericEnvelope.d.ts new file mode 100644 index 00000000..6b199ced --- /dev/null +++ b/dist/vdxf/classes/envelope/GenericEnvelope.d.ts @@ -0,0 +1,76 @@ +import { BigNumber } from "../../../utils/types/BigNumber"; +import { OrdinalVDXFObject, OrdinalVDXFObjectJson } from "../ordinals/OrdinalVDXFObject"; +import { SerializableEntity } from "../../../utils/types/SerializableEntity"; +import { VerifiableSignatureData, VerifiableSignatureDataJson } from "../VerifiableSignatureData"; +import { CompactAddressObjectJson, CompactIAddressObject } from "../CompactAddressObject"; +export interface GenericEnvelopeInterface { + version?: BigNumber; + flags?: BigNumber; + signature?: VerifiableSignatureData; + requestID?: CompactIAddressObject; + createdAt?: BigNumber; + salt?: Buffer; + appOrDelegatedID?: CompactIAddressObject; + details: Array; +} +export type GenericEnvelopeJson = { + version: string; + flags?: string; + signature?: VerifiableSignatureDataJson; + requestid?: CompactAddressObjectJson; + createdat?: string; + salt?: string; + appOrDelegatedID?: CompactAddressObjectJson; + details: Array; +}; +export declare class GenericEnvelope implements SerializableEntity { + version: BigNumber; + flags: BigNumber; + signature?: VerifiableSignatureData; + requestID?: CompactIAddressObject; + createdAt?: BigNumber; + salt?: Buffer; + appOrDelegatedID?: CompactIAddressObject; + details: Array; + static VERSION_CURRENT: import("bn.js"); + static VERSION_FIRSTVALID: import("bn.js"); + static VERSION_LASTVALID: import("bn.js"); + static BASE_FLAGS: import("bn.js"); + static FLAG_SIGNED: import("bn.js"); + static FLAG_HAS_REQUEST_ID: import("bn.js"); + static FLAG_HAS_CREATED_AT: import("bn.js"); + static FLAG_MULTI_DETAILS: import("bn.js"); + static FLAG_IS_TESTNET: import("bn.js"); + static FLAG_HAS_SALT: import("bn.js"); + static FLAG_HAS_APP_OR_DELEGATED_ID: import("bn.js"); + constructor(envelope?: GenericEnvelopeInterface); + isValidVersion(): boolean; + isSigned(): boolean; + hasRequestID(): boolean; + hasMultiDetails(): boolean; + hasCreatedAt(): boolean; + hasSalt(): boolean; + hasAppOrDelegatedID(): boolean; + isTestnet(): boolean; + setSigned(): void; + setHasRequestID(): void; + setHasMultiDetails(): void; + setHasCreatedAt(): void; + setHasSalt(): void; + setHasAppOrDelegatedID(): void; + setIsTestnet(): void; + setFlags(): void; + getRawDataSha256(includeSig?: boolean): Buffer; + getDetailsIdentitySignatureHash(signedBlockheight: number): Buffer; + getDetails(index?: number): OrdinalVDXFObject; + protected getDataBufferLengthAfterSig(): number; + protected getDataBufferAfterSig(): Buffer; + private internalGetByteLength; + protected getByteLengthOptionalSig(includeSig?: boolean): number; + getByteLength(): number; + protected toBufferOptionalSig(includeSig?: boolean): Buffer; + toBuffer(): Buffer; + fromBuffer(buffer: Buffer, offset?: number): number; + toString(): string; + toJson(): GenericEnvelopeJson; +} diff --git a/dist/vdxf/classes/envelope/GenericEnvelope.js b/dist/vdxf/classes/envelope/GenericEnvelope.js new file mode 100644 index 00000000..7dc2b023 --- /dev/null +++ b/dist/vdxf/classes/envelope/GenericEnvelope.js @@ -0,0 +1,260 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.GenericEnvelope = void 0; +const bufferutils_1 = require("../../../utils/bufferutils"); +const base64url_1 = require("base64url"); +const bn_js_1 = require("bn.js"); +const OrdinalVDXFObject_1 = require("../ordinals/OrdinalVDXFObject"); +const varuint_1 = require("../../../utils/varuint"); +const crypto_1 = require("crypto"); +const VerifiableSignatureData_1 = require("../VerifiableSignatureData"); +const CompactAddressObject_1 = require("../CompactAddressObject"); +class GenericEnvelope { + constructor(envelope = { + details: [], + flags: GenericEnvelope.BASE_FLAGS + }) { + this.signature = envelope === null || envelope === void 0 ? void 0 : envelope.signature; + this.requestID = envelope === null || envelope === void 0 ? void 0 : envelope.requestID; + this.details = envelope === null || envelope === void 0 ? void 0 : envelope.details; + this.createdAt = envelope === null || envelope === void 0 ? void 0 : envelope.createdAt; + this.salt = envelope === null || envelope === void 0 ? void 0 : envelope.salt; + this.appOrDelegatedID = envelope === null || envelope === void 0 ? void 0 : envelope.appOrDelegatedID; + if (envelope === null || envelope === void 0 ? void 0 : envelope.flags) + this.flags = envelope.flags; + else + this.flags = GenericEnvelope.BASE_FLAGS; + if (envelope === null || envelope === void 0 ? void 0 : envelope.version) + this.version = envelope.version; + else + this.version = GenericEnvelope.VERSION_CURRENT; + this.setFlags(); + } + isValidVersion() { + return this.version.gte(GenericEnvelope.VERSION_FIRSTVALID) && this.version.lte(GenericEnvelope.VERSION_LASTVALID); + } + isSigned() { + return !!(this.flags.and(GenericEnvelope.FLAG_SIGNED).toNumber()); + } + hasRequestID() { + return !!(this.flags.and(GenericEnvelope.FLAG_HAS_REQUEST_ID).toNumber()); + } + hasMultiDetails() { + return !!(this.flags.and(GenericEnvelope.FLAG_MULTI_DETAILS).toNumber()); + } + hasCreatedAt() { + return !!(this.flags.and(GenericEnvelope.FLAG_HAS_CREATED_AT).toNumber()); + } + hasSalt() { + return !!(this.flags.and(GenericEnvelope.FLAG_HAS_SALT).toNumber()); + } + hasAppOrDelegatedID() { + return !!(this.flags.and(GenericEnvelope.FLAG_HAS_APP_OR_DELEGATED_ID).toNumber()); + } + isTestnet() { + return !!(this.flags.and(GenericEnvelope.FLAG_IS_TESTNET).toNumber()); + } + setSigned() { + this.flags = this.flags.or(GenericEnvelope.FLAG_SIGNED); + } + setHasRequestID() { + this.flags = this.flags.or(GenericEnvelope.FLAG_HAS_REQUEST_ID); + } + setHasMultiDetails() { + this.flags = this.flags.or(GenericEnvelope.FLAG_MULTI_DETAILS); + } + setHasCreatedAt() { + this.flags = this.flags.or(GenericEnvelope.FLAG_HAS_CREATED_AT); + } + setHasSalt() { + this.flags = this.flags.or(GenericEnvelope.FLAG_HAS_SALT); + } + setHasAppOrDelegatedID() { + this.flags = this.flags.or(GenericEnvelope.FLAG_HAS_APP_OR_DELEGATED_ID); + } + setIsTestnet() { + this.flags = this.flags.or(GenericEnvelope.FLAG_IS_TESTNET); + } + setFlags() { + if (this.signature) + this.setSigned(); + if (this.requestID) + this.setHasRequestID(); + if (this.createdAt) + this.setHasCreatedAt(); + if (this.salt) + this.setHasSalt(); + if (this.appOrDelegatedID) + this.setHasAppOrDelegatedID(); + if (this.details && this.details.length > 1) + this.setHasMultiDetails(); + } + getRawDataSha256(includeSig = false) { + return (0, crypto_1.createHash)("sha256").update(this.toBufferOptionalSig(includeSig)).digest(); + } + getDetailsIdentitySignatureHash(signedBlockheight) { + if (this.isSigned()) { + return this.signature.getIdentityHash(signedBlockheight, this.getRawDataSha256()); + } + else + throw new Error("Must contain verifiable signature with at least systemID and identityID to generate details identity signature hash"); + } + getDetails(index = 0) { + return this.details[index]; + } + getDataBufferLengthAfterSig() { + let length = 0; + if (this.hasRequestID()) { + length += this.requestID.getByteLength(); + } + if (this.hasCreatedAt()) { + length += varuint_1.default.encodingLength(this.createdAt.toNumber()); + } + if (this.hasSalt()) { + const saltLen = this.salt.length; + length += varuint_1.default.encodingLength(saltLen); + length += saltLen; + } + if (this.hasAppOrDelegatedID()) { + length += this.appOrDelegatedID.getByteLength(); + } + if (this.hasMultiDetails()) { + length += varuint_1.default.encodingLength(this.details.length); + for (const detail of this.details) { + length += detail.getByteLength(); + } + } + else { + length += this.getDetails().getByteLength(); + } + return length; + } + getDataBufferAfterSig() { + const writer = new bufferutils_1.default.BufferWriter(Buffer.alloc(this.getDataBufferLengthAfterSig())); + if (this.hasRequestID()) { + writer.writeSlice(this.requestID.toBuffer()); + } + if (this.hasCreatedAt()) { + writer.writeCompactSize(this.createdAt.toNumber()); + } + if (this.hasSalt()) { + writer.writeVarSlice(this.salt); + } + if (this.hasAppOrDelegatedID()) { + writer.writeSlice(this.appOrDelegatedID.toBuffer()); + } + if (this.hasMultiDetails()) { + writer.writeCompactSize(this.details.length); + for (const detail of this.details) { + writer.writeSlice(detail.toBuffer()); + } + } + else { + writer.writeSlice(this.getDetails().toBuffer()); + } + return writer.buffer; + } + internalGetByteLength(includeSig = true) { + let length = 0; + length += varuint_1.default.encodingLength(this.version.toNumber()); + length += varuint_1.default.encodingLength(this.flags.toNumber()); + if (this.isSigned() && includeSig) { + length += this.signature.getByteLength(); + } + length += this.getDataBufferLengthAfterSig(); + return length; + } + getByteLengthOptionalSig(includeSig) { + return this.internalGetByteLength(includeSig); + } + getByteLength() { + return this.getByteLengthOptionalSig(true); + } + toBufferOptionalSig(includeSig = true) { + const writer = new bufferutils_1.default.BufferWriter(Buffer.alloc(this.internalGetByteLength(includeSig))); + writer.writeCompactSize(this.version.toNumber()); + writer.writeCompactSize(this.flags.toNumber()); + if (this.isSigned() && includeSig) { + writer.writeSlice(this.signature.toBuffer()); + } + writer.writeSlice(this.getDataBufferAfterSig()); + return writer.buffer; + } + toBuffer() { + return this.toBufferOptionalSig(true); + } + fromBuffer(buffer, offset) { + if (buffer.length == 0) + throw new Error("Cannot create envelope from empty buffer"); + const reader = new bufferutils_1.default.BufferReader(buffer, offset); + this.version = new bn_js_1.BN(reader.readCompactSize()); + this.flags = new bn_js_1.BN(reader.readCompactSize()); + if (this.isSigned()) { + const _sig = new VerifiableSignatureData_1.VerifiableSignatureData(); + reader.offset = _sig.fromBuffer(reader.buffer, reader.offset); + this.signature = _sig; + } + if (this.hasRequestID()) { + this.requestID = new CompactAddressObject_1.CompactIAddressObject(); + reader.offset = this.requestID.fromBuffer(reader.buffer, reader.offset); + } + if (this.hasCreatedAt()) { + this.createdAt = new bn_js_1.BN(reader.readCompactSize()); + } + if (this.hasSalt()) { + this.salt = reader.readVarSlice(); + } + if (this.hasAppOrDelegatedID()) { + this.appOrDelegatedID = new CompactAddressObject_1.CompactIAddressObject(); + reader.offset = this.appOrDelegatedID.fromBuffer(reader.buffer, reader.offset); + } + if (this.hasMultiDetails()) { + this.details = []; + const numItems = reader.readCompactSize(); + for (let i = 0; i < numItems; i++) { + const ord = OrdinalVDXFObject_1.OrdinalVDXFObject.createFromBuffer(reader.buffer, reader.offset); + reader.offset = ord.offset; + this.details.push(ord.obj); + } + } + else { + const ord = OrdinalVDXFObject_1.OrdinalVDXFObject.createFromBuffer(reader.buffer, reader.offset); + reader.offset = ord.offset; + this.details = [ord.obj]; + } + return reader.offset; + } + toString() { + return base64url_1.default.encode(this.toBuffer()); + } + toJson() { + const details = []; + if (this.details != null) { + for (const detail of this.details) { + details.push(detail.toJson()); + } + } + return { + version: this.version.toString(), + flags: this.flags.toString(), + signature: this.isSigned() ? this.signature.toJson() : undefined, + requestid: this.hasRequestID() ? this.requestID.toJson() : undefined, + createdat: this.hasCreatedAt() ? this.createdAt.toString() : undefined, + salt: this.hasSalt() ? this.salt.toString('hex') : undefined, + appOrDelegatedID: this.hasAppOrDelegatedID() ? this.appOrDelegatedID.toJson() : undefined, + details: details + }; + } +} +exports.GenericEnvelope = GenericEnvelope; +GenericEnvelope.VERSION_CURRENT = new bn_js_1.BN(1, 10); +GenericEnvelope.VERSION_FIRSTVALID = new bn_js_1.BN(1, 10); +GenericEnvelope.VERSION_LASTVALID = new bn_js_1.BN(1, 10); +GenericEnvelope.BASE_FLAGS = new bn_js_1.BN(0, 10); +GenericEnvelope.FLAG_SIGNED = new bn_js_1.BN(1, 10); +GenericEnvelope.FLAG_HAS_REQUEST_ID = new bn_js_1.BN(2, 10); +GenericEnvelope.FLAG_HAS_CREATED_AT = new bn_js_1.BN(4, 10); +GenericEnvelope.FLAG_MULTI_DETAILS = new bn_js_1.BN(8, 10); +GenericEnvelope.FLAG_IS_TESTNET = new bn_js_1.BN(16, 10); +GenericEnvelope.FLAG_HAS_SALT = new bn_js_1.BN(32, 10); +GenericEnvelope.FLAG_HAS_APP_OR_DELEGATED_ID = new bn_js_1.BN(64, 10); diff --git a/dist/vdxf/classes/identity/IdentityUpdateEnvelope.d.ts b/dist/vdxf/classes/identity/IdentityUpdateEnvelope.d.ts deleted file mode 100644 index 51ea6aa6..00000000 --- a/dist/vdxf/classes/identity/IdentityUpdateEnvelope.d.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { VDXFObject, VerusIDSignature } from "../.."; -import { BigNumber } from "../../../utils/types/BigNumber"; -import { IdentityUpdateRequestDetails, IdentityUpdateRequestDetailsJson } from "./IdentityUpdateRequestDetails"; -import { IdentityID } from "../../../pbaas"; -import { IdentityUpdateResponseDetails, IdentityUpdateResponseDetailsJson } from "./IdentityUpdateResponseDetails"; -export declare const IDENTITY_UPDATE_VERSION_CURRENT: import("bn.js"); -export declare const IDENTITY_UPDATE_VERSION_FIRSTVALID: import("bn.js"); -export declare const IDENTITY_UPDATE_VERSION_LASTVALID: import("bn.js"); -export declare const IDENTITY_UPDATE_VERSION_SIGNED: import("bn.js"); -export declare const IDENTITY_UPDATE_VERSION_MASK: import("bn.js"); -export type IdentityUpdateDetails = IdentityUpdateRequestDetails | IdentityUpdateResponseDetails; -export type IdentityUpdateDetailsJson = IdentityUpdateRequestDetailsJson | IdentityUpdateResponseDetailsJson; -export interface IdentityUpdateEnvelopeInterface { - details: IdentityUpdateDetails; - systemid?: IdentityID; - signingid?: IdentityID; - signature?: string; - version?: BigNumber; -} -export interface IdentityUpdateEnvelopeJson { - details: IdentityUpdateDetailsJson; - systemid?: string; - signingid?: string; - signature?: string; - version?: string; -} -export declare class IdentityUpdateEnvelope extends VDXFObject { - systemid: IdentityID; - signingid: IdentityID; - signature?: VerusIDSignature; - details: IdentityUpdateDetails; - constructor(vdxfkey: string, request?: IdentityUpdateEnvelopeInterface); - private createEmptyDetails; - getVersionNoFlags(): BigNumber; - isValidVersion(): boolean; - isSigned(): boolean; - setSigned(): void; - getDetailsHash(signedBlockheight: number, signatureVersion?: number): Buffer; - protected _dataByteLength(signer?: IdentityID): number; - protected _toDataBuffer(signer?: IdentityID): Buffer; - dataByteLength(): number; - toDataBuffer(): Buffer; - protected _fromDataBuffer(buffer: Buffer, offset?: number): number; - fromDataBuffer(buffer: Buffer, offset?: number): number; - toWalletDeeplinkUri(): string; - static fromWalletDeeplinkUri(vdxfkey: string, uri: string): IdentityUpdateEnvelope; - toQrString(): string; - static fromQrString(vdxfkey: string, qrstring: string): IdentityUpdateEnvelope; - toJson(): IdentityUpdateEnvelopeJson; - protected static internalFromJson(json: IdentityUpdateEnvelopeJson, ctor: new (...args: any[]) => T, detailsFromJson: (json: IdentityUpdateDetailsJson) => IdentityUpdateDetails): T; -} -export declare class IdentityUpdateRequest extends IdentityUpdateEnvelope { - constructor(request?: IdentityUpdateEnvelopeInterface); - static fromWalletDeeplinkUri(uri: string): IdentityUpdateRequest; - static fromQrString(qrstring: string): IdentityUpdateRequest; - static fromJson(json: IdentityUpdateEnvelopeJson): IdentityUpdateRequest; -} -export declare class IdentityUpdateResponse extends IdentityUpdateEnvelope { - constructor(response?: IdentityUpdateEnvelopeInterface); - static fromWalletDeeplinkUri(uri: string): IdentityUpdateEnvelope; - static fromQrString(qrstring: string): IdentityUpdateResponse; - static fromJson(json: IdentityUpdateEnvelopeJson): IdentityUpdateResponse; -} diff --git a/dist/vdxf/classes/identity/IdentityUpdateEnvelope.js b/dist/vdxf/classes/identity/IdentityUpdateEnvelope.js deleted file mode 100644 index 4e89f9bb..00000000 --- a/dist/vdxf/classes/identity/IdentityUpdateEnvelope.js +++ /dev/null @@ -1,210 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.IdentityUpdateResponse = exports.IdentityUpdateRequest = exports.IdentityUpdateEnvelope = exports.IDENTITY_UPDATE_VERSION_MASK = exports.IDENTITY_UPDATE_VERSION_SIGNED = exports.IDENTITY_UPDATE_VERSION_LASTVALID = exports.IDENTITY_UPDATE_VERSION_FIRSTVALID = exports.IDENTITY_UPDATE_VERSION_CURRENT = void 0; -const __1 = require("../.."); -const keys_1 = require("../../keys"); -const bufferutils_1 = require("../../../utils/bufferutils"); -const vdxf_1 = require("../../../constants/vdxf"); -const createHash = require("create-hash"); -const base64url_1 = require("base64url"); -const bn_js_1 = require("bn.js"); -const IdentityUpdateRequestDetails_1 = require("./IdentityUpdateRequestDetails"); -const pbaas_1 = require("../../../pbaas"); -const IdentityUpdateResponseDetails_1 = require("./IdentityUpdateResponseDetails"); -exports.IDENTITY_UPDATE_VERSION_CURRENT = new bn_js_1.BN(1, 10); -exports.IDENTITY_UPDATE_VERSION_FIRSTVALID = new bn_js_1.BN(1, 10); -exports.IDENTITY_UPDATE_VERSION_LASTVALID = new bn_js_1.BN(1, 10); -exports.IDENTITY_UPDATE_VERSION_SIGNED = new bn_js_1.BN('80000000', 16); -exports.IDENTITY_UPDATE_VERSION_MASK = exports.IDENTITY_UPDATE_VERSION_SIGNED; -class IdentityUpdateEnvelope extends __1.VDXFObject { - constructor(vdxfkey, request = { - details: undefined - }) { - super(vdxfkey); - if (request.version) - this.version = request.version; - else - this.version = exports.IDENTITY_UPDATE_VERSION_CURRENT; - if (!request.details) { - this.details = this.createEmptyDetails(); - } - this.systemid = request.systemid; - this.signingid = request.signingid; - if (request.signature) { - this.signature = new __1.VerusIDSignature({ signature: request.signature }, keys_1.IDENTITY_AUTH_SIG_VDXF_KEY, false); - this.setSigned(); - } - this.details = request.details; - } - createEmptyDetails() { - if (this.vdxfkey === keys_1.IDENTITY_UPDATE_REQUEST_VDXF_KEY.vdxfid) { - return new IdentityUpdateRequestDetails_1.IdentityUpdateRequestDetails(); - } - else if (this.vdxfkey === keys_1.IDENTITY_UPDATE_RESPONSE_VDXF_KEY.vdxfid) { - return new IdentityUpdateResponseDetails_1.IdentityUpdateResponseDetails(); - } - else - throw new Error("Unrecognized vdxf key for identity update"); - } - getVersionNoFlags() { - return this.version.and(exports.IDENTITY_UPDATE_VERSION_MASK.notn(exports.IDENTITY_UPDATE_VERSION_MASK.bitLength())); - } - isValidVersion() { - return this.getVersionNoFlags().gte(exports.IDENTITY_UPDATE_VERSION_FIRSTVALID) && this.getVersionNoFlags().lte(exports.IDENTITY_UPDATE_VERSION_LASTVALID); - } - isSigned() { - return !!(this.version.and(exports.IDENTITY_UPDATE_VERSION_SIGNED).toNumber()); - } - setSigned() { - this.version = this.version.xor(exports.IDENTITY_UPDATE_VERSION_SIGNED); - } - getDetailsHash(signedBlockheight, signatureVersion = 2) { - if (this.isSigned()) { - var heightBufferWriter = new bufferutils_1.default.BufferWriter(Buffer.allocUnsafe(4)); - heightBufferWriter.writeUInt32(signedBlockheight); - if (signatureVersion === 1) { - return createHash("sha256") - .update(vdxf_1.VERUS_DATA_SIGNATURE_PREFIX) - .update(this.systemid.toBuffer()) - .update(heightBufferWriter.buffer) - .update(this.signingid.toBuffer()) - .update(this.details.toSha256()) - .digest(); - } - else { - return createHash("sha256") - .update(this.systemid.toBuffer()) - .update(heightBufferWriter.buffer) - .update(this.signingid.toBuffer()) - .update(vdxf_1.VERUS_DATA_SIGNATURE_PREFIX) - .update(this.details.toSha256()) - .digest(); - } - } - else - return this.details.toSha256(); - } - _dataByteLength(signer = this.signingid) { - if (this.isSigned()) { - let length = 0; - const _signature = this.signature - ? this.signature - : new __1.VerusIDSignature({ signature: "" }, keys_1.IDENTITY_AUTH_SIG_VDXF_KEY, false); - length += this.systemid.getByteLength(); - length += signer.getByteLength(); - length += _signature.byteLength(); - length += this.details.getByteLength(); - return length; - } - else - return this.details.getByteLength(); - } - _toDataBuffer(signer = this.signingid) { - const writer = new bufferutils_1.default.BufferWriter(Buffer.alloc(this.dataByteLength())); - if (this.isSigned()) { - const _signature = this.signature - ? this.signature - : new __1.VerusIDSignature({ signature: "" }, keys_1.IDENTITY_AUTH_SIG_VDXF_KEY, false); - writer.writeSlice(this.systemid.toBuffer()); - writer.writeSlice(signer.toBuffer()); - writer.writeSlice(_signature.toBuffer()); - } - writer.writeSlice(this.details.toBuffer()); - return writer.buffer; - } - dataByteLength() { - return this._dataByteLength(); - } - toDataBuffer() { - return this._toDataBuffer(); - } - _fromDataBuffer(buffer, offset) { - const reader = new bufferutils_1.default.BufferReader(buffer, offset); - const reqLength = reader.readCompactSize(); - if (reqLength == 0) { - throw new Error("Cannot create request from empty buffer"); - } - else { - if (this.isSigned()) { - this.systemid = new pbaas_1.IdentityID(); - reader.offset = this.systemid.fromBuffer(reader.buffer, reader.offset); - this.signingid = new pbaas_1.IdentityID(); - reader.offset = this.signingid.fromBuffer(reader.buffer, reader.offset); - const _sig = new __1.VerusIDSignature(undefined, keys_1.IDENTITY_AUTH_SIG_VDXF_KEY, false); - reader.offset = _sig.fromBuffer(reader.buffer, reader.offset, keys_1.IDENTITY_AUTH_SIG_VDXF_KEY.vdxfid); - this.signature = _sig; - } - const _details = this.createEmptyDetails(); - reader.offset = _details.fromBuffer(reader.buffer, reader.offset); - this.details = _details; - } - return reader.offset; - } - fromDataBuffer(buffer, offset) { - return this._fromDataBuffer(buffer, offset); - } - toWalletDeeplinkUri() { - return `${__1.WALLET_VDXF_KEY.vdxfid.toLowerCase()}://x-callback-url/${keys_1.IDENTITY_UPDATE_REQUEST_VDXF_KEY.vdxfid}/${this.toString(false)}`; - } - static fromWalletDeeplinkUri(vdxfkey, uri) { - const split = uri.split(`${keys_1.IDENTITY_UPDATE_REQUEST_VDXF_KEY.vdxfid}/`); - const inv = new IdentityUpdateEnvelope(vdxfkey); - inv.fromBuffer(base64url_1.default.toBuffer(split[1]), 0, keys_1.IDENTITY_UPDATE_REQUEST_VDXF_KEY.vdxfid); - return inv; - } - toQrString() { - return this.toString(true); - } - static fromQrString(vdxfkey, qrstring) { - const inv = new IdentityUpdateEnvelope(vdxfkey); - inv.fromBuffer(base64url_1.default.toBuffer(qrstring), 0); - return inv; - } - toJson() { - return { - systemid: this.systemid ? this.systemid.toAddress() : undefined, - signingid: this.signingid ? this.signingid.toAddress() : undefined, - signature: this.signature ? this.signature.signature : undefined, - details: this.details ? this.details.toJson() : undefined - }; - } - static internalFromJson(json, ctor, detailsFromJson) { - return new ctor({ - systemid: json.systemid ? pbaas_1.IdentityID.fromAddress(json.systemid) : undefined, - signingid: json.signingid ? pbaas_1.IdentityID.fromAddress(json.signingid) : undefined, - signature: json.signature, - details: json.details ? detailsFromJson(json.details) : undefined - }); - } -} -exports.IdentityUpdateEnvelope = IdentityUpdateEnvelope; -class IdentityUpdateRequest extends IdentityUpdateEnvelope { - constructor(request) { - super(keys_1.IDENTITY_UPDATE_REQUEST_VDXF_KEY.vdxfid, request); - } - static fromWalletDeeplinkUri(uri) { - return IdentityUpdateEnvelope.fromWalletDeeplinkUri(keys_1.IDENTITY_UPDATE_REQUEST_VDXF_KEY.vdxfid, uri); - } - static fromQrString(qrstring) { - return IdentityUpdateEnvelope.fromQrString(keys_1.IDENTITY_UPDATE_REQUEST_VDXF_KEY.vdxfid, qrstring); - } - static fromJson(json) { - return IdentityUpdateEnvelope.internalFromJson(json, IdentityUpdateRequest, IdentityUpdateRequestDetails_1.IdentityUpdateRequestDetails.fromJson); - } -} -exports.IdentityUpdateRequest = IdentityUpdateRequest; -class IdentityUpdateResponse extends IdentityUpdateEnvelope { - constructor(response) { - super(keys_1.IDENTITY_UPDATE_RESPONSE_VDXF_KEY.vdxfid, response); - } - static fromWalletDeeplinkUri(uri) { - return IdentityUpdateEnvelope.fromWalletDeeplinkUri(keys_1.IDENTITY_UPDATE_RESPONSE_VDXF_KEY.vdxfid, uri); - } - static fromQrString(qrstring) { - return IdentityUpdateEnvelope.fromQrString(keys_1.IDENTITY_UPDATE_RESPONSE_VDXF_KEY.vdxfid, qrstring); - } - static fromJson(json) { - return IdentityUpdateEnvelope.internalFromJson(json, IdentityUpdateResponse, IdentityUpdateResponseDetails_1.IdentityUpdateResponseDetails.fromJson); - } -} -exports.IdentityUpdateResponse = IdentityUpdateResponse; diff --git a/dist/vdxf/classes/identity/IdentityUpdateRequestDetails.d.ts b/dist/vdxf/classes/identity/IdentityUpdateRequestDetails.d.ts index aedfa051..5d1b9eeb 100644 --- a/dist/vdxf/classes/identity/IdentityUpdateRequestDetails.d.ts +++ b/dist/vdxf/classes/identity/IdentityUpdateRequestDetails.d.ts @@ -2,7 +2,6 @@ import { PartialIdentity } from '../../../pbaas/PartialIdentity'; import { PartialSignData, PartialSignDataCLIJson, PartialSignDataJson } from '../../../pbaas/PartialSignData'; import { BigNumber } from '../../../utils/types/BigNumber'; import { ContentMultiMapJsonValue, IdentityID, VerusCLIVerusIDJson, VerusCLIVerusIDJsonBase } from '../../../pbaas'; -import { ResponseUri, ResponseUriJson } from '../ResponseUri'; import { SerializableEntity } from '../../../utils/types/SerializableEntity'; export type SignDataMap = Map; export type VerusCLIVerusIDJsonWithData = VerusCLIVerusIDJsonBase<{ @@ -13,64 +12,49 @@ export type VerusCLIVerusIDJsonWithData = VerusCLIVerusIDJsonBase<{ export type IdentityUpdateRequestDetailsJson = { flags?: string; requestid?: string; - createdat?: string; identity?: VerusCLIVerusIDJson; expiryheight?: string; systemid?: string; - responseuris?: Array; signdatamap?: { [key: string]: PartialSignDataJson; }; - salt?: string; txid?: string; }; export declare class IdentityUpdateRequestDetails implements SerializableEntity { flags?: BigNumber; - requestid?: BigNumber; - createdat?: BigNumber; + requestID?: string; identity?: PartialIdentity; - expiryheight?: BigNumber; - systemid?: IdentityID; - responseuris?: Array; - signdatamap?: SignDataMap; - salt?: Buffer; + expiryHeight?: BigNumber; + systemID?: IdentityID; + signDataMap?: SignDataMap; txid?: Buffer; static IDENTITY_UPDATE_REQUEST_VALID: import("bn.js"); static IDENTITY_UPDATE_REQUEST_CONTAINS_SIGNDATA: import("bn.js"); static IDENTITY_UPDATE_REQUEST_EXPIRES: import("bn.js"); - static IDENTITY_UPDATE_REQUEST_CONTAINS_RESPONSE_URIS: import("bn.js"); + static IDENTITY_UPDATE_REQUEST_CONTAINS_REQUEST_ID: import("bn.js"); static IDENTITY_UPDATE_REQUEST_CONTAINS_SYSTEM: import("bn.js"); static IDENTITY_UPDATE_REQUEST_CONTAINS_TXID: import("bn.js"); - static IDENTITY_UPDATE_REQUEST_CONTAINS_SALT: import("bn.js"); - static IDENTITY_UPDATE_REQUEST_IS_TESTNET: import("bn.js"); constructor(data?: { flags?: BigNumber; - requestid?: BigNumber; - createdat?: BigNumber; + requestID?: string; identity?: PartialIdentity; - expiryheight?: BigNumber; - systemid?: IdentityID; + expiryHeight?: BigNumber; + systemID?: IdentityID; txid?: Buffer; - responseuris?: Array; - signdatamap?: SignDataMap; - salt?: Buffer; + signDataMap?: SignDataMap; }); expires(): boolean; containsSignData(): boolean; containsSystem(): boolean; + containsRequestID(): boolean; containsTxid(): boolean; - containsResponseUris(): boolean; - containsSalt(): boolean; - isTestnet(): boolean; toggleExpires(): void; toggleContainsSignData(): void; toggleContainsSystem(): void; + toggleContainsRequestID(): void; toggleContainsTxid(): void; - toggleContainsResponseUris(): void; - toggleContainsSalt(): void; - toggleIsTestnet(): void; toSha256(): Buffer; - getIdentityAddress(): string; + getIdentityAddress(isTestnet?: boolean): string; getByteLength(): number; toBuffer(): Buffer; fromBuffer(buffer: Buffer, offset?: number, parseVdxfObjects?: boolean): number; diff --git a/dist/vdxf/classes/identity/IdentityUpdateRequestDetails.js b/dist/vdxf/classes/identity/IdentityUpdateRequestDetails.js index 9773525f..47761669 100644 --- a/dist/vdxf/classes/identity/IdentityUpdateRequestDetails.js +++ b/dist/vdxf/classes/identity/IdentityUpdateRequestDetails.js @@ -1,7 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.IdentityUpdateRequestDetails = void 0; -const varint_1 = require("../../../utils/varint"); const varuint_1 = require("../../../utils/varuint"); const bufferutils_1 = require("../../../utils/bufferutils"); const address_1 = require("../../../utils/address"); @@ -11,54 +10,38 @@ const PartialIdentity_1 = require("../../../pbaas/PartialIdentity"); const PartialSignData_1 = require("../../../pbaas/PartialSignData"); const bn_js_1 = require("bn.js"); const pbaas_1 = require("../../../pbaas"); -const ResponseUri_1 = require("../ResponseUri"); const pbaas_2 = require("../../../constants/pbaas"); const { BufferReader, BufferWriter } = bufferutils_1.default; class IdentityUpdateRequestDetails { constructor(data) { this.flags = data && data.flags ? data.flags : new bn_js_1.BN("0", 10); - if (data === null || data === void 0 ? void 0 : data.requestid) { - this.requestid = data.requestid; + if (data === null || data === void 0 ? void 0 : data.requestID) { + if (!this.containsRequestID()) + this.toggleContainsRequestID(); + this.requestID = data.requestID; } - else - this.requestid = new bn_js_1.BN("0", 10); - if (data === null || data === void 0 ? void 0 : data.createdat) { - this.createdat = data.createdat; - } - else - this.createdat = new bn_js_1.BN("0", 10); if (data === null || data === void 0 ? void 0 : data.identity) { this.identity = data.identity; } - if (data === null || data === void 0 ? void 0 : data.expiryheight) { + if (data === null || data === void 0 ? void 0 : data.expiryHeight) { if (!this.expires()) this.toggleExpires(); - this.expiryheight = data.expiryheight; + this.expiryHeight = data.expiryHeight; } - if (data === null || data === void 0 ? void 0 : data.systemid) { + if (data === null || data === void 0 ? void 0 : data.systemID) { if (!this.containsSystem()) this.toggleContainsSystem(); - this.systemid = data.systemid; + this.systemID = data.systemID; } if (data === null || data === void 0 ? void 0 : data.txid) { if (!this.containsTxid()) this.toggleContainsTxid(); this.txid = data.txid; } - if (data === null || data === void 0 ? void 0 : data.responseuris) { - if (!this.containsResponseUris()) - this.toggleContainsResponseUris(); - this.responseuris = data.responseuris; - } - if (data === null || data === void 0 ? void 0 : data.signdatamap) { + if (data === null || data === void 0 ? void 0 : data.signDataMap) { if (!this.containsSignData()) this.toggleContainsSignData(); - this.signdatamap = data.signdatamap; - } - if (data === null || data === void 0 ? void 0 : data.salt) { - if (!this.containsSalt()) - this.toggleContainsSalt(); - this.salt = data.salt; + this.signDataMap = data.signDataMap; } } expires() { @@ -70,18 +53,12 @@ class IdentityUpdateRequestDetails { containsSystem() { return !!(this.flags.and(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_SYSTEM).toNumber()); } + containsRequestID() { + return !!(this.flags.and(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_REQUEST_ID).toNumber()); + } containsTxid() { return !!(this.flags.and(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_TXID).toNumber()); } - containsResponseUris() { - return !!(this.flags.and(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_RESPONSE_URIS).toNumber()); - } - containsSalt() { - return !!(this.flags.and(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_SALT).toNumber()); - } - isTestnet() { - return !!(this.flags.and(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_IS_TESTNET).toNumber()); - } toggleExpires() { this.flags = this.flags.xor(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_EXPIRES); } @@ -91,29 +68,23 @@ class IdentityUpdateRequestDetails { toggleContainsSystem() { this.flags = this.flags.xor(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_SYSTEM); } + toggleContainsRequestID() { + this.flags = this.flags.xor(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_REQUEST_ID); + } toggleContainsTxid() { this.flags = this.flags.xor(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_TXID); } - toggleContainsResponseUris() { - this.flags = this.flags.xor(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_RESPONSE_URIS); - } - toggleContainsSalt() { - this.flags = this.flags.xor(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_SALT); - } - toggleIsTestnet() { - this.flags = this.flags.xor(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_IS_TESTNET); - } toSha256() { return createHash("sha256").update(this.toBuffer()).digest(); } - getIdentityAddress() { + getIdentityAddress(isTestnet = false) { if (this.identity.name === "VRSC" || this.identity.name === "VRSCTEST") { return (0, address_1.nameAndParentAddrToIAddr)(this.identity.name); } else if (this.identity.parent) { return this.identity.getIdentityAddress(); } - else if (this.isTestnet()) { + else if (isTestnet) { return (0, address_1.nameAndParentAddrToIAddr)(this.identity.name, (0, address_1.nameAndParentAddrToIAddr)("VRSCTEST")); } else { @@ -122,144 +93,115 @@ class IdentityUpdateRequestDetails { } getByteLength() { let length = 0; - length += varint_1.default.encodingLength(this.flags); - length += varint_1.default.encodingLength(this.requestid); - length += varint_1.default.encodingLength(this.createdat); + length += varuint_1.default.encodingLength(this.flags.toNumber()); + if (this.containsRequestID()) { + length += vdxf_1.HASH160_BYTE_LENGTH; + } length += this.identity.getByteLength(); if (this.expires()) - length += varint_1.default.encodingLength(this.expiryheight); + length += varuint_1.default.encodingLength(this.expiryHeight.toNumber()); if (this.containsSystem()) - length += this.systemid.getByteLength(); + length += this.systemID.getByteLength(); if (this.containsTxid()) { length += pbaas_2.UINT_256_LENGTH; } - if (this.containsResponseUris()) { - length += varuint_1.default.encodingLength(this.responseuris.length); - length += this.responseuris.reduce((sum, current) => sum + current.getByteLength(), 0); - } if (this.containsSignData()) { - length += varuint_1.default.encodingLength(this.signdatamap.size); - for (const [key, value] of this.signdatamap.entries()) { + length += varuint_1.default.encodingLength(this.signDataMap.size); + for (const [key, value] of this.signDataMap.entries()) { length += (0, address_1.fromBase58Check)(key).hash.length; length += value.getByteLength(); } } - if (this.containsSalt()) { - length += varuint_1.default.encodingLength(this.salt.length); - length += this.salt.length; - } return length; } toBuffer() { const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); - writer.writeVarInt(this.flags); - writer.writeVarInt(this.requestid); - writer.writeVarInt(this.createdat); + writer.writeCompactSize(this.flags.toNumber()); + if (this.containsRequestID()) { + writer.writeSlice((0, address_1.fromBase58Check)(this.requestID).hash); + } writer.writeSlice(this.identity.toBuffer()); if (this.expires()) - writer.writeVarInt(this.expiryheight); + writer.writeCompactSize(this.expiryHeight.toNumber()); if (this.containsSystem()) - writer.writeSlice(this.systemid.toBuffer()); + writer.writeSlice(this.systemID.toBuffer()); if (this.containsTxid()) { if (this.txid.length !== pbaas_2.UINT_256_LENGTH) throw new Error("invalid txid length"); writer.writeSlice(this.txid); } - if (this.containsResponseUris()) { - writer.writeArray(this.responseuris.map((x) => x.toBuffer())); - } if (this.containsSignData()) { - writer.writeCompactSize(this.signdatamap.size); - for (const [key, value] of this.signdatamap.entries()) { + writer.writeCompactSize(this.signDataMap.size); + for (const [key, value] of this.signDataMap.entries()) { writer.writeSlice((0, address_1.fromBase58Check)(key).hash); writer.writeSlice(value.toBuffer()); } } - if (this.containsSalt()) { - writer.writeVarSlice(this.salt); - } return writer.buffer; } fromBuffer(buffer, offset = 0, parseVdxfObjects = true) { const reader = new BufferReader(buffer, offset); - this.flags = reader.readVarInt(); - this.requestid = reader.readVarInt(); - this.createdat = reader.readVarInt(); + this.flags = new bn_js_1.BN(reader.readCompactSize()); + if (this.containsRequestID()) { + this.requestID = (0, address_1.toBase58Check)(reader.readSlice(vdxf_1.HASH160_BYTE_LENGTH), vdxf_1.I_ADDR_VERSION); + } this.identity = new PartialIdentity_1.PartialIdentity(); reader.offset = this.identity.fromBuffer(reader.buffer, reader.offset, parseVdxfObjects); if (this.expires()) { - this.expiryheight = reader.readVarInt(); + this.expiryHeight = new bn_js_1.BN(reader.readCompactSize()); } if (this.containsSystem()) { - this.systemid = new pbaas_1.IdentityID(); - reader.offset = this.systemid.fromBuffer(reader.buffer, reader.offset); + this.systemID = new pbaas_1.IdentityID(); + reader.offset = this.systemID.fromBuffer(reader.buffer, reader.offset); } if (this.containsTxid()) { this.txid = reader.readSlice(pbaas_2.UINT_256_LENGTH); } - if (this.containsResponseUris()) { - this.responseuris = []; - const urisLength = reader.readCompactSize(); - for (let i = 0; i < urisLength; i++) { - const uri = new ResponseUri_1.ResponseUri(); - reader.offset = uri.fromBuffer(reader.buffer, reader.offset); - this.responseuris.push(uri); - } - } if (this.containsSignData()) { - this.signdatamap = new Map(); + this.signDataMap = new Map(); const size = reader.readCompactSize(); for (let i = 0; i < size; i++) { const key = (0, address_1.toBase58Check)(reader.readSlice(vdxf_1.HASH160_BYTE_LENGTH), vdxf_1.I_ADDR_VERSION); const value = new PartialSignData_1.PartialSignData(); reader.offset = value.fromBuffer(reader.buffer, reader.offset); - this.signdatamap.set(key, value); + this.signDataMap.set(key, value); } } - if (this.containsSalt()) { - this.salt = reader.readVarSlice(); - } return reader.offset; } toJson() { let signDataJson; - if (this.signdatamap) { + if (this.signDataMap) { signDataJson = {}; - for (const [key, psd] of this.signdatamap.entries()) { + for (const [key, psd] of this.signDataMap.entries()) { signDataJson[key] = psd.toJson(); } } return { flags: this.flags ? this.flags.toString(10) : undefined, - requestid: this.requestid ? this.requestid.toString(10) : undefined, - createdat: this.createdat ? this.createdat.toString(10) : undefined, + requestid: this.containsRequestID() ? this.requestID : undefined, identity: this.identity ? this.identity.toJson() : undefined, - expiryheight: this.expiryheight ? this.expiryheight.toString(10) : undefined, - systemid: this.systemid ? this.systemid.toAddress() : undefined, + expiryheight: this.expiryHeight ? this.expiryHeight.toString(10) : undefined, + systemid: this.systemID ? this.systemID.toAddress() : undefined, txid: this.txid ? (Buffer.from(this.txid.toString('hex'), 'hex').reverse()).toString('hex') : undefined, - responseuris: this.responseuris ? this.responseuris.map(x => x.toJson()) : undefined, - signdatamap: signDataJson, - salt: this.salt ? this.salt.toString('hex') : undefined + signdatamap: signDataJson }; } static fromJson(json) { - let signdatamap; + let signDataMap; if (json.signdatamap) { - signdatamap = new Map(); + signDataMap = new Map(); for (const key in json.signdatamap) { - signdatamap.set(key, PartialSignData_1.PartialSignData.fromJson(json.signdatamap[key])); + signDataMap.set(key, PartialSignData_1.PartialSignData.fromJson(json.signdatamap[key])); } } return new IdentityUpdateRequestDetails({ flags: json.flags ? new bn_js_1.BN(json.flags, 10) : undefined, - requestid: json.requestid ? new bn_js_1.BN(json.requestid, 10) : undefined, - createdat: json.createdat ? new bn_js_1.BN(json.createdat, 10) : undefined, + requestID: json.requestid, identity: json.identity ? PartialIdentity_1.PartialIdentity.fromJson(json.identity) : undefined, - expiryheight: json.expiryheight ? new bn_js_1.BN(json.expiryheight, 10) : undefined, - systemid: json.systemid ? pbaas_1.IdentityID.fromAddress(json.systemid) : undefined, - responseuris: json.responseuris ? json.responseuris.map(x => ResponseUri_1.ResponseUri.fromJson(x)) : undefined, - signdatamap, - salt: json.salt ? Buffer.from(json.salt, 'hex') : undefined, + expiryHeight: json.expiryheight ? new bn_js_1.BN(json.expiryheight, 10) : undefined, + systemID: json.systemid ? pbaas_1.IdentityID.fromAddress(json.systemid) : undefined, + signDataMap, txid: json.txid ? Buffer.from(json.txid, 'hex').reverse() : undefined, }); } @@ -268,7 +210,7 @@ class IdentityUpdateRequestDetails { throw new Error("No identity details to update"); const idJson = this.identity.toJson(); if (this.containsSignData()) { - for (const [key, psd] of this.signdatamap.entries()) { + for (const [key, psd] of this.signDataMap.entries()) { idJson.contentmultimap[key] = { "data": psd.toCLIJson() }; @@ -278,15 +220,15 @@ class IdentityUpdateRequestDetails { } static fromCLIJson(json, details) { let identity; - let signdatamap; + let signDataMap; if (json.contentmultimap) { const cmm = Object.assign({}, json.contentmultimap); for (const key in cmm) { if (cmm[key]['data']) { - if (!signdatamap) - signdatamap = new Map(); + if (!signDataMap) + signDataMap = new Map(); const psd = PartialSignData_1.PartialSignData.fromCLIJson(cmm[key]['data']); - signdatamap.set(key, psd); + signDataMap.set(key, psd); delete cmm[key]; } } @@ -295,13 +237,10 @@ class IdentityUpdateRequestDetails { identity = PartialIdentity_1.PartialIdentity.fromJson(json); return new IdentityUpdateRequestDetails({ identity, - signdatamap, - systemid: (details === null || details === void 0 ? void 0 : details.systemid) ? pbaas_1.IdentityID.fromAddress(details.systemid) : undefined, - requestid: (details === null || details === void 0 ? void 0 : details.requestid) ? new bn_js_1.BN(details.requestid, 10) : undefined, - createdat: (details === null || details === void 0 ? void 0 : details.createdat) ? new bn_js_1.BN(details.createdat, 10) : undefined, - expiryheight: (details === null || details === void 0 ? void 0 : details.expiryheight) ? new bn_js_1.BN(details.expiryheight, 10) : undefined, - responseuris: (details === null || details === void 0 ? void 0 : details.responseuris) ? details.responseuris.map(x => ResponseUri_1.ResponseUri.fromJson(x)) : undefined, - salt: (details === null || details === void 0 ? void 0 : details.salt) ? Buffer.from(details.salt, 'hex') : undefined, + signDataMap, + systemID: (details === null || details === void 0 ? void 0 : details.systemid) ? pbaas_1.IdentityID.fromAddress(details.systemid) : undefined, + requestID: details === null || details === void 0 ? void 0 : details.requestid, + expiryHeight: (details === null || details === void 0 ? void 0 : details.expiryheight) ? new bn_js_1.BN(details.expiryheight, 10) : undefined, txid: (details === null || details === void 0 ? void 0 : details.txid) ? Buffer.from(details.txid, 'hex').reverse() : undefined, }); } @@ -311,8 +250,6 @@ exports.IdentityUpdateRequestDetails = IdentityUpdateRequestDetails; IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_VALID = new bn_js_1.BN(0, 10); IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_SIGNDATA = new bn_js_1.BN(1, 10); IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_EXPIRES = new bn_js_1.BN(2, 10); -IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_RESPONSE_URIS = new bn_js_1.BN(4, 10); +IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_REQUEST_ID = new bn_js_1.BN(4, 10); IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_SYSTEM = new bn_js_1.BN(8, 10); IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_TXID = new bn_js_1.BN(16, 10); -IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_SALT = new bn_js_1.BN(32, 10); -IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_IS_TESTNET = new bn_js_1.BN(64, 10); diff --git a/dist/vdxf/classes/identity/IdentityUpdateResponseDetails.d.ts b/dist/vdxf/classes/identity/IdentityUpdateResponseDetails.d.ts index 88049967..eb319c96 100644 --- a/dist/vdxf/classes/identity/IdentityUpdateResponseDetails.d.ts +++ b/dist/vdxf/classes/identity/IdentityUpdateResponseDetails.d.ts @@ -3,30 +3,23 @@ import { SerializableEntity } from '../../../utils/types/SerializableEntity'; export type IdentityUpdateResponseDetailsJson = { flags: string; requestid: string; - createdat: string; txid?: string; - salt?: string; }; export declare class IdentityUpdateResponseDetails implements SerializableEntity { flags?: BigNumber; - requestid?: BigNumber; - createdat?: BigNumber; + requestID?: string; txid?: Buffer; - salt?: Buffer; - static IDENTITY_UPDATE_RESPONSE_VALID: import("bn.js"); static IDENTITY_UPDATE_RESPONSE_CONTAINS_TXID: import("bn.js"); - static IDENTITY_UPDATE_RESPONSE_CONTAINS_SALT: import("bn.js"); + static IDENTITY_UPDATE_RESPONSE_CONTAINS_REQUEST_ID: import("bn.js"); constructor(data?: { flags?: BigNumber; - requestid?: BigNumber; - createdat?: BigNumber; + requestID?: string; txid?: Buffer; - salt?: Buffer; }); containsTxid(): boolean; - containsSalt(): boolean; + containsRequestID(): boolean; toggleContainsTxid(): void; - toggleContainsSalt(): void; + toggleContainsRequestID(): void; toSha256(): Buffer; getByteLength(): number; toBuffer(): Buffer; diff --git a/dist/vdxf/classes/identity/IdentityUpdateResponseDetails.js b/dist/vdxf/classes/identity/IdentityUpdateResponseDetails.js index f17fc8b5..c677b35a 100644 --- a/dist/vdxf/classes/identity/IdentityUpdateResponseDetails.js +++ b/dist/vdxf/classes/identity/IdentityUpdateResponseDetails.js @@ -6,41 +6,34 @@ const bufferutils_1 = require("../../../utils/bufferutils"); const createHash = require("create-hash"); const bn_js_1 = require("bn.js"); const pbaas_1 = require("../../../constants/pbaas"); -const varuint_1 = require("../../../utils/varuint"); +const vdxf_1 = require("../../../constants/vdxf"); +const address_1 = require("../../../utils/address"); const { BufferReader, BufferWriter } = bufferutils_1.default; class IdentityUpdateResponseDetails { constructor(data) { this.flags = data && data.flags ? data.flags : new bn_js_1.BN("0", 10); - if (data === null || data === void 0 ? void 0 : data.requestid) { - this.requestid = data.requestid; - } - else - this.requestid = new bn_js_1.BN("0", 10); - if (data === null || data === void 0 ? void 0 : data.createdat) { - this.createdat = data.createdat; + if (data === null || data === void 0 ? void 0 : data.requestID) { + if (!this.containsRequestID()) + this.toggleContainsRequestID(); + this.requestID = data.requestID; } if (data === null || data === void 0 ? void 0 : data.txid) { if (!this.containsTxid()) this.toggleContainsTxid(); this.txid = data.txid; } - if (data === null || data === void 0 ? void 0 : data.salt) { - if (!this.containsSalt()) - this.toggleContainsSalt(); - this.salt = data.salt; - } } containsTxid() { return !!(this.flags.and(IdentityUpdateResponseDetails.IDENTITY_UPDATE_RESPONSE_CONTAINS_TXID).toNumber()); } - containsSalt() { - return !!(this.flags.and(IdentityUpdateResponseDetails.IDENTITY_UPDATE_RESPONSE_CONTAINS_SALT).toNumber()); + containsRequestID() { + return !!(this.flags.and(IdentityUpdateResponseDetails.IDENTITY_UPDATE_RESPONSE_CONTAINS_REQUEST_ID).toNumber()); } toggleContainsTxid() { this.flags = this.flags.xor(IdentityUpdateResponseDetails.IDENTITY_UPDATE_RESPONSE_CONTAINS_TXID); } - toggleContainsSalt() { - this.flags = this.flags.xor(IdentityUpdateResponseDetails.IDENTITY_UPDATE_RESPONSE_CONTAINS_SALT); + toggleContainsRequestID() { + this.flags = this.flags.xor(IdentityUpdateResponseDetails.IDENTITY_UPDATE_RESPONSE_CONTAINS_REQUEST_ID); } toSha256() { return createHash("sha256").update(this.toBuffer()).digest(); @@ -48,66 +41,54 @@ class IdentityUpdateResponseDetails { getByteLength() { let length = 0; length += varint_1.default.encodingLength(this.flags); - length += varint_1.default.encodingLength(this.requestid); - length += varint_1.default.encodingLength(this.createdat); + if (this.containsRequestID()) { + length += vdxf_1.HASH160_BYTE_LENGTH; + } if (this.containsTxid()) { length += pbaas_1.UINT_256_LENGTH; } - if (this.containsSalt()) { - const saltLen = this.salt.length; - length += varuint_1.default.encodingLength(saltLen); - length += saltLen; - } return length; } toBuffer() { const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); writer.writeVarInt(this.flags); - writer.writeVarInt(this.requestid); - writer.writeVarInt(this.createdat); + if (this.containsRequestID()) { + writer.writeSlice((0, address_1.fromBase58Check)(this.requestID).hash); + } if (this.containsTxid()) { if (this.txid.length !== pbaas_1.UINT_256_LENGTH) throw new Error("invalid txid length"); writer.writeSlice(this.txid); } - if (this.containsSalt()) { - writer.writeVarSlice(this.salt); - } return writer.buffer; } fromBuffer(buffer, offset = 0) { const reader = new BufferReader(buffer, offset); this.flags = reader.readVarInt(); - this.requestid = reader.readVarInt(); - this.createdat = reader.readVarInt(); + if (this.containsRequestID()) { + this.requestID = (0, address_1.toBase58Check)(reader.readSlice(vdxf_1.HASH160_BYTE_LENGTH), vdxf_1.I_ADDR_VERSION); + } if (this.containsTxid()) { this.txid = reader.readSlice(pbaas_1.UINT_256_LENGTH); } - if (this.containsSalt()) { - this.salt = reader.readVarSlice(); - } return reader.offset; } toJson() { return { flags: this.flags.toString(10), - requestid: this.requestid.toString(10), - createdat: this.createdat.toString(10), - txid: this.containsTxid() ? (Buffer.from(this.txid.toString('hex'), 'hex').reverse()).toString('hex') : undefined, - salt: this.containsSalt() ? this.salt.toString('hex') : undefined + requestid: this.containsRequestID() ? this.requestID : undefined, + txid: this.containsTxid() ? (Buffer.from(this.txid.toString('hex'), 'hex').reverse()).toString('hex') : undefined }; } static fromJson(json) { return new IdentityUpdateResponseDetails({ flags: new bn_js_1.BN(json.flags, 10), - requestid: new bn_js_1.BN(json.requestid, 10), - createdat: new bn_js_1.BN(json.createdat, 10), - txid: json.txid ? Buffer.from(json.txid, 'hex').reverse() : undefined, - salt: json.salt ? Buffer.from(json.salt, 'hex') : undefined + requestID: json.requestid, + txid: json.txid ? Buffer.from(json.txid, 'hex').reverse() : undefined }); } } exports.IdentityUpdateResponseDetails = IdentityUpdateResponseDetails; -IdentityUpdateResponseDetails.IDENTITY_UPDATE_RESPONSE_VALID = new bn_js_1.BN(0, 10); +// stored in natural order, if displayed as text make sure to reverse! IdentityUpdateResponseDetails.IDENTITY_UPDATE_RESPONSE_CONTAINS_TXID = new bn_js_1.BN(1, 10); -IdentityUpdateResponseDetails.IDENTITY_UPDATE_RESPONSE_CONTAINS_SALT = new bn_js_1.BN(2, 10); +IdentityUpdateResponseDetails.IDENTITY_UPDATE_RESPONSE_CONTAINS_REQUEST_ID = new bn_js_1.BN(2, 10); diff --git a/dist/vdxf/classes/index.d.ts b/dist/vdxf/classes/index.d.ts index f9f49eb1..47371ba7 100644 --- a/dist/vdxf/classes/index.d.ts +++ b/dist/vdxf/classes/index.d.ts @@ -20,12 +20,23 @@ export { ProvisioningChallengeInterface as LoginConsentProvisioningChallengeInte export { ProvisioningResponseInterface as LoginConsentProvisioningResponseInterface } from "./provisioning/ProvisioningResponse"; export { ProvisioningDecisionInterface as LoginConsentProvisioningDecisionInterface } from "./provisioning/ProvisioningDecision"; export { ProvisioningResultInterface as LoginConsentProvisioningResultInterface } from "./provisioning/ProvisioningResult"; -export * from "./identity/IdentityUpdateEnvelope"; export * from "./identity/IdentityUpdateRequestDetails"; export * from "./identity/IdentityUpdateResponseDetails"; -export * from './ResponseUri'; +export * from './ResponseURI'; +export * from './request/GenericRequest'; +export * from './response/GenericResponse'; +export * from './appencryption/AppEncryptionResponseDetails'; +export * from './ordinals'; export { Hash160 } from './Hash160'; export { RedirectUri, Subject, ProvisioningInfo, RequestedPermission, Audience, AltAuthFactor, Attestation, } from "./Challenge"; export { ProvisioningTxid } from './provisioning/ProvisioningResult'; export { Context } from './Context'; export { DataCategory } from './PersonalProfile'; +export * from './requestobjects/UserDataRequestDetails'; +export * from './login/AuthenticationRequestDetails'; +export * from './login/AuthenticationResponseDetails'; +export * from './requestobjects/ProvisionIdentityDetails'; +export * from './appencryption/AppEncryptionRequestDetails'; +export * from './requestobjects/UserSpecificDataPacketDetails'; +export * from './CompactAddressObject'; +export * from './VerifiableSignatureData'; diff --git a/dist/vdxf/classes/index.js b/dist/vdxf/classes/index.js index 09e87339..e21fde43 100644 --- a/dist/vdxf/classes/index.js +++ b/dist/vdxf/classes/index.js @@ -41,10 +41,13 @@ var ProvisioningDecision_1 = require("./provisioning/ProvisioningDecision"); Object.defineProperty(exports, "LoginConsentProvisioningDecision", { enumerable: true, get: function () { return ProvisioningDecision_1.ProvisioningDecision; } }); var ProvisioningResult_1 = require("./provisioning/ProvisioningResult"); Object.defineProperty(exports, "LoginConsentProvisioningResult", { enumerable: true, get: function () { return ProvisioningResult_1.ProvisioningResult; } }); -__exportStar(require("./identity/IdentityUpdateEnvelope"), exports); __exportStar(require("./identity/IdentityUpdateRequestDetails"), exports); __exportStar(require("./identity/IdentityUpdateResponseDetails"), exports); -__exportStar(require("./ResponseUri"), exports); +__exportStar(require("./ResponseURI"), exports); +__exportStar(require("./request/GenericRequest"), exports); +__exportStar(require("./response/GenericResponse"), exports); +__exportStar(require("./appencryption/AppEncryptionResponseDetails"), exports); +__exportStar(require("./ordinals"), exports); var Hash160_1 = require("./Hash160"); Object.defineProperty(exports, "Hash160", { enumerable: true, get: function () { return Hash160_1.Hash160; } }); var Challenge_2 = require("./Challenge"); @@ -61,3 +64,11 @@ var Context_1 = require("./Context"); Object.defineProperty(exports, "Context", { enumerable: true, get: function () { return Context_1.Context; } }); var PersonalProfile_1 = require("./PersonalProfile"); Object.defineProperty(exports, "DataCategory", { enumerable: true, get: function () { return PersonalProfile_1.DataCategory; } }); +__exportStar(require("./requestobjects/UserDataRequestDetails"), exports); +__exportStar(require("./login/AuthenticationRequestDetails"), exports); +__exportStar(require("./login/AuthenticationResponseDetails"), exports); +__exportStar(require("./requestobjects/ProvisionIdentityDetails"), exports); +__exportStar(require("./appencryption/AppEncryptionRequestDetails"), exports); +__exportStar(require("./requestobjects/UserSpecificDataPacketDetails"), exports); +__exportStar(require("./CompactAddressObject"), exports); +__exportStar(require("./VerifiableSignatureData"), exports); diff --git a/dist/vdxf/classes/login/AuthenticationRequestDetails.d.ts b/dist/vdxf/classes/login/AuthenticationRequestDetails.d.ts new file mode 100644 index 00000000..6cfa2244 --- /dev/null +++ b/dist/vdxf/classes/login/AuthenticationRequestDetails.d.ts @@ -0,0 +1,61 @@ +/** + * AuthenticationRequestDetails - Class for handling application login and authentication requests + * + * This class is used when an application is requesting authentication or login from the user, + * including specific recipientConstraints and callback information. The request includes: + * - Request ID for tracking the authentication session + * - Permission sets defining what access the application is requesting + * - Optional expiry time for the authentication session + * + * The user's wallet can use these parameters to present a clear authentication request + * to the user, showing exactly what recipientConstraints are being requested and where they will + * be redirected after successful authentication. This enables secure, user-controlled + * authentication flows with granular permission management. + */ +import { BigNumber } from "../../../utils/types/BigNumber"; +import { SerializableEntity } from "../../../utils/types/SerializableEntity"; +import { CompactIAddressObject, CompactAddressObjectJson } from "../CompactAddressObject"; +export interface AuthenticationRequestDetailsInterface { + flags?: BigNumber; + requestID?: CompactIAddressObject; + recipientConstraints?: Array; + expiryTime?: BigNumber; +} +export interface RecipientConstraintJson { + type: number; + identity: CompactAddressObjectJson; +} +export interface RecipientConstraint { + type: number; + identity: CompactIAddressObject; +} +export interface AuthenticationRequestDetailsJson { + requestid?: CompactAddressObjectJson; + flags: number; + recipientconstraints?: Array; + expirytime?: number; +} +export declare class AuthenticationRequestDetails implements SerializableEntity { + flags?: BigNumber; + requestID?: CompactIAddressObject; + recipientConstraints?: Array; + expiryTime?: BigNumber; + static FLAG_HAS_REQUEST_ID: import("bn.js"); + static FLAG_HAS_RECIPIENT_CONSTRAINTS: import("bn.js"); + static FLAG_HAS_EXPIRY_TIME: import("bn.js"); + static REQUIRED_ID: number; + static REQUIRED_SYSTEM: number; + static REQUIRED_PARENT: number; + constructor(request?: AuthenticationRequestDetailsInterface); + hasRequestID(): boolean; + hasRecipentConstraints(): boolean; + hasExpiryTime(): boolean; + calcFlags(flags?: BigNumber): BigNumber; + getByteLength(): number; + toBuffer(): Buffer; + fromBuffer(buffer: Buffer, offset?: number): number; + toJson(): AuthenticationRequestDetailsJson; + static fromJson(data: AuthenticationRequestDetailsJson): AuthenticationRequestDetails; + setFlags(): void; + isValid(): boolean; +} diff --git a/dist/vdxf/classes/login/AuthenticationRequestDetails.js b/dist/vdxf/classes/login/AuthenticationRequestDetails.js new file mode 100644 index 00000000..7dbfbe2c --- /dev/null +++ b/dist/vdxf/classes/login/AuthenticationRequestDetails.js @@ -0,0 +1,168 @@ +"use strict"; +/** + * AuthenticationRequestDetails - Class for handling application login and authentication requests + * + * This class is used when an application is requesting authentication or login from the user, + * including specific recipientConstraints and callback information. The request includes: + * - Request ID for tracking the authentication session + * - Permission sets defining what access the application is requesting + * - Optional expiry time for the authentication session + * + * The user's wallet can use these parameters to present a clear authentication request + * to the user, showing exactly what recipientConstraints are being requested and where they will + * be redirected after successful authentication. This enables secure, user-controlled + * authentication flows with granular permission management. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AuthenticationRequestDetails = void 0; +const bufferutils_1 = require("../../../utils/bufferutils"); +const bn_js_1 = require("bn.js"); +const varuint_1 = require("../../../utils/varuint"); +const CompactAddressObject_1 = require("../CompactAddressObject"); +class AuthenticationRequestDetails { + constructor(request) { + this.flags = (request === null || request === void 0 ? void 0 : request.flags) || new bn_js_1.BN(0, 10); + this.requestID = (request === null || request === void 0 ? void 0 : request.requestID) || null; + this.recipientConstraints = (request === null || request === void 0 ? void 0 : request.recipientConstraints) || null; + this.expiryTime = (request === null || request === void 0 ? void 0 : request.expiryTime) || null; + this.setFlags(); + } + hasRequestID() { + return this.flags.and(AuthenticationRequestDetails.FLAG_HAS_REQUEST_ID).eq(AuthenticationRequestDetails.FLAG_HAS_REQUEST_ID); + } + hasRecipentConstraints() { + return this.flags.and(AuthenticationRequestDetails.FLAG_HAS_RECIPIENT_CONSTRAINTS).eq(AuthenticationRequestDetails.FLAG_HAS_RECIPIENT_CONSTRAINTS); + } + hasExpiryTime() { + return this.flags.and(AuthenticationRequestDetails.FLAG_HAS_EXPIRY_TIME).eq(AuthenticationRequestDetails.FLAG_HAS_EXPIRY_TIME); + } + calcFlags(flags = this.flags) { + if (this.requestID) { + flags = flags.or(AuthenticationRequestDetails.FLAG_HAS_REQUEST_ID); + } + if (this.recipientConstraints) { + flags = flags.or(AuthenticationRequestDetails.FLAG_HAS_RECIPIENT_CONSTRAINTS); + } + if (this.expiryTime) { + flags = flags.or(AuthenticationRequestDetails.FLAG_HAS_EXPIRY_TIME); + } + return flags; + } + getByteLength() { + let length = 0; + length += varuint_1.default.encodingLength(this.flags.toNumber()); + if (this.hasRequestID()) { + length += this.requestID.getByteLength(); + } + if (this.hasRecipentConstraints()) { + length += varuint_1.default.encodingLength(this.recipientConstraints.length); + for (let i = 0; i < this.recipientConstraints.length; i++) { + length += varuint_1.default.encodingLength(this.recipientConstraints[i].type); + length += this.recipientConstraints[i].identity.getByteLength(); + } + } + if (this.hasExpiryTime()) { + length += varuint_1.default.encodingLength(this.expiryTime.toNumber()); + } + return length; + } + toBuffer() { + const writer = new bufferutils_1.default.BufferWriter(Buffer.alloc(this.getByteLength())); + writer.writeCompactSize(this.flags.toNumber()); + if (this.hasRequestID()) { + writer.writeSlice(this.requestID.toBuffer()); + } + if (this.hasRecipentConstraints()) { + writer.writeCompactSize(this.recipientConstraints.length); + for (let i = 0; i < this.recipientConstraints.length; i++) { + writer.writeCompactSize(this.recipientConstraints[i].type); + writer.writeSlice(this.recipientConstraints[i].identity.toBuffer()); + } + } + if (this.hasExpiryTime()) { + writer.writeCompactSize(this.expiryTime.toNumber()); + } + return writer.buffer; + } + fromBuffer(buffer, offset) { + const reader = new bufferutils_1.default.BufferReader(buffer, offset); + this.flags = new bn_js_1.BN(reader.readCompactSize()); + if (this.hasRequestID()) { + this.requestID = new CompactAddressObject_1.CompactIAddressObject(); + reader.offset = this.requestID.fromBuffer(reader.buffer, reader.offset); + } + if (this.hasRecipentConstraints()) { + this.recipientConstraints = []; + const recipientConstraintsLength = reader.readCompactSize(); + for (let i = 0; i < recipientConstraintsLength; i++) { + const compactId = new CompactAddressObject_1.CompactIAddressObject(); + const type = reader.readCompactSize(); + const identityOffset = reader.offset; + reader.offset = compactId.fromBuffer(buffer, identityOffset); + this.recipientConstraints.push({ + type: type, + identity: compactId + }); + } + } + if (this.hasExpiryTime()) { + this.expiryTime = new bn_js_1.BN(reader.readCompactSize()); + } + return reader.offset; + } + toJson() { + const flags = this.calcFlags(); + const retval = { + flags: flags.toNumber(), + requestid: this.requestID.toJson(), + recipientConstraints: this.recipientConstraints ? this.recipientConstraints.map(p => ({ type: p.type, + identity: p.identity.toJson() })) : undefined, + expirytime: this.expiryTime ? this.expiryTime.toNumber() : undefined + }; + return retval; + } + static fromJson(data) { + const loginDetails = new AuthenticationRequestDetails(); + loginDetails.flags = new bn_js_1.BN((data === null || data === void 0 ? void 0 : data.flags) || 0); + loginDetails.requestID = CompactAddressObject_1.CompactIAddressObject.fromCompactAddressObjectJson(data.requestid); + if (loginDetails.hasRecipentConstraints() && data.recipientconstraints) { + loginDetails.recipientConstraints = data.recipientconstraints.map(p => ({ type: p.type, + identity: CompactAddressObject_1.CompactIAddressObject.fromCompactAddressObjectJson(p.identity) })); + } + if (loginDetails.hasExpiryTime() && data.expirytime) { + loginDetails.expiryTime = new bn_js_1.BN(data.expirytime); + } + return loginDetails; + } + setFlags() { + this.flags = this.calcFlags(); + } + isValid() { + let valid = true; + valid && (valid = this.flags != null && this.flags.gte(new bn_js_1.BN(0))); + if (this.hasRequestID()) { + if (!this.requestID || !this.requestID.isValid()) { + return false; + } + } + if (this.hasRecipentConstraints()) { + if (!this.recipientConstraints || this.recipientConstraints.length === 0) { + return false; + } + } + if (this.hasExpiryTime()) { + if (!this.expiryTime || this.expiryTime.isZero()) { + return false; + } + } + return valid; + } +} +exports.AuthenticationRequestDetails = AuthenticationRequestDetails; +AuthenticationRequestDetails.FLAG_HAS_REQUEST_ID = new bn_js_1.BN(1, 10); +AuthenticationRequestDetails.FLAG_HAS_RECIPIENT_CONSTRAINTS = new bn_js_1.BN(2, 10); +AuthenticationRequestDetails.FLAG_HAS_EXPIRY_TIME = new bn_js_1.BN(4, 10); +// Recipient Constraint Types - What types of Identity can login, e.g. REQUIRED_SYSTEM and "VRSC" means only identities on the Verus chain can login +AuthenticationRequestDetails.REQUIRED_ID = 1; +AuthenticationRequestDetails.REQUIRED_SYSTEM = 2; +AuthenticationRequestDetails.REQUIRED_PARENT = 3; diff --git a/dist/vdxf/classes/login/AuthenticationResponseDetails.d.ts b/dist/vdxf/classes/login/AuthenticationResponseDetails.d.ts new file mode 100644 index 00000000..9794053d --- /dev/null +++ b/dist/vdxf/classes/login/AuthenticationResponseDetails.d.ts @@ -0,0 +1,25 @@ +import { BigNumber } from '../../../utils/types/BigNumber'; +import { SerializableEntity } from '../../../utils/types/SerializableEntity'; +import { CompactIAddressObject, CompactAddressObjectJson } from '../CompactAddressObject'; +export type AuthenticationResponseDetailsJson = { + flags: string; + requestid?: CompactAddressObjectJson; +}; +export declare class AuthenticationResponseDetails implements SerializableEntity { + flags?: BigNumber; + requestID?: CompactIAddressObject; + static FLAG_HAS_REQUEST_ID: import("bn.js"); + constructor(data?: { + flags?: BigNumber; + requestID?: CompactIAddressObject; + }); + hasRequestID(): boolean; + setFlags(): void; + calcFlags(flags?: BigNumber): BigNumber; + toSha256(): Buffer; + getByteLength(): number; + toBuffer(): Buffer; + fromBuffer(buffer: Buffer, offset?: number): number; + toJson(): AuthenticationResponseDetailsJson; + static fromJson(json: AuthenticationResponseDetailsJson): AuthenticationResponseDetails; +} diff --git a/dist/vdxf/classes/login/AuthenticationResponseDetails.js b/dist/vdxf/classes/login/AuthenticationResponseDetails.js new file mode 100644 index 00000000..5c774a5b --- /dev/null +++ b/dist/vdxf/classes/login/AuthenticationResponseDetails.js @@ -0,0 +1,70 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AuthenticationResponseDetails = void 0; +const varint_1 = require("../../../utils/varint"); +const bufferutils_1 = require("../../../utils/bufferutils"); +const createHash = require("create-hash"); +const bn_js_1 = require("bn.js"); +const CompactAddressObject_1 = require("../CompactAddressObject"); +const { BufferReader, BufferWriter } = bufferutils_1.default; +class AuthenticationResponseDetails { + constructor(data) { + this.flags = data && data.flags ? data.flags : new bn_js_1.BN("0", 10); + this.requestID = (data === null || data === void 0 ? void 0 : data.requestID) || null; + this.setFlags(); + } + hasRequestID() { + return this.flags.and(AuthenticationResponseDetails.FLAG_HAS_REQUEST_ID).eq(AuthenticationResponseDetails.FLAG_HAS_REQUEST_ID); + } + setFlags() { + this.flags = this.calcFlags(); + } + calcFlags(flags = this.flags) { + if (this.requestID) { + flags = flags.or(AuthenticationResponseDetails.FLAG_HAS_REQUEST_ID); + } + return flags; + } + toSha256() { + return createHash("sha256").update(this.toBuffer()).digest(); + } + getByteLength() { + let length = 0; + length += varint_1.default.encodingLength(this.flags); + if (this.hasRequestID()) { + length += this.requestID.getByteLength(); + } + return length; + } + toBuffer() { + const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); + writer.writeVarInt(this.flags); + if (this.hasRequestID()) { + writer.writeSlice(this.requestID.toBuffer()); + } + return writer.buffer; + } + fromBuffer(buffer, offset = 0) { + const reader = new BufferReader(buffer, offset); + this.flags = reader.readVarInt(); + if (this.hasRequestID()) { + this.requestID = new CompactAddressObject_1.CompactIAddressObject(); + reader.offset = this.requestID.fromBuffer(reader.buffer, reader.offset); + } + return reader.offset; + } + toJson() { + return { + flags: this.flags.toString(10), + requestid: this.hasRequestID() ? this.requestID.toJson() : undefined + }; + } + static fromJson(json) { + return new AuthenticationResponseDetails({ + flags: new bn_js_1.BN(json.flags, 10), + requestID: CompactAddressObject_1.CompactIAddressObject.fromCompactAddressObjectJson(json.requestid) + }); + } +} +exports.AuthenticationResponseDetails = AuthenticationResponseDetails; +AuthenticationResponseDetails.FLAG_HAS_REQUEST_ID = new bn_js_1.BN(1, 10); diff --git a/dist/vdxf/classes/ordinals/AppEncryptionRequestOrdinalVDXFObject.d.ts b/dist/vdxf/classes/ordinals/AppEncryptionRequestOrdinalVDXFObject.d.ts new file mode 100644 index 00000000..26268652 --- /dev/null +++ b/dist/vdxf/classes/ordinals/AppEncryptionRequestOrdinalVDXFObject.d.ts @@ -0,0 +1,9 @@ +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; +import { AppEncryptionRequestDetails, AppEncryptionRequestJson } from "../appencryption/AppEncryptionRequestDetails"; +export declare class AppEncryptionRequestOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: AppEncryptionRequestDetails; + constructor(request?: OrdinalVDXFObjectInterfaceTemplate); + static fromJson(details: OrdinalVDXFObjectJsonTemplate): AppEncryptionRequestOrdinalVDXFObject; +} diff --git a/dist/vdxf/classes/ordinals/AppEncryptionRequestOrdinalVDXFObject.js b/dist/vdxf/classes/ordinals/AppEncryptionRequestOrdinalVDXFObject.js new file mode 100644 index 00000000..2f9c4d2e --- /dev/null +++ b/dist/vdxf/classes/ordinals/AppEncryptionRequestOrdinalVDXFObject.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AppEncryptionRequestOrdinalVDXFObject = void 0; +const ordinals_1 = require("../../../constants/ordinals/ordinals"); +const SerializableEntityOrdinalVDXFObject_1 = require("./SerializableEntityOrdinalVDXFObject"); +const AppEncryptionRequestDetails_1 = require("../appencryption/AppEncryptionRequestDetails"); +class AppEncryptionRequestOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject_1.SerializableEntityOrdinalVDXFObject { + constructor(request = { + data: new AppEncryptionRequestDetails_1.AppEncryptionRequestDetails() + }) { + super({ + type: ordinals_1.VDXF_ORDINAL_APP_ENCRYPTION_REQUEST, + data: request.data + }, AppEncryptionRequestDetails_1.AppEncryptionRequestDetails); + } + static fromJson(details) { + return new AppEncryptionRequestOrdinalVDXFObject({ + data: AppEncryptionRequestDetails_1.AppEncryptionRequestDetails.fromJson(details.data) + }); + } +} +exports.AppEncryptionRequestOrdinalVDXFObject = AppEncryptionRequestOrdinalVDXFObject; diff --git a/dist/vdxf/classes/ordinals/AppEncryptionResponseOrdinalVDXFObject.d.ts b/dist/vdxf/classes/ordinals/AppEncryptionResponseOrdinalVDXFObject.d.ts new file mode 100644 index 00000000..b4cdfbd0 --- /dev/null +++ b/dist/vdxf/classes/ordinals/AppEncryptionResponseOrdinalVDXFObject.d.ts @@ -0,0 +1,9 @@ +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; +import { AppEncryptionResponseDetails, AppEncryptionResponseDetailsJson } from "../appencryption/AppEncryptionResponseDetails"; +export declare class AppEncryptionResponseOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: AppEncryptionResponseDetails; + constructor(request?: OrdinalVDXFObjectInterfaceTemplate); + static fromJson(details: OrdinalVDXFObjectJsonTemplate): AppEncryptionResponseOrdinalVDXFObject; +} diff --git a/dist/vdxf/classes/ordinals/AppEncryptionResponseOrdinalVDXFObject.js b/dist/vdxf/classes/ordinals/AppEncryptionResponseOrdinalVDXFObject.js new file mode 100644 index 00000000..ed657738 --- /dev/null +++ b/dist/vdxf/classes/ordinals/AppEncryptionResponseOrdinalVDXFObject.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AppEncryptionResponseOrdinalVDXFObject = void 0; +const ordinals_1 = require("../../../constants/ordinals/ordinals"); +const SerializableEntityOrdinalVDXFObject_1 = require("./SerializableEntityOrdinalVDXFObject"); +const AppEncryptionResponseDetails_1 = require("../appencryption/AppEncryptionResponseDetails"); +class AppEncryptionResponseOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject_1.SerializableEntityOrdinalVDXFObject { + constructor(request = { + data: new AppEncryptionResponseDetails_1.AppEncryptionResponseDetails() + }) { + super({ + type: ordinals_1.VDXF_ORDINAL_APP_ENCRYPTION_RESPONSE, + data: request.data + }, AppEncryptionResponseDetails_1.AppEncryptionResponseDetails); + } + static fromJson(details) { + return new AppEncryptionResponseOrdinalVDXFObject({ + data: AppEncryptionResponseDetails_1.AppEncryptionResponseDetails.fromJson(details.data) + }); + } +} +exports.AppEncryptionResponseOrdinalVDXFObject = AppEncryptionResponseOrdinalVDXFObject; diff --git a/dist/vdxf/classes/ordinals/AuthenticationRequestOrdinalVDXFObject.d.ts b/dist/vdxf/classes/ordinals/AuthenticationRequestOrdinalVDXFObject.d.ts new file mode 100644 index 00000000..f0a5abf8 --- /dev/null +++ b/dist/vdxf/classes/ordinals/AuthenticationRequestOrdinalVDXFObject.d.ts @@ -0,0 +1,9 @@ +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; +import { AuthenticationRequestDetails, AuthenticationRequestDetailsJson } from "../login/AuthenticationRequestDetails"; +export declare class AuthenticationRequestOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: AuthenticationRequestDetails; + constructor(request?: OrdinalVDXFObjectInterfaceTemplate); + static fromJson(details: OrdinalVDXFObjectJsonTemplate): AuthenticationRequestOrdinalVDXFObject; +} diff --git a/dist/vdxf/classes/ordinals/AuthenticationRequestOrdinalVDXFObject.js b/dist/vdxf/classes/ordinals/AuthenticationRequestOrdinalVDXFObject.js new file mode 100644 index 00000000..70fe1f66 --- /dev/null +++ b/dist/vdxf/classes/ordinals/AuthenticationRequestOrdinalVDXFObject.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AuthenticationRequestOrdinalVDXFObject = void 0; +const ordinals_1 = require("../../../constants/ordinals/ordinals"); +const SerializableEntityOrdinalVDXFObject_1 = require("./SerializableEntityOrdinalVDXFObject"); +const AuthenticationRequestDetails_1 = require("../login/AuthenticationRequestDetails"); +class AuthenticationRequestOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject_1.SerializableEntityOrdinalVDXFObject { + constructor(request = { + data: new AuthenticationRequestDetails_1.AuthenticationRequestDetails() + }) { + super({ + type: ordinals_1.VDXF_ORDINAL_AUTHENTICATION_REQUEST, + data: request.data + }, AuthenticationRequestDetails_1.AuthenticationRequestDetails); + } + static fromJson(details) { + return new AuthenticationRequestOrdinalVDXFObject({ + data: AuthenticationRequestDetails_1.AuthenticationRequestDetails.fromJson(details.data) + }); + } +} +exports.AuthenticationRequestOrdinalVDXFObject = AuthenticationRequestOrdinalVDXFObject; diff --git a/dist/vdxf/classes/ordinals/AuthenticationResponseOrdinalVDXFObject.d.ts b/dist/vdxf/classes/ordinals/AuthenticationResponseOrdinalVDXFObject.d.ts new file mode 100644 index 00000000..b9f7e900 --- /dev/null +++ b/dist/vdxf/classes/ordinals/AuthenticationResponseOrdinalVDXFObject.d.ts @@ -0,0 +1,9 @@ +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; +import { AuthenticationResponseDetails, AuthenticationResponseDetailsJson } from "../login/AuthenticationResponseDetails"; +export declare class AuthenticationResponseOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: AuthenticationResponseDetails; + constructor(response?: OrdinalVDXFObjectInterfaceTemplate); + static fromJson(details: OrdinalVDXFObjectJsonTemplate): AuthenticationResponseOrdinalVDXFObject; +} diff --git a/dist/vdxf/classes/ordinals/AuthenticationResponseOrdinalVDXFObject.js b/dist/vdxf/classes/ordinals/AuthenticationResponseOrdinalVDXFObject.js new file mode 100644 index 00000000..0e209df2 --- /dev/null +++ b/dist/vdxf/classes/ordinals/AuthenticationResponseOrdinalVDXFObject.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AuthenticationResponseOrdinalVDXFObject = void 0; +const ordinals_1 = require("../../../constants/ordinals/ordinals"); +const SerializableEntityOrdinalVDXFObject_1 = require("./SerializableEntityOrdinalVDXFObject"); +const AuthenticationResponseDetails_1 = require("../login/AuthenticationResponseDetails"); +class AuthenticationResponseOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject_1.SerializableEntityOrdinalVDXFObject { + constructor(response = { + data: new AuthenticationResponseDetails_1.AuthenticationResponseDetails() + }) { + super({ + type: ordinals_1.VDXF_ORDINAL_AUTHENTICATION_RESPONSE, + data: response.data + }, AuthenticationResponseDetails_1.AuthenticationResponseDetails); + } + static fromJson(details) { + return new AuthenticationResponseOrdinalVDXFObject({ + data: AuthenticationResponseDetails_1.AuthenticationResponseDetails.fromJson(details.data) + }); + } +} +exports.AuthenticationResponseOrdinalVDXFObject = AuthenticationResponseOrdinalVDXFObject; diff --git a/dist/vdxf/classes/ordinals/DataDescriptorOrdinalVDXFObject.d.ts b/dist/vdxf/classes/ordinals/DataDescriptorOrdinalVDXFObject.d.ts new file mode 100644 index 00000000..cb7d2683 --- /dev/null +++ b/dist/vdxf/classes/ordinals/DataDescriptorOrdinalVDXFObject.d.ts @@ -0,0 +1,9 @@ +import { DataDescriptor, DataDescriptorJson } from "../../../pbaas"; +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; +export declare class DataDescriptorOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: DataDescriptor; + constructor(request?: OrdinalVDXFObjectInterfaceTemplate); + static fromJson(details: OrdinalVDXFObjectJsonTemplate): DataDescriptorOrdinalVDXFObject; +} diff --git a/dist/vdxf/classes/ordinals/DataDescriptorOrdinalVDXFObject.js b/dist/vdxf/classes/ordinals/DataDescriptorOrdinalVDXFObject.js new file mode 100644 index 00000000..545d2dd9 --- /dev/null +++ b/dist/vdxf/classes/ordinals/DataDescriptorOrdinalVDXFObject.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.DataDescriptorOrdinalVDXFObject = void 0; +const ordinals_1 = require("../../../constants/ordinals/ordinals"); +const pbaas_1 = require("../../../pbaas"); +const SerializableEntityOrdinalVDXFObject_1 = require("./SerializableEntityOrdinalVDXFObject"); +class DataDescriptorOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject_1.SerializableEntityOrdinalVDXFObject { + constructor(request = { + data: new pbaas_1.DataDescriptor() + }) { + super({ + type: ordinals_1.VDXF_ORDINAL_DATA_DESCRIPTOR, + data: request.data + }, pbaas_1.DataDescriptor); + } + static fromJson(details) { + return new DataDescriptorOrdinalVDXFObject({ + data: pbaas_1.DataDescriptor.fromJson(details.data) + }); + } +} +exports.DataDescriptorOrdinalVDXFObject = DataDescriptorOrdinalVDXFObject; diff --git a/dist/vdxf/classes/ordinals/DataPacketResponseOrdinalVDXFObject.d.ts b/dist/vdxf/classes/ordinals/DataPacketResponseOrdinalVDXFObject.d.ts new file mode 100644 index 00000000..b61057ef --- /dev/null +++ b/dist/vdxf/classes/ordinals/DataPacketResponseOrdinalVDXFObject.d.ts @@ -0,0 +1,9 @@ +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; +import { DataPacketResponse, DataResponseJson } from "../datapacket/DataPacketResponse"; +export declare class DataPacketResponseOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: DataPacketResponse; + constructor(request?: OrdinalVDXFObjectInterfaceTemplate); + static fromJson(details: OrdinalVDXFObjectJsonTemplate): DataPacketResponseOrdinalVDXFObject; +} diff --git a/dist/vdxf/classes/ordinals/DataPacketResponseOrdinalVDXFObject.js b/dist/vdxf/classes/ordinals/DataPacketResponseOrdinalVDXFObject.js new file mode 100644 index 00000000..7697708a --- /dev/null +++ b/dist/vdxf/classes/ordinals/DataPacketResponseOrdinalVDXFObject.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.DataPacketResponseOrdinalVDXFObject = void 0; +const ordinals_1 = require("../../../constants/ordinals/ordinals"); +const SerializableEntityOrdinalVDXFObject_1 = require("./SerializableEntityOrdinalVDXFObject"); +const DataPacketResponse_1 = require("../datapacket/DataPacketResponse"); +class DataPacketResponseOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject_1.SerializableEntityOrdinalVDXFObject { + constructor(request = { + data: new DataPacketResponse_1.DataPacketResponse() + }) { + super({ + type: ordinals_1.VDXF_ORDINAL_DATA_RESPONSE, + data: request.data + }, DataPacketResponse_1.DataPacketResponse); + } + static fromJson(details) { + return new DataPacketResponseOrdinalVDXFObject({ + data: DataPacketResponse_1.DataPacketResponse.fromJson(details.data) + }); + } +} +exports.DataPacketResponseOrdinalVDXFObject = DataPacketResponseOrdinalVDXFObject; diff --git a/dist/vdxf/classes/ordinals/IdentityUpdateRequestOrdinalVDXFObject.d.ts b/dist/vdxf/classes/ordinals/IdentityUpdateRequestOrdinalVDXFObject.d.ts new file mode 100644 index 00000000..ca0fef4d --- /dev/null +++ b/dist/vdxf/classes/ordinals/IdentityUpdateRequestOrdinalVDXFObject.d.ts @@ -0,0 +1,9 @@ +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { IdentityUpdateRequestDetails, IdentityUpdateRequestDetailsJson } from "../identity/IdentityUpdateRequestDetails"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; +export declare class IdentityUpdateRequestOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: IdentityUpdateRequestDetails; + constructor(request?: OrdinalVDXFObjectInterfaceTemplate); + static fromJson(details: OrdinalVDXFObjectJsonTemplate): IdentityUpdateRequestOrdinalVDXFObject; +} diff --git a/dist/vdxf/classes/ordinals/IdentityUpdateRequestOrdinalVDXFObject.js b/dist/vdxf/classes/ordinals/IdentityUpdateRequestOrdinalVDXFObject.js new file mode 100644 index 00000000..13aac64c --- /dev/null +++ b/dist/vdxf/classes/ordinals/IdentityUpdateRequestOrdinalVDXFObject.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.IdentityUpdateRequestOrdinalVDXFObject = void 0; +const ordinals_1 = require("../../../constants/ordinals/ordinals"); +const IdentityUpdateRequestDetails_1 = require("../identity/IdentityUpdateRequestDetails"); +const SerializableEntityOrdinalVDXFObject_1 = require("./SerializableEntityOrdinalVDXFObject"); +class IdentityUpdateRequestOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject_1.SerializableEntityOrdinalVDXFObject { + constructor(request = { + data: new IdentityUpdateRequestDetails_1.IdentityUpdateRequestDetails() + }) { + super({ + type: ordinals_1.VDXF_ORDINAL_IDENTITY_UPDATE_REQUEST, + data: request.data + }, IdentityUpdateRequestDetails_1.IdentityUpdateRequestDetails); + } + static fromJson(details) { + return new IdentityUpdateRequestOrdinalVDXFObject({ + data: IdentityUpdateRequestDetails_1.IdentityUpdateRequestDetails.fromJson(details.data) + }); + } +} +exports.IdentityUpdateRequestOrdinalVDXFObject = IdentityUpdateRequestOrdinalVDXFObject; diff --git a/dist/vdxf/classes/ordinals/IdentityUpdateResponseOrdinalVDXFObject.d.ts b/dist/vdxf/classes/ordinals/IdentityUpdateResponseOrdinalVDXFObject.d.ts new file mode 100644 index 00000000..0b295a14 --- /dev/null +++ b/dist/vdxf/classes/ordinals/IdentityUpdateResponseOrdinalVDXFObject.d.ts @@ -0,0 +1,9 @@ +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { IdentityUpdateResponseDetails, IdentityUpdateResponseDetailsJson } from "../identity/IdentityUpdateResponseDetails"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; +export declare class IdentityUpdateResponseOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: IdentityUpdateResponseDetails; + constructor(response?: OrdinalVDXFObjectInterfaceTemplate); + static fromJson(details: OrdinalVDXFObjectJsonTemplate): IdentityUpdateResponseOrdinalVDXFObject; +} diff --git a/dist/vdxf/classes/ordinals/IdentityUpdateResponseOrdinalVDXFObject.js b/dist/vdxf/classes/ordinals/IdentityUpdateResponseOrdinalVDXFObject.js new file mode 100644 index 00000000..680f7183 --- /dev/null +++ b/dist/vdxf/classes/ordinals/IdentityUpdateResponseOrdinalVDXFObject.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.IdentityUpdateResponseOrdinalVDXFObject = void 0; +const ordinals_1 = require("../../../constants/ordinals/ordinals"); +const IdentityUpdateResponseDetails_1 = require("../identity/IdentityUpdateResponseDetails"); +const SerializableEntityOrdinalVDXFObject_1 = require("./SerializableEntityOrdinalVDXFObject"); +class IdentityUpdateResponseOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject_1.SerializableEntityOrdinalVDXFObject { + constructor(response = { + data: new IdentityUpdateResponseDetails_1.IdentityUpdateResponseDetails() + }) { + super({ + type: ordinals_1.VDXF_ORDINAL_IDENTITY_UPDATE_RESPONSE, + data: response.data + }, IdentityUpdateResponseDetails_1.IdentityUpdateResponseDetails); + } + static fromJson(details) { + return new IdentityUpdateResponseOrdinalVDXFObject({ + data: IdentityUpdateResponseDetails_1.IdentityUpdateResponseDetails.fromJson(details.data) + }); + } +} +exports.IdentityUpdateResponseOrdinalVDXFObject = IdentityUpdateResponseOrdinalVDXFObject; diff --git a/dist/vdxf/classes/ordinals/OrdinalVDXFObject.d.ts b/dist/vdxf/classes/ordinals/OrdinalVDXFObject.d.ts new file mode 100644 index 00000000..98e1c534 --- /dev/null +++ b/dist/vdxf/classes/ordinals/OrdinalVDXFObject.d.ts @@ -0,0 +1,59 @@ +import { BigNumber } from "../../../utils/types/BigNumber"; +import { SerializableDataEntity, SerializableEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectReservedData, OrdinalVDXFObjectReservedDataJson } from "../../../constants/ordinals/types"; +export interface OrdinalVDXFObjectInterfaceTemplate { + version?: BigNumber; + type?: BigNumber; + key?: string; + data?: T; +} +export type OrdinalVDXFObjectJsonTemplate = { + version: string; + type: string; + vdxfkey?: string; + data?: T; +}; +export type BufferOrOrdinalVDXFObjectReservedData = Buffer | OrdinalVDXFObjectReservedData; +export type StringOrOrdinalVDXFObjectReservedDataJson = string | OrdinalVDXFObjectReservedDataJson; +export type OrdinalVDXFObjectInterface = OrdinalVDXFObjectInterfaceTemplate; +export type OrdinalVDXFObjectJson = OrdinalVDXFObjectJsonTemplate; +export type OrdinalVDXFObjectDataClass = new (...args: any[]) => OrdinalVDXFObjectReservedData; +export type OrdinalVDXFObjectClass = new (...args: any[]) => OrdinalVDXFObject; +export declare const getOrdinalVDXFObjectClassForType: (type: BigNumber) => OrdinalVDXFObjectClass; +export declare class OrdinalVDXFObject implements SerializableEntity { + version: BigNumber; + type: BigNumber; + key?: string; + data?: BufferOrOrdinalVDXFObjectReservedData; + static VERSION_INVALID: import("bn.js"); + static VERSION_FIRST: import("bn.js"); + static VERSION_LAST: import("bn.js"); + static VERSION_CURRENT: import("bn.js"); + constructor(request?: OrdinalVDXFObjectInterfaceTemplate); + isDefinedByVdxfKey(): boolean; + isDefinedByTextVdxfKey(): boolean; + isDefinedByIDOrCurrencyFQN(): boolean; + isDefinedByCustomKey(): boolean; + getIAddressKey(): string; + getDataByteLength(): number; + toDataBuffer(): Buffer; + fromDataBuffer(buffer: Buffer): void; + getByteLength(): number; + toBuffer(): Buffer; + fromBufferOptionalType(buffer: Buffer, offset?: number, type?: BigNumber, key?: string): number; + fromBuffer(buffer: Buffer, offset?: number): number; + toJson(): OrdinalVDXFObjectJson; + static createFromBuffer(buffer: Buffer, offset?: number, optimizeWithOrdinal?: boolean, rootSystemName?: string): { + offset: number; + obj: OrdinalVDXFObject; + }; +} +export declare class GeneralTypeOrdinalVDXFObject extends OrdinalVDXFObject implements SerializableDataEntity { + data: Buffer; + key: string; + constructor(request?: OrdinalVDXFObjectInterfaceTemplate); + getDataByteLength(): number; + toDataBuffer(): Buffer; + fromDataBuffer(buffer: Buffer): void; + static fromJson(details: OrdinalVDXFObjectJson): GeneralTypeOrdinalVDXFObject; +} diff --git a/dist/vdxf/classes/ordinals/OrdinalVDXFObject.js b/dist/vdxf/classes/ordinals/OrdinalVDXFObject.js new file mode 100644 index 00000000..937472aa --- /dev/null +++ b/dist/vdxf/classes/ordinals/OrdinalVDXFObject.js @@ -0,0 +1,223 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.GeneralTypeOrdinalVDXFObject = exports.OrdinalVDXFObject = exports.getOrdinalVDXFObjectClassForType = void 0; +const bufferutils_1 = require("../../../utils/bufferutils"); +const bn_js_1 = require("bn.js"); +const varuint_1 = require("../../../utils/varuint"); +const address_1 = require("../../../utils/address"); +const varint_1 = require("../../../utils/varint"); +const vdxf_1 = require("../../../constants/vdxf"); +const OrdinalVDXFObjectOrdinalMap_1 = require("./OrdinalVDXFObjectOrdinalMap"); +const pbaas_1 = require("../../../constants/pbaas"); +const ordinals_1 = require("../../../constants/ordinals/ordinals"); +const getOrdinalVDXFObjectClassForType = (type) => { + if (OrdinalVDXFObjectOrdinalMap_1.OrdinalVDXFObjectOrdinalMap.isRecognizedOrdinal(type.toNumber())) { + const key = OrdinalVDXFObjectOrdinalMap_1.OrdinalVDXFObjectOrdinalMap.getVdxfKeyForOrdinal(type.toNumber()); + if (OrdinalVDXFObjectOrdinalMap_1.OrdinalVDXFObjectOrdinalMap.hasClassForVdxfKey(key)) { + return OrdinalVDXFObjectOrdinalMap_1.OrdinalVDXFObjectOrdinalMap.getClassForVdxfKey(OrdinalVDXFObjectOrdinalMap_1.OrdinalVDXFObjectOrdinalMap.getVdxfKeyForOrdinal(type.toNumber())); + } + else { + throw new Error("No class found for " + key); + } + } + else if (type.eq(ordinals_1.VDXF_OBJECT_RESERVED_BYTE_I_ADDR) || + type.eq(ordinals_1.VDXF_OBJECT_RESERVED_BYTE_VDXF_ID_STRING) || + type.eq(ordinals_1.VDXF_OBJECT_RESERVED_BYTE_ID_OR_CURRENCY)) + return GeneralTypeOrdinalVDXFObject; + else + throw new Error("Unrecognized vdxf ordinal object type " + type.toNumber()); +}; +exports.getOrdinalVDXFObjectClassForType = getOrdinalVDXFObjectClassForType; +class OrdinalVDXFObject { + constructor(request = { + type: ordinals_1.VDXF_ORDINAL_DATA_DESCRIPTOR + }) { + if (request.key) { + this.type = request.type ? request.type : ordinals_1.VDXF_OBJECT_RESERVED_BYTE_I_ADDR; + this.key = request.key; + if (request.data) { + this.data = request.data; + } + else + this.data = Buffer.alloc(0); + } + else if (request.type == null) { + this.type = ordinals_1.VDXF_ORDINAL_DATA_DESCRIPTOR; + } + else { + this.type = request.type; + } + if (request.version) + this.version = request.version; + else + this.version = OrdinalVDXFObject.VERSION_CURRENT; + } + isDefinedByVdxfKey() { + return this.type.eq(ordinals_1.VDXF_OBJECT_RESERVED_BYTE_I_ADDR); + } + isDefinedByTextVdxfKey() { + return this.type.eq(ordinals_1.VDXF_OBJECT_RESERVED_BYTE_VDXF_ID_STRING); + } + isDefinedByIDOrCurrencyFQN() { + return this.type.eq(ordinals_1.VDXF_OBJECT_RESERVED_BYTE_ID_OR_CURRENCY); + } + isDefinedByCustomKey() { + return this.isDefinedByIDOrCurrencyFQN() || this.isDefinedByTextVdxfKey() || this.isDefinedByVdxfKey(); + } + // Returns the I address vdxf key of this vdxf object + getIAddressKey() { + if (this.isDefinedByVdxfKey()) { + return this.key; + } + else if (this.isDefinedByTextVdxfKey()) { + return (0, address_1.getDataKey)(this.key).id; + } + else if (this.isDefinedByIDOrCurrencyFQN()) { + return (0, address_1.toIAddress)(this.key); + } + else if (OrdinalVDXFObjectOrdinalMap_1.OrdinalVDXFObjectOrdinalMap.isRecognizedOrdinal(this.type.toNumber())) { + return OrdinalVDXFObjectOrdinalMap_1.OrdinalVDXFObjectOrdinalMap.getVdxfKeyForOrdinal(this.type.toNumber()); + } + else + throw new Error("Could not get I address for ordinal VDXF object"); + } + getDataByteLength() { + return 0; + } + toDataBuffer() { + return Buffer.alloc(0); + } + fromDataBuffer(buffer) { } + getByteLength() { + let length = 0; + length += varuint_1.default.encodingLength(this.type.toNumber()); + if (this.isDefinedByVdxfKey()) { + length += (0, address_1.fromBase58Check)(this.key).hash.length; + } + else if (this.isDefinedByTextVdxfKey() || this.isDefinedByIDOrCurrencyFQN()) { + const utf8Key = Buffer.from(this.key, 'utf8'); + length += varuint_1.default.encodingLength(utf8Key.length); + length += utf8Key.length; + } + length += varint_1.default.encodingLength(this.version); + const dataLength = this.getDataByteLength(); + length += varuint_1.default.encodingLength(dataLength); + length += dataLength; + return length; + } + toBuffer() { + const writer = new bufferutils_1.default.BufferWriter(Buffer.alloc(this.getByteLength())); + writer.writeCompactSize(this.type.toNumber()); + if (this.isDefinedByVdxfKey()) { + writer.writeSlice((0, address_1.fromBase58Check)(this.key).hash); + } + else if (this.isDefinedByTextVdxfKey() || this.isDefinedByIDOrCurrencyFQN()) { + writer.writeVarSlice(Buffer.from(this.key, 'utf8')); + } + writer.writeVarInt(this.version); + writer.writeVarSlice(this.toDataBuffer()); + return writer.buffer; + } + fromBufferOptionalType(buffer, offset, type, key) { + if (buffer.length == 0) + throw new Error("Cannot create request from empty buffer"); + const reader = new bufferutils_1.default.BufferReader(buffer, offset); + if (!type) { + this.type = new bn_js_1.BN(reader.readCompactSize()); + } + else + this.type = type; + if (!key) { + if (this.isDefinedByVdxfKey()) { + this.key = (0, address_1.toBase58Check)(reader.readSlice(vdxf_1.HASH160_BYTE_LENGTH), vdxf_1.I_ADDR_VERSION); + } + else if (this.isDefinedByTextVdxfKey() || this.isDefinedByIDOrCurrencyFQN()) { + this.key = reader.readVarSlice().toString('utf8'); + } + } + else { + this.key = key; + } + this.version = reader.readVarInt(); + const dataBuf = reader.readVarSlice(); + this.fromDataBuffer(dataBuf); + return reader.offset; + } + fromBuffer(buffer, offset) { + return this.fromBufferOptionalType(buffer, offset); + } + toJson() { + return { + type: this.type ? this.type.toString() : undefined, + version: this.version ? this.version.toString() : undefined, + vdxfkey: this.key, + data: this.data ? this.isDefinedByCustomKey() ? this.data.toString('hex') : this.data.toJson() : undefined + }; + } + static createFromBuffer(buffer, offset, optimizeWithOrdinal = false, rootSystemName = pbaas_1.DEFAULT_VERUS_CHAINNAME) { + if (buffer.length == 0) + throw new Error("Cannot create request from empty buffer"); + const reader = new bufferutils_1.default.BufferReader(buffer, offset); + let type = new bn_js_1.BN(reader.readCompactSize()); + const rootSystemId = (0, address_1.toIAddress)(rootSystemName); + const Entity = (0, exports.getOrdinalVDXFObjectClassForType)(type); + const ord = new Entity({ type }); + let key; + if (optimizeWithOrdinal) { + let vdxfKey; + if (ord.isDefinedByVdxfKey()) { + key = (0, address_1.toBase58Check)(reader.readSlice(vdxf_1.HASH160_BYTE_LENGTH), vdxf_1.I_ADDR_VERSION); + vdxfKey = key; + } + else if (ord.isDefinedByTextVdxfKey() || ord.isDefinedByIDOrCurrencyFQN()) { + key = reader.readVarSlice().toString('utf8'); + if (ord.isDefinedByTextVdxfKey()) { + vdxfKey = (0, address_1.getDataKey)(key, undefined, rootSystemId).id; + } + else { + vdxfKey = (0, address_1.toIAddress)(key, rootSystemName); + } + } + if (OrdinalVDXFObjectOrdinalMap_1.OrdinalVDXFObjectOrdinalMap.vdxfKeyHasOrdinal(vdxfKey)) { + type = new bn_js_1.BN(OrdinalVDXFObjectOrdinalMap_1.OrdinalVDXFObjectOrdinalMap.getOrdinalForVdxfKey(vdxfKey)); + } + } + reader.offset = ord.fromBufferOptionalType(buffer, reader.offset, type, key); + return { offset: reader.offset, obj: ord }; + } +} +exports.OrdinalVDXFObject = OrdinalVDXFObject; +OrdinalVDXFObject.VERSION_INVALID = new bn_js_1.BN(0, 10); +OrdinalVDXFObject.VERSION_FIRST = new bn_js_1.BN(1, 10); +OrdinalVDXFObject.VERSION_LAST = new bn_js_1.BN(1, 10); +OrdinalVDXFObject.VERSION_CURRENT = new bn_js_1.BN(1, 10); +class GeneralTypeOrdinalVDXFObject extends OrdinalVDXFObject { + constructor(request = { + type: ordinals_1.VDXF_OBJECT_RESERVED_BYTE_I_ADDR, + data: Buffer.alloc(0), + key: vdxf_1.NULL_ADDRESS + }) { + super({ + type: request.type, + data: request.data, + key: request.key + }); + } + getDataByteLength() { + return this.data.length; + } + toDataBuffer() { + return this.data; + } + fromDataBuffer(buffer) { + this.data = Buffer.from(buffer); + } + static fromJson(details) { + return new GeneralTypeOrdinalVDXFObject({ + key: details.vdxfkey, + data: details.data ? Buffer.from(details.data, 'hex') : undefined, + type: details.type ? new bn_js_1.BN(details.type) : ordinals_1.VDXF_OBJECT_RESERVED_BYTE_I_ADDR + }); + } +} +exports.GeneralTypeOrdinalVDXFObject = GeneralTypeOrdinalVDXFObject; diff --git a/dist/vdxf/classes/ordinals/OrdinalVDXFObjectOrdinalMap.d.ts b/dist/vdxf/classes/ordinals/OrdinalVDXFObjectOrdinalMap.d.ts new file mode 100644 index 00000000..2cf94547 --- /dev/null +++ b/dist/vdxf/classes/ordinals/OrdinalVDXFObjectOrdinalMap.d.ts @@ -0,0 +1,17 @@ +import { OrdinalVDXFObjectClass } from "./OrdinalVDXFObject"; +declare class _OrdinalVDXFObjectOrdinalMap { + private keyToOrdinalMap; + private ordinalToKeyMap; + keyToOrdinalClass: Map; + constructor(); + private updateOrdinalToKeyMap; + registerOrdinal(ordinal: number, vdxfKey: string, ordinalClass: OrdinalVDXFObjectClass, throwOnDuplicate?: boolean): void; + isRecognizedOrdinal(ordinal: number): boolean; + vdxfKeyHasOrdinal(vdxfKey: string): boolean; + hasClassForVdxfKey(vdxfKey: string): boolean; + getOrdinalForVdxfKey(vdxfKey: string): number; + getVdxfKeyForOrdinal(ordinal: number): string; + getClassForVdxfKey(vdxfKey: string): OrdinalVDXFObjectClass; +} +export declare const OrdinalVDXFObjectOrdinalMap: _OrdinalVDXFObjectOrdinalMap; +export {}; diff --git a/dist/vdxf/classes/ordinals/OrdinalVDXFObjectOrdinalMap.js b/dist/vdxf/classes/ordinals/OrdinalVDXFObjectOrdinalMap.js new file mode 100644 index 00000000..bf31a1c1 --- /dev/null +++ b/dist/vdxf/classes/ordinals/OrdinalVDXFObjectOrdinalMap.js @@ -0,0 +1,44 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.OrdinalVDXFObjectOrdinalMap = void 0; +// Singleton class that exists to create a bidirectional map of ordinals <-> vdxf keys +class _OrdinalVDXFObjectOrdinalMap { + constructor() { + this.keyToOrdinalMap = new Map(); + this.ordinalToKeyMap = new Map(); + this.keyToOrdinalClass = new Map(); + } + updateOrdinalToKeyMap() { + this.ordinalToKeyMap = new Map(Array.from(this.keyToOrdinalMap, a => a.reverse())); + } + registerOrdinal(ordinal, vdxfKey, ordinalClass, throwOnDuplicate = true) { + if (this.isRecognizedOrdinal(ordinal) || this.vdxfKeyHasOrdinal(vdxfKey)) { + if (throwOnDuplicate) + throw new Error("Cannot overwrite existing ordinal"); + else + return; + } + this.keyToOrdinalMap.set(vdxfKey, ordinal); + this.keyToOrdinalClass.set(vdxfKey, ordinalClass); + this.updateOrdinalToKeyMap(); + } + isRecognizedOrdinal(ordinal) { + return this.ordinalToKeyMap.has(ordinal); + } + vdxfKeyHasOrdinal(vdxfKey) { + return this.keyToOrdinalMap.has(vdxfKey); + } + hasClassForVdxfKey(vdxfKey) { + return this.keyToOrdinalClass.has(vdxfKey); + } + getOrdinalForVdxfKey(vdxfKey) { + return this.keyToOrdinalMap.get(vdxfKey); + } + getVdxfKeyForOrdinal(ordinal) { + return this.ordinalToKeyMap.get(ordinal); + } + getClassForVdxfKey(vdxfKey) { + return this.keyToOrdinalClass.get(vdxfKey); + } +} +exports.OrdinalVDXFObjectOrdinalMap = new _OrdinalVDXFObjectOrdinalMap(); diff --git a/dist/vdxf/classes/ordinals/ProvisionIdentityDetailsOrdinalVDXFObject.d.ts b/dist/vdxf/classes/ordinals/ProvisionIdentityDetailsOrdinalVDXFObject.d.ts new file mode 100644 index 00000000..66bef3a1 --- /dev/null +++ b/dist/vdxf/classes/ordinals/ProvisionIdentityDetailsOrdinalVDXFObject.d.ts @@ -0,0 +1,9 @@ +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; +import { ProvisionIdentityDetails, ProvisionIdentityDetailsJson } from "../requestobjects/ProvisionIdentityDetails"; +export declare class ProvisionIdentityDetailsOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: ProvisionIdentityDetails; + constructor(request?: OrdinalVDXFObjectInterfaceTemplate); + static fromJson(details: OrdinalVDXFObjectJsonTemplate): ProvisionIdentityDetailsOrdinalVDXFObject; +} diff --git a/dist/vdxf/classes/ordinals/ProvisionIdentityDetailsOrdinalVDXFObject.js b/dist/vdxf/classes/ordinals/ProvisionIdentityDetailsOrdinalVDXFObject.js new file mode 100644 index 00000000..a68f75bb --- /dev/null +++ b/dist/vdxf/classes/ordinals/ProvisionIdentityDetailsOrdinalVDXFObject.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ProvisionIdentityDetailsOrdinalVDXFObject = void 0; +const ordinals_1 = require("../../../constants/ordinals/ordinals"); +const SerializableEntityOrdinalVDXFObject_1 = require("./SerializableEntityOrdinalVDXFObject"); +const ProvisionIdentityDetails_1 = require("../requestobjects/ProvisionIdentityDetails"); +class ProvisionIdentityDetailsOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject_1.SerializableEntityOrdinalVDXFObject { + constructor(request = { + data: new ProvisionIdentityDetails_1.ProvisionIdentityDetails() + }) { + super({ + type: ordinals_1.VDXF_ORDINAL_PROVISION_IDENTITY_DETAILS, + data: request.data + }, ProvisionIdentityDetails_1.ProvisionIdentityDetails); + } + static fromJson(details) { + return new ProvisionIdentityDetailsOrdinalVDXFObject({ + data: ProvisionIdentityDetails_1.ProvisionIdentityDetails.fromJson(details.data) + }); + } +} +exports.ProvisionIdentityDetailsOrdinalVDXFObject = ProvisionIdentityDetailsOrdinalVDXFObject; diff --git a/dist/vdxf/classes/ordinals/SerializableEntityOrdinalVDXFObject.d.ts b/dist/vdxf/classes/ordinals/SerializableEntityOrdinalVDXFObject.d.ts new file mode 100644 index 00000000..18735edf --- /dev/null +++ b/dist/vdxf/classes/ordinals/SerializableEntityOrdinalVDXFObject.d.ts @@ -0,0 +1,11 @@ +import { OrdinalVDXFObjectReservedData } from "../../../constants/ordinals/types"; +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObject, OrdinalVDXFObjectDataClass, OrdinalVDXFObjectInterfaceTemplate } from "./OrdinalVDXFObject"; +export declare class SerializableEntityOrdinalVDXFObject extends OrdinalVDXFObject implements SerializableDataEntity { + data: OrdinalVDXFObjectReservedData; + entity: OrdinalVDXFObjectDataClass; + constructor(request: OrdinalVDXFObjectInterfaceTemplate, entity: OrdinalVDXFObjectDataClass); + getDataByteLength(): number; + toDataBuffer(): Buffer; + fromDataBuffer(buffer: Buffer): void; +} diff --git a/dist/vdxf/classes/ordinals/SerializableEntityOrdinalVDXFObject.js b/dist/vdxf/classes/ordinals/SerializableEntityOrdinalVDXFObject.js new file mode 100644 index 00000000..e5d4d0f7 --- /dev/null +++ b/dist/vdxf/classes/ordinals/SerializableEntityOrdinalVDXFObject.js @@ -0,0 +1,26 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.SerializableEntityOrdinalVDXFObject = void 0; +const OrdinalVDXFObject_1 = require("./OrdinalVDXFObject"); +class SerializableEntityOrdinalVDXFObject extends OrdinalVDXFObject_1.OrdinalVDXFObject { + constructor(request, entity) { + if (!request || !request.type) + throw new Error("Expected request with data and type"); + super({ + type: request.type + }); + this.entity = entity; + this.data = request.data ? request.data : new entity(); + } + getDataByteLength() { + return this.data.getByteLength(); + } + toDataBuffer() { + return this.data.toBuffer(); + } + fromDataBuffer(buffer) { + this.data = new this.entity(); + this.data.fromBuffer(buffer); + } +} +exports.SerializableEntityOrdinalVDXFObject = SerializableEntityOrdinalVDXFObject; diff --git a/dist/vdxf/classes/ordinals/UserDataRequestOrdinalVDXFObject.d.ts b/dist/vdxf/classes/ordinals/UserDataRequestOrdinalVDXFObject.d.ts new file mode 100644 index 00000000..5487e06f --- /dev/null +++ b/dist/vdxf/classes/ordinals/UserDataRequestOrdinalVDXFObject.d.ts @@ -0,0 +1,9 @@ +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; +import { UserDataRequestDetails, UserDataRequestJson } from "../requestobjects/UserDataRequestDetails"; +export declare class UserDataRequestOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: UserDataRequestDetails; + constructor(request?: OrdinalVDXFObjectInterfaceTemplate); + static fromJson(details: OrdinalVDXFObjectJsonTemplate): UserDataRequestOrdinalVDXFObject; +} diff --git a/dist/vdxf/classes/ordinals/UserDataRequestOrdinalVDXFObject.js b/dist/vdxf/classes/ordinals/UserDataRequestOrdinalVDXFObject.js new file mode 100644 index 00000000..13029828 --- /dev/null +++ b/dist/vdxf/classes/ordinals/UserDataRequestOrdinalVDXFObject.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.UserDataRequestOrdinalVDXFObject = void 0; +const ordinals_1 = require("../../../constants/ordinals/ordinals"); +const SerializableEntityOrdinalVDXFObject_1 = require("./SerializableEntityOrdinalVDXFObject"); +const UserDataRequestDetails_1 = require("../requestobjects/UserDataRequestDetails"); +class UserDataRequestOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject_1.SerializableEntityOrdinalVDXFObject { + constructor(request = { + data: new UserDataRequestDetails_1.UserDataRequestDetails() + }) { + super({ + type: ordinals_1.VDXF_ORDINAL_USER_DATA_REQUEST, + data: request.data + }, UserDataRequestDetails_1.UserDataRequestDetails); + } + static fromJson(details) { + return new UserDataRequestOrdinalVDXFObject({ + data: UserDataRequestDetails_1.UserDataRequestDetails.fromJson(details.data) + }); + } +} +exports.UserDataRequestOrdinalVDXFObject = UserDataRequestOrdinalVDXFObject; diff --git a/dist/vdxf/classes/ordinals/UserSpecificDataPacketDetailsOrdinalVDXFObject.d.ts b/dist/vdxf/classes/ordinals/UserSpecificDataPacketDetailsOrdinalVDXFObject.d.ts new file mode 100644 index 00000000..5ad5a816 --- /dev/null +++ b/dist/vdxf/classes/ordinals/UserSpecificDataPacketDetailsOrdinalVDXFObject.d.ts @@ -0,0 +1,9 @@ +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; +import { UserSpecificDataPacketDetails, UserSpecificDataPacketDetailsJson } from "../requestobjects/UserSpecificDataPacketDetails"; +export declare class UserSpecificDataPacketDetailsOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: UserSpecificDataPacketDetails; + constructor(request?: OrdinalVDXFObjectInterfaceTemplate); + static fromJson(details: OrdinalVDXFObjectJsonTemplate): UserSpecificDataPacketDetailsOrdinalVDXFObject; +} diff --git a/dist/vdxf/classes/ordinals/UserSpecificDataPacketDetailsOrdinalVDXFObject.js b/dist/vdxf/classes/ordinals/UserSpecificDataPacketDetailsOrdinalVDXFObject.js new file mode 100644 index 00000000..fd9b6c4b --- /dev/null +++ b/dist/vdxf/classes/ordinals/UserSpecificDataPacketDetailsOrdinalVDXFObject.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.UserSpecificDataPacketDetailsOrdinalVDXFObject = void 0; +const ordinals_1 = require("../../../constants/ordinals/ordinals"); +const SerializableEntityOrdinalVDXFObject_1 = require("./SerializableEntityOrdinalVDXFObject"); +const UserSpecificDataPacketDetails_1 = require("../requestobjects/UserSpecificDataPacketDetails"); +class UserSpecificDataPacketDetailsOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject_1.SerializableEntityOrdinalVDXFObject { + constructor(request = { + data: new UserSpecificDataPacketDetails_1.UserSpecificDataPacketDetails() + }) { + super({ + type: ordinals_1.VDXF_ORDINAL_USER_SPECIFIC_DATA_PACKET, + data: request.data + }, UserSpecificDataPacketDetails_1.UserSpecificDataPacketDetails); + } + static fromJson(details) { + return new UserSpecificDataPacketDetailsOrdinalVDXFObject({ + data: UserSpecificDataPacketDetails_1.UserSpecificDataPacketDetails.fromJson(details.data) + }); + } +} +exports.UserSpecificDataPacketDetailsOrdinalVDXFObject = UserSpecificDataPacketDetailsOrdinalVDXFObject; diff --git a/dist/vdxf/classes/ordinals/VerusPayInvoiceOrdinalVDXFObject.d.ts b/dist/vdxf/classes/ordinals/VerusPayInvoiceOrdinalVDXFObject.d.ts new file mode 100644 index 00000000..24a2fa43 --- /dev/null +++ b/dist/vdxf/classes/ordinals/VerusPayInvoiceOrdinalVDXFObject.d.ts @@ -0,0 +1,9 @@ +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { VerusPayInvoiceDetails, VerusPayInvoiceDetailsJson } from "../payment/VerusPayInvoiceDetails"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; +export declare class VerusPayInvoiceOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: VerusPayInvoiceDetails; + constructor(request?: OrdinalVDXFObjectInterfaceTemplate); + static fromJson(details: OrdinalVDXFObjectJsonTemplate): VerusPayInvoiceOrdinalVDXFObject; +} diff --git a/dist/vdxf/classes/ordinals/VerusPayInvoiceOrdinalVDXFObject.js b/dist/vdxf/classes/ordinals/VerusPayInvoiceOrdinalVDXFObject.js new file mode 100644 index 00000000..56b896f0 --- /dev/null +++ b/dist/vdxf/classes/ordinals/VerusPayInvoiceOrdinalVDXFObject.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.VerusPayInvoiceOrdinalVDXFObject = void 0; +const ordinals_1 = require("../../../constants/ordinals/ordinals"); +const VerusPayInvoiceDetails_1 = require("../payment/VerusPayInvoiceDetails"); +const SerializableEntityOrdinalVDXFObject_1 = require("./SerializableEntityOrdinalVDXFObject"); +class VerusPayInvoiceOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject_1.SerializableEntityOrdinalVDXFObject { + constructor(request = { + data: new VerusPayInvoiceDetails_1.VerusPayInvoiceDetails() + }) { + super({ + type: ordinals_1.VDXF_ORDINAL_VERUSPAY_INVOICE, + data: request.data + }, VerusPayInvoiceDetails_1.VerusPayInvoiceDetails); + } + static fromJson(details) { + return new VerusPayInvoiceOrdinalVDXFObject({ + data: VerusPayInvoiceDetails_1.VerusPayInvoiceDetails.fromJson(details.data) + }); + } +} +exports.VerusPayInvoiceOrdinalVDXFObject = VerusPayInvoiceOrdinalVDXFObject; diff --git a/dist/vdxf/classes/ordinals/index.d.ts b/dist/vdxf/classes/ordinals/index.d.ts new file mode 100644 index 00000000..f967e2ac --- /dev/null +++ b/dist/vdxf/classes/ordinals/index.d.ts @@ -0,0 +1,15 @@ +export * from './DataDescriptorOrdinalVDXFObject'; +export * from './IdentityUpdateRequestOrdinalVDXFObject'; +export * from './IdentityUpdateResponseOrdinalVDXFObject'; +export * from './OrdinalVDXFObject'; +export * from './OrdinalVDXFObjectOrdinalMap'; +export * from './SerializableEntityOrdinalVDXFObject'; +export * from './VerusPayInvoiceOrdinalVDXFObject'; +export * from './AuthenticationRequestOrdinalVDXFObject'; +export * from './AuthenticationResponseOrdinalVDXFObject'; +export * from './AppEncryptionRequestOrdinalVDXFObject'; +export * from './AppEncryptionResponseOrdinalVDXFObject'; +export * from './ProvisionIdentityDetailsOrdinalVDXFObject'; +export * from './DataPacketResponseOrdinalVDXFObject'; +export * from './UserDataRequestOrdinalVDXFObject'; +export * from './UserSpecificDataPacketDetailsOrdinalVDXFObject'; diff --git a/dist/vdxf/classes/ordinals/index.js b/dist/vdxf/classes/ordinals/index.js new file mode 100644 index 00000000..1a80910b --- /dev/null +++ b/dist/vdxf/classes/ordinals/index.js @@ -0,0 +1,33 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const register_1 = require("../../../constants/ordinals/register"); +__exportStar(require("./DataDescriptorOrdinalVDXFObject"), exports); +__exportStar(require("./IdentityUpdateRequestOrdinalVDXFObject"), exports); +__exportStar(require("./IdentityUpdateResponseOrdinalVDXFObject"), exports); +__exportStar(require("./OrdinalVDXFObject"), exports); +__exportStar(require("./OrdinalVDXFObjectOrdinalMap"), exports); +__exportStar(require("./SerializableEntityOrdinalVDXFObject"), exports); +__exportStar(require("./VerusPayInvoiceOrdinalVDXFObject"), exports); +__exportStar(require("./AuthenticationRequestOrdinalVDXFObject"), exports); +__exportStar(require("./AuthenticationResponseOrdinalVDXFObject"), exports); +__exportStar(require("./AppEncryptionRequestOrdinalVDXFObject"), exports); +__exportStar(require("./AppEncryptionResponseOrdinalVDXFObject"), exports); +__exportStar(require("./ProvisionIdentityDetailsOrdinalVDXFObject"), exports); +__exportStar(require("./DataPacketResponseOrdinalVDXFObject"), exports); +__exportStar(require("./UserDataRequestOrdinalVDXFObject"), exports); +__exportStar(require("./UserSpecificDataPacketDetailsOrdinalVDXFObject"), exports); +(0, register_1.registerOrdinals)(); diff --git a/dist/vdxf/classes/payment/VerusPayInvoice.d.ts b/dist/vdxf/classes/payment/VerusPayInvoice.d.ts index 1a3c38b9..2d01279c 100644 --- a/dist/vdxf/classes/payment/VerusPayInvoice.d.ts +++ b/dist/vdxf/classes/payment/VerusPayInvoice.d.ts @@ -1,11 +1,6 @@ import { VDXFObject, VerusIDSignature, VerusIDSignatureInterface, VerusIDSignatureJson } from "../../"; import { VerusPayInvoiceDetails, VerusPayInvoiceDetailsJson } from "./VerusPayInvoiceDetails"; import { BigNumber } from "../../../utils/types/BigNumber"; -export declare const VERUSPAY_VERSION_CURRENT: import("bn.js"); -export declare const VERUSPAY_VERSION_FIRSTVALID: import("bn.js"); -export declare const VERUSPAY_VERSION_LASTVALID: import("bn.js"); -export declare const VERUSPAY_VERSION_SIGNED: import("bn.js"); -export declare const VERUSPAY_VERSION_MASK: import("bn.js"); export interface VerusPayInvoiceInterface { details: VerusPayInvoiceDetails; system_id?: string; diff --git a/dist/vdxf/classes/payment/VerusPayInvoice.js b/dist/vdxf/classes/payment/VerusPayInvoice.js index 8e80103b..018b70d6 100644 --- a/dist/vdxf/classes/payment/VerusPayInvoice.js +++ b/dist/vdxf/classes/payment/VerusPayInvoice.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.VerusPayInvoice = exports.VERUSPAY_VERSION_MASK = exports.VERUSPAY_VERSION_SIGNED = exports.VERUSPAY_VERSION_LASTVALID = exports.VERUSPAY_VERSION_FIRSTVALID = exports.VERUSPAY_VERSION_CURRENT = void 0; +exports.VerusPayInvoice = void 0; const __1 = require("../../"); const keys_1 = require("../../keys"); const Hash160_1 = require("./../Hash160"); @@ -11,11 +11,7 @@ const createHash = require("create-hash"); const base64url_1 = require("base64url"); const VerusPayInvoiceDetails_1 = require("./VerusPayInvoiceDetails"); const bn_js_1 = require("bn.js"); -exports.VERUSPAY_VERSION_CURRENT = new bn_js_1.BN(3, 10); -exports.VERUSPAY_VERSION_FIRSTVALID = new bn_js_1.BN(3, 10); -exports.VERUSPAY_VERSION_LASTVALID = new bn_js_1.BN(3, 10); -exports.VERUSPAY_VERSION_SIGNED = new bn_js_1.BN('80000000', 16); -exports.VERUSPAY_VERSION_MASK = exports.VERUSPAY_VERSION_SIGNED; +const veruspay_1 = require("../../../constants/vdxf/veruspay"); class VerusPayInvoice extends __1.VDXFObject { constructor(request = { details: new VerusPayInvoiceDetails_1.VerusPayInvoiceDetails(), @@ -26,23 +22,23 @@ class VerusPayInvoice extends __1.VDXFObject { this.signature = request.signature ? new __1.VerusIDSignature(request.signature, keys_1.IDENTITY_AUTH_SIG_VDXF_KEY, false) : undefined; - this.details = new VerusPayInvoiceDetails_1.VerusPayInvoiceDetails(request.details); if (request.version) this.version = request.version; else - this.version = exports.VERUSPAY_VERSION_CURRENT; + this.version = veruspay_1.VERUSPAY_VERSION_CURRENT; + this.details = new VerusPayInvoiceDetails_1.VerusPayInvoiceDetails(request.details, this.getVersionNoFlags()); } getVersionNoFlags() { - return this.version.and(exports.VERUSPAY_VERSION_MASK.notn(exports.VERUSPAY_VERSION_MASK.bitLength())); + return this.version.and(veruspay_1.VERUSPAY_VERSION_MASK.notn(veruspay_1.VERUSPAY_VERSION_MASK.bitLength())); } isValidVersion() { - return this.getVersionNoFlags().gte(exports.VERUSPAY_VERSION_FIRSTVALID) && this.getVersionNoFlags().lte(exports.VERUSPAY_VERSION_LASTVALID); + return this.getVersionNoFlags().gte(veruspay_1.VERUSPAY_VERSION_FIRSTVALID) && this.getVersionNoFlags().lte(veruspay_1.VERUSPAY_VERSION_LASTVALID); } isSigned() { - return !!(this.version.and(exports.VERUSPAY_VERSION_SIGNED).toNumber()); + return !!(this.version.and(veruspay_1.VERUSPAY_VERSION_SIGNED).toNumber()); } setSigned() { - this.version = this.version.xor(exports.VERUSPAY_VERSION_SIGNED); + this.version = this.version.or(veruspay_1.VERUSPAY_VERSION_SIGNED); } getDetailsHash(signedBlockheight, signatureVersion = 2) { if (this.isSigned()) { @@ -123,7 +119,7 @@ class VerusPayInvoice extends __1.VDXFObject { this.signature = _sig; } const _details = new VerusPayInvoiceDetails_1.VerusPayInvoiceDetails(); - reader.offset = _details.fromBuffer(reader.buffer, reader.offset); + reader.offset = _details.fromBuffer(reader.buffer, reader.offset, this.getVersionNoFlags()); this.details = _details; } return reader.offset; @@ -150,7 +146,7 @@ class VerusPayInvoice extends __1.VDXFObject { } static fromJson(data) { return new VerusPayInvoice({ - details: VerusPayInvoiceDetails_1.VerusPayInvoiceDetails.fromJson(data.details), + details: VerusPayInvoiceDetails_1.VerusPayInvoiceDetails.fromJson(data.details, data.version ? new bn_js_1.BN(data.version) : veruspay_1.VERUSPAY_VERSION_CURRENT), signature: data.signature != null ? __1.VerusIDSignature.fromJson(data.signature) : undefined, signing_id: data.signing_id, system_id: data.system_id, diff --git a/dist/vdxf/classes/payment/VerusPayInvoiceDetails.d.ts b/dist/vdxf/classes/payment/VerusPayInvoiceDetails.d.ts index 426542f7..8b857b65 100644 --- a/dist/vdxf/classes/payment/VerusPayInvoiceDetails.d.ts +++ b/dist/vdxf/classes/payment/VerusPayInvoiceDetails.d.ts @@ -1,5 +1,8 @@ import { BigNumber } from '../../../utils/types/BigNumber'; import { TransferDestination, TransferDestinationJson } from '../../../pbaas/TransferDestination'; +import { SerializableEntity } from '../../../utils/types/SerializableEntity'; +import { SaplingPaymentAddress } from '../../../pbaas'; +import { CompactAddressObjectJson, CompactXAddressObject } from '../CompactAddressObject'; export declare const VERUSPAY_INVALID: import("bn.js"); export declare const VERUSPAY_VALID: import("bn.js"); export declare const VERUSPAY_ACCEPTS_CONVERSION: import("bn.js"); @@ -9,32 +12,39 @@ export declare const VERUSPAY_ACCEPTS_ANY_DESTINATION: import("bn.js"); export declare const VERUSPAY_ACCEPTS_ANY_AMOUNT: import("bn.js"); export declare const VERUSPAY_EXCLUDES_VERUS_BLOCKCHAIN: import("bn.js"); export declare const VERUSPAY_IS_TESTNET: import("bn.js"); +export declare const VERUSPAY_IS_PRECONVERT: import("bn.js"); +export declare const VERUSPAY_DESTINATION_IS_SAPLING_PAYMENT_ADDRESS: import("bn.js"); +export declare const VERUSPAY_IS_TAGGED: import("bn.js"); export type VerusPayInvoiceDetailsJson = { flags?: string; amount?: string; - destination?: TransferDestinationJson; + destination?: TransferDestinationJson | string; requestedcurrencyid: string; expiryheight?: string; maxestimatedslippage?: string; acceptedsystems?: Array; + tag?: CompactAddressObjectJson; }; -export declare class VerusPayInvoiceDetails { +export declare class VerusPayInvoiceDetails implements SerializableEntity { + verusPayVersion: BigNumber; flags: BigNumber; amount: BigNumber; - destination: TransferDestination; + destination: TransferDestination | SaplingPaymentAddress; requestedcurrencyid: string; expiryheight: BigNumber; maxestimatedslippage: BigNumber; acceptedsystems: Array; + tag: CompactXAddressObject; constructor(data?: { flags?: BigNumber; amount?: BigNumber; - destination?: TransferDestination; + destination?: TransferDestination | SaplingPaymentAddress; requestedcurrencyid: string; expiryheight?: BigNumber; maxestimatedslippage?: BigNumber; acceptedsystems?: Array; - }); + tag?: CompactXAddressObject; + }, verusPayVersion?: BigNumber); setFlags(flags: { acceptsConversion?: boolean; acceptsNonVerusSystems?: boolean; @@ -43,6 +53,9 @@ export declare class VerusPayInvoiceDetails { acceptsAnyDestination?: boolean; excludesVerusBlockchain?: boolean; isTestnet?: boolean; + isPreconvert?: boolean; + destinationIsSaplingPaymentAddress?: boolean; + isTagged?: boolean; }): void; getFlagsJson(): { [key: string]: boolean; @@ -55,10 +68,17 @@ export declare class VerusPayInvoiceDetails { expires(): boolean; excludesVerusBlockchain(): boolean; isTestnet(): boolean; + isPreconvert(): boolean; + destinationIsSaplingPaymentAddress(): boolean; + isTagged(): boolean; isValid(): boolean; + isGTEV4(): boolean; + private getVarUIntEncodingLength; + private writeVarUInt; + private readVarUInt; getByteLength(): number; toBuffer(): Buffer; - fromBuffer(buffer: Buffer, offset?: number): number; - static fromJson(data: VerusPayInvoiceDetailsJson): VerusPayInvoiceDetails; + fromBuffer(buffer: Buffer, offset?: number, verusPayVersion?: BigNumber): number; + static fromJson(data: VerusPayInvoiceDetailsJson, verusPayVersion?: BigNumber): VerusPayInvoiceDetails; toJson(): VerusPayInvoiceDetailsJson; } diff --git a/dist/vdxf/classes/payment/VerusPayInvoiceDetails.js b/dist/vdxf/classes/payment/VerusPayInvoiceDetails.js index 7bbbe77b..fd2ff37c 100644 --- a/dist/vdxf/classes/payment/VerusPayInvoiceDetails.js +++ b/dist/vdxf/classes/payment/VerusPayInvoiceDetails.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.VerusPayInvoiceDetails = exports.VERUSPAY_IS_TESTNET = exports.VERUSPAY_EXCLUDES_VERUS_BLOCKCHAIN = exports.VERUSPAY_ACCEPTS_ANY_AMOUNT = exports.VERUSPAY_ACCEPTS_ANY_DESTINATION = exports.VERUSPAY_EXPIRES = exports.VERUSPAY_ACCEPTS_NON_VERUS_SYSTEMS = exports.VERUSPAY_ACCEPTS_CONVERSION = exports.VERUSPAY_VALID = exports.VERUSPAY_INVALID = void 0; +exports.VerusPayInvoiceDetails = exports.VERUSPAY_IS_TAGGED = exports.VERUSPAY_DESTINATION_IS_SAPLING_PAYMENT_ADDRESS = exports.VERUSPAY_IS_PRECONVERT = exports.VERUSPAY_IS_TESTNET = exports.VERUSPAY_EXCLUDES_VERUS_BLOCKCHAIN = exports.VERUSPAY_ACCEPTS_ANY_AMOUNT = exports.VERUSPAY_ACCEPTS_ANY_DESTINATION = exports.VERUSPAY_EXPIRES = exports.VERUSPAY_ACCEPTS_NON_VERUS_SYSTEMS = exports.VERUSPAY_ACCEPTS_CONVERSION = exports.VERUSPAY_VALID = exports.VERUSPAY_INVALID = void 0; const varint_1 = require("../../../utils/varint"); const varuint_1 = require("../../../utils/varuint"); const bufferutils_1 = require("../../../utils/bufferutils"); @@ -9,18 +9,26 @@ const TransferDestination_1 = require("../../../pbaas/TransferDestination"); const address_1 = require("../../../utils/address"); const vdxf_1 = require("../../../constants/vdxf"); const createHash = require("create-hash"); +const veruspay_1 = require("../../../constants/vdxf/veruspay"); +const pbaas_1 = require("../../../pbaas"); +const CompactAddressObject_1 = require("../CompactAddressObject"); const { BufferReader, BufferWriter } = bufferutils_1.default; +// Added in V3 exports.VERUSPAY_INVALID = new bn_js_1.BN(0, 10); exports.VERUSPAY_VALID = new bn_js_1.BN(1, 10); exports.VERUSPAY_ACCEPTS_CONVERSION = new bn_js_1.BN(2, 10); exports.VERUSPAY_ACCEPTS_NON_VERUS_SYSTEMS = new bn_js_1.BN(4, 10); exports.VERUSPAY_EXPIRES = new bn_js_1.BN(8, 10); -exports.VERUSPAY_ACCEPTS_ANY_DESTINATION = new bn_js_1.BN(16, 0); -exports.VERUSPAY_ACCEPTS_ANY_AMOUNT = new bn_js_1.BN(32, 0); -exports.VERUSPAY_EXCLUDES_VERUS_BLOCKCHAIN = new bn_js_1.BN(64, 0); -exports.VERUSPAY_IS_TESTNET = new bn_js_1.BN(128, 0); +exports.VERUSPAY_ACCEPTS_ANY_DESTINATION = new bn_js_1.BN(16, 10); +exports.VERUSPAY_ACCEPTS_ANY_AMOUNT = new bn_js_1.BN(32, 10); +exports.VERUSPAY_EXCLUDES_VERUS_BLOCKCHAIN = new bn_js_1.BN(64, 10); +exports.VERUSPAY_IS_TESTNET = new bn_js_1.BN(128, 10); +// Added in V4 +exports.VERUSPAY_IS_PRECONVERT = new bn_js_1.BN(256, 10); +exports.VERUSPAY_DESTINATION_IS_SAPLING_PAYMENT_ADDRESS = new bn_js_1.BN(512, 10); +exports.VERUSPAY_IS_TAGGED = new bn_js_1.BN(1024, 10); class VerusPayInvoiceDetails { - constructor(data) { + constructor(data, verusPayVersion = veruspay_1.VERUSPAY_VERSION_CURRENT) { this.flags = exports.VERUSPAY_VALID; this.amount = null; this.destination = null; @@ -28,6 +36,8 @@ class VerusPayInvoiceDetails { this.expiryheight = null; this.maxestimatedslippage = null; this.acceptedsystems = null; + this.verusPayVersion = verusPayVersion; + this.tag = null; if (data != null) { if (data.flags != null) this.flags = data.flags; @@ -43,23 +53,33 @@ class VerusPayInvoiceDetails { this.maxestimatedslippage = data.maxestimatedslippage; if (data.acceptedsystems != null) this.acceptedsystems = data.acceptedsystems; + if (data.tag != null) + this.tag = data.tag; } } setFlags(flags) { if (flags.acceptsConversion) - this.flags = this.flags.xor(exports.VERUSPAY_ACCEPTS_CONVERSION); + this.flags = this.flags.or(exports.VERUSPAY_ACCEPTS_CONVERSION); if (flags.acceptsNonVerusSystems) - this.flags = this.flags.xor(exports.VERUSPAY_ACCEPTS_NON_VERUS_SYSTEMS); + this.flags = this.flags.or(exports.VERUSPAY_ACCEPTS_NON_VERUS_SYSTEMS); if (flags.expires) - this.flags = this.flags.xor(exports.VERUSPAY_EXPIRES); + this.flags = this.flags.or(exports.VERUSPAY_EXPIRES); if (flags.acceptsAnyAmount) - this.flags = this.flags.xor(exports.VERUSPAY_ACCEPTS_ANY_AMOUNT); + this.flags = this.flags.or(exports.VERUSPAY_ACCEPTS_ANY_AMOUNT); if (flags.acceptsAnyDestination) - this.flags = this.flags.xor(exports.VERUSPAY_ACCEPTS_ANY_DESTINATION); + this.flags = this.flags.or(exports.VERUSPAY_ACCEPTS_ANY_DESTINATION); if (flags.excludesVerusBlockchain) - this.flags = this.flags.xor(exports.VERUSPAY_EXCLUDES_VERUS_BLOCKCHAIN); + this.flags = this.flags.or(exports.VERUSPAY_EXCLUDES_VERUS_BLOCKCHAIN); if (flags.isTestnet) - this.flags = this.flags.xor(exports.VERUSPAY_IS_TESTNET); + this.flags = this.flags.or(exports.VERUSPAY_IS_TESTNET); + if (this.isGTEV4()) { + if (flags.isPreconvert) + this.flags = this.flags.or(exports.VERUSPAY_IS_PRECONVERT); + if (flags.destinationIsSaplingPaymentAddress) + this.flags = this.flags.or(exports.VERUSPAY_DESTINATION_IS_SAPLING_PAYMENT_ADDRESS); + if (flags.isTagged) + this.flags = this.flags.or(exports.VERUSPAY_IS_TAGGED); + } } getFlagsJson() { return { @@ -69,7 +89,10 @@ class VerusPayInvoiceDetails { acceptsAnyAmount: this.acceptsAnyAmount(), acceptsAnyDestination: this.acceptsAnyDestination(), excludesVerusBlockchain: this.excludesVerusBlockchain(), - isTestnet: this.isTestnet() + isTestnet: this.isTestnet(), + isPreconvert: this.isPreconvert(), + destinationIsSaplingPaymentAddress: this.destinationIsSaplingPaymentAddress(), + isTagged: this.isTagged() }; } toSha256() { @@ -96,94 +119,143 @@ class VerusPayInvoiceDetails { isTestnet() { return !!(this.flags.and(exports.VERUSPAY_IS_TESTNET).toNumber()); } + isPreconvert() { + return this.isGTEV4() && !!(this.flags.and(exports.VERUSPAY_IS_PRECONVERT).toNumber()); + } + destinationIsSaplingPaymentAddress() { + return this.isGTEV4() && !!(this.flags.and(exports.VERUSPAY_DESTINATION_IS_SAPLING_PAYMENT_ADDRESS).toNumber()); + } + isTagged() { + return this.isGTEV4() && !!(this.flags.and(exports.VERUSPAY_IS_TAGGED).toNumber()); + } isValid() { return (!!(this.flags.and(exports.VERUSPAY_VALID).toNumber())); } + isGTEV4() { + return (this.verusPayVersion.gte(veruspay_1.VERUSPAY_VERSION_4)); + } + // Functions to deal with change in v4 + getVarUIntEncodingLength(uint) { + return this.isGTEV4() ? varuint_1.default.encodingLength(uint.toNumber()) : varint_1.default.encodingLength(uint); + } + writeVarUInt(writer = new BufferWriter(Buffer.alloc(0)), uint) { + if (this.isGTEV4()) { + return writer.writeCompactSize(uint.toNumber()); + } + else { + return writer.writeVarInt(uint); + } + } + readVarUInt(reader = new BufferReader(Buffer.alloc(0))) { + if (this.isGTEV4()) { + return new bn_js_1.BN(reader.readCompactSize()); + } + else { + return reader.readVarInt(); + } + } getByteLength() { let length = 0; - length += varint_1.default.encodingLength(this.flags); + length += this.getVarUIntEncodingLength(this.flags); if (!this.acceptsAnyAmount()) { - length += varint_1.default.encodingLength(this.amount); + length += this.getVarUIntEncodingLength(this.amount); } if (!this.acceptsAnyDestination()) { length += this.destination.getByteLength(); } length += (0, address_1.fromBase58Check)(this.requestedcurrencyid).hash.length; if (this.expires()) { - length += varint_1.default.encodingLength(this.expiryheight); + length += this.getVarUIntEncodingLength(this.expiryheight); } if (this.acceptsConversion()) { - length += varint_1.default.encodingLength(this.maxestimatedslippage); + length += this.getVarUIntEncodingLength(this.maxestimatedslippage); } if (this.acceptsNonVerusSystems()) { length += varuint_1.default.encodingLength(this.acceptedsystems.length); this.acceptedsystems.forEach(() => { - length += 20; + length += vdxf_1.HASH160_BYTE_LENGTH; }); } + if (this.isTagged()) { + length += this.tag.getByteLength(); + } return length; } toBuffer() { const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); - writer.writeVarInt(this.flags); + this.writeVarUInt(writer, this.flags); if (!this.acceptsAnyAmount()) - writer.writeVarInt(this.amount); + this.writeVarUInt(writer, this.amount); if (!this.acceptsAnyDestination()) writer.writeSlice(this.destination.toBuffer()); writer.writeSlice((0, address_1.fromBase58Check)(this.requestedcurrencyid).hash); if (this.expires()) { - writer.writeVarInt(this.expiryheight); + this.writeVarUInt(writer, this.expiryheight); } if (this.acceptsConversion()) { - writer.writeVarInt(this.maxestimatedslippage); + this.writeVarUInt(writer, this.maxestimatedslippage); } if (this.acceptsNonVerusSystems()) { writer.writeArray(this.acceptedsystems.map(x => (0, address_1.fromBase58Check)(x).hash)); } + if (this.isTagged()) { + writer.writeSlice(this.tag.toBuffer()); + } return writer.buffer; } - fromBuffer(buffer, offset = 0) { + fromBuffer(buffer, offset = 0, verusPayVersion = veruspay_1.VERUSPAY_VERSION_CURRENT) { const reader = new BufferReader(buffer, offset); - this.flags = reader.readVarInt(); + this.verusPayVersion = verusPayVersion; + this.flags = this.readVarUInt(reader); if (!this.acceptsAnyAmount()) - this.amount = reader.readVarInt(); + this.amount = this.readVarUInt(reader); if (!this.acceptsAnyDestination()) { - this.destination = new TransferDestination_1.TransferDestination(); - reader.offset = this.destination.fromBuffer(buffer, reader.offset); + if (this.destinationIsSaplingPaymentAddress()) { + this.destination = new pbaas_1.SaplingPaymentAddress(); + } + else + this.destination = new TransferDestination_1.TransferDestination(); + reader.offset = this.destination.fromBuffer(reader.buffer, reader.offset); } this.requestedcurrencyid = (0, address_1.toBase58Check)(reader.readSlice(20), vdxf_1.I_ADDR_VERSION); if (this.expires()) { - this.expiryheight = reader.readVarInt(); + this.expiryheight = this.readVarUInt(reader); } if (this.acceptsConversion()) { - this.maxestimatedslippage = reader.readVarInt(); + this.maxestimatedslippage = this.readVarUInt(reader); } if (this.acceptsNonVerusSystems()) { const acceptedSystemsBuffers = reader.readArray(20); this.acceptedsystems = acceptedSystemsBuffers.map(x => (0, address_1.toBase58Check)(x, vdxf_1.I_ADDR_VERSION)); } + if (this.isTagged()) { + this.tag = new CompactAddressObject_1.CompactXAddressObject(); + reader.offset = this.tag.fromBuffer(reader.buffer, reader.offset); + } return reader.offset; } - static fromJson(data) { + static fromJson(data, verusPayVersion = veruspay_1.VERUSPAY_VERSION_CURRENT) { return new VerusPayInvoiceDetails({ flags: new bn_js_1.BN(data.flags), amount: data.amount != null ? new bn_js_1.BN(data.amount) : undefined, - destination: data.destination != null ? TransferDestination_1.TransferDestination.fromJson(data.destination) : undefined, + destination: data.destination != null ? typeof data.destination === 'string' ? pbaas_1.SaplingPaymentAddress.fromAddressString(data.destination) : TransferDestination_1.TransferDestination.fromJson(data.destination) : undefined, requestedcurrencyid: data.requestedcurrencyid, expiryheight: data.expiryheight != null ? new bn_js_1.BN(data.expiryheight) : undefined, maxestimatedslippage: data.maxestimatedslippage != null ? new bn_js_1.BN(data.maxestimatedslippage) : undefined, - acceptedsystems: data.acceptedsystems - }); + acceptedsystems: data.acceptedsystems, + tag: data.tag ? CompactAddressObject_1.CompactAddressObject.fromJson(data.tag) : undefined + }, verusPayVersion); } toJson() { return { flags: this.flags.toString(), amount: this.acceptsAnyAmount() ? undefined : this.amount.toString(), - destination: this.acceptsAnyDestination() ? undefined : this.destination.toJson(), + destination: this.acceptsAnyDestination() ? undefined : this.destinationIsSaplingPaymentAddress() ? this.destination.toAddressString() : this.destination.toJson(), requestedcurrencyid: this.requestedcurrencyid, expiryheight: this.expires() ? this.expiryheight.toString() : undefined, maxestimatedslippage: this.acceptsConversion() ? this.maxestimatedslippage.toString() : undefined, acceptedsystems: this.acceptsNonVerusSystems() ? this.acceptedsystems : undefined, + tag: this.isTagged() ? this.tag.toJson() : undefined }; } } diff --git a/dist/vdxf/classes/request/GenericRequest.d.ts b/dist/vdxf/classes/request/GenericRequest.d.ts new file mode 100644 index 00000000..ee60e691 --- /dev/null +++ b/dist/vdxf/classes/request/GenericRequest.d.ts @@ -0,0 +1,42 @@ +import { SerializableEntity } from "../../../utils/types/SerializableEntity"; +import { GenericEnvelope, GenericEnvelopeInterface, GenericEnvelopeJson } from "../envelope/GenericEnvelope"; +import { SaplingPaymentAddress } from '../../../pbaas/SaplingPaymentAddress'; +import { ResponseURI, ResponseURIJson } from '../ResponseURI'; +export type GenericRequestJson = GenericEnvelopeJson & { + responseuris?: Array; + encryptresponsetoaddress?: string; +}; +export type GenericRequestInterface = GenericEnvelopeInterface & { + responseURIs?: Array; + encryptResponseToAddress?: SaplingPaymentAddress; +}; +export declare class GenericRequest extends GenericEnvelope implements SerializableEntity { + responseURIs?: Array; + encryptResponseToAddress?: SaplingPaymentAddress; + static VERSION_CURRENT: import("bn.js"); + static VERSION_FIRSTVALID: import("bn.js"); + static VERSION_LASTVALID: import("bn.js"); + static BASE_FLAGS: import("bn.js"); + static FLAG_SIGNED: import("bn.js"); + static FLAG_HAS_CREATED_AT: import("bn.js"); + static FLAG_MULTI_DETAILS: import("bn.js"); + static FLAG_IS_TESTNET: import("bn.js"); + static FLAG_HAS_SALT: import("bn.js"); + static FLAG_HAS_APP_OR_DELEGATED_ID: import("bn.js"); + static FLAG_HAS_RESPONSE_URIS: import("bn.js"); + static FLAG_HAS_ENCRYPT_RESPONSE_TO_ADDRESS: import("bn.js"); + constructor(envelope?: GenericRequestInterface); + hasResponseURIs(): boolean; + hasEncryptResponseToAddress(): boolean; + setHasResponseURIs(): void; + setHasEncryptResponseToAddress(): void; + setFlags(): void; + getByteLengthOptionalSig(includeSig?: boolean): number; + toBufferOptionalSig(includeSig?: boolean): Buffer; + fromBuffer(buffer: Buffer, offset?: number): number; + toJson(): GenericRequestJson; + static fromWalletDeeplinkUri(uri: string): GenericRequest; + static fromQrString(qrstring: string): GenericRequest; + toWalletDeeplinkUri(): string; + toQrString(): string; +} diff --git a/dist/vdxf/classes/request/GenericRequest.js b/dist/vdxf/classes/request/GenericRequest.js new file mode 100644 index 00000000..ac241f1b --- /dev/null +++ b/dist/vdxf/classes/request/GenericRequest.js @@ -0,0 +1,137 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.GenericRequest = void 0; +const bn_js_1 = require("bn.js"); +const GenericEnvelope_1 = require("../envelope/GenericEnvelope"); +const SaplingPaymentAddress_1 = require("../../../pbaas/SaplingPaymentAddress"); +const bufferutils_1 = require("../../../utils/bufferutils"); +const base64url_1 = require("base64url"); +const deeplink_1 = require("../../../constants/deeplink"); +const ResponseURI_1 = require("../ResponseURI"); +const varuint_1 = require("../../../utils/varuint"); +class GenericRequest extends GenericEnvelope_1.GenericEnvelope { + constructor(envelope = { + details: [], + flags: GenericRequest.BASE_FLAGS + }) { + super(envelope); + this.responseURIs = envelope === null || envelope === void 0 ? void 0 : envelope.responseURIs; + this.encryptResponseToAddress = envelope === null || envelope === void 0 ? void 0 : envelope.encryptResponseToAddress; + this.setFlags(); + } + hasResponseURIs() { + return !!(this.flags.and(GenericRequest.FLAG_HAS_RESPONSE_URIS).toNumber()); + } + hasEncryptResponseToAddress() { + return !!(this.flags.and(GenericRequest.FLAG_HAS_ENCRYPT_RESPONSE_TO_ADDRESS).toNumber()); + } + setHasResponseURIs() { + this.flags = this.flags.or(GenericRequest.FLAG_HAS_RESPONSE_URIS); + } + setHasEncryptResponseToAddress() { + this.flags = this.flags.or(GenericRequest.FLAG_HAS_ENCRYPT_RESPONSE_TO_ADDRESS); + } + setFlags() { + super.setFlags(); + if (this.responseURIs) + this.setHasResponseURIs(); + if (this.encryptResponseToAddress) + this.setHasEncryptResponseToAddress(); + } + getByteLengthOptionalSig(includeSig = true) { + let length = super.getByteLengthOptionalSig(includeSig); + if (this.hasResponseURIs()) { + length += varuint_1.default.encodingLength(this.responseURIs.length); + for (let i = 0; i < this.responseURIs.length; i++) { + length += this.responseURIs[i].getByteLength(); + } + } + if (this.hasEncryptResponseToAddress()) { + length += this.encryptResponseToAddress.getByteLength(); + } + return length; + } + toBufferOptionalSig(includeSig = true) { + const writer = new bufferutils_1.default.BufferWriter(Buffer.alloc(this.getByteLengthOptionalSig(includeSig))); + const superBuf = super.toBufferOptionalSig(includeSig); + writer.writeSlice(superBuf); + if (this.hasResponseURIs()) { + writer.writeCompactSize(this.responseURIs.length); + for (let i = 0; i < this.responseURIs.length; i++) { + writer.writeSlice(this.responseURIs[i].toBuffer()); + } + } + if (this.hasEncryptResponseToAddress()) { + writer.writeSlice(this.encryptResponseToAddress.toBuffer()); + } + return writer.buffer; + } + fromBuffer(buffer, offset) { + if (buffer.length == 0) + throw new Error("Cannot create request from empty buffer"); + const reader = new bufferutils_1.default.BufferReader(buffer, offset); + reader.offset = super.fromBuffer(reader.buffer, reader.offset); + if (this.hasResponseURIs()) { + this.responseURIs = []; + const callbackURIsLength = reader.readCompactSize(); + for (let i = 0; i < callbackURIsLength; i++) { + const newURI = new ResponseURI_1.ResponseURI(); + reader.offset = newURI.fromBuffer(reader.buffer, reader.offset); + this.responseURIs.push(newURI); + } + } + if (this.hasEncryptResponseToAddress()) { + this.encryptResponseToAddress = new SaplingPaymentAddress_1.SaplingPaymentAddress(); + reader.offset = this.encryptResponseToAddress.fromBuffer(reader.buffer, reader.offset); + } + return reader.offset; + } + toJson() { + const parentJson = super.toJson(); + if (this.hasResponseURIs()) { + parentJson["responseuris"] = this.responseURIs.map(x => x.toJson()); + } + if (this.hasEncryptResponseToAddress()) { + parentJson["encryptresponsetoaddress"] = this.encryptResponseToAddress.toAddressString(); + } + return parentJson; + } + static fromWalletDeeplinkUri(uri) { + const urlProtocol = `${deeplink_1.DEEPLINK_PROTOCOL_URL_STRING}:`; + const split = uri.split(`/`); + if (split.length !== 4 || split.some(x => x == null)) + throw new Error("Unrecognized URL format"); + if (split[0] !== urlProtocol) + throw new Error("Unrecognized URL protocol"); + else if (isNaN(Number(split[2])) || !(new bn_js_1.BN(split[2], 10).eq(deeplink_1.DEEPLINK_PROTOCOL_URL_CURRENT_VERSION))) { + throw new Error("Unrecognized or incompatible generic request protocol version"); + } + const inv = new GenericRequest(); + inv.fromBuffer(base64url_1.default.toBuffer(split[3]), 0); + return inv; + } + static fromQrString(qrstring) { + const inv = new GenericRequest(); + inv.fromBuffer(base64url_1.default.toBuffer(qrstring), 0); + return inv; + } + toWalletDeeplinkUri() { + return `${deeplink_1.DEEPLINK_PROTOCOL_URL_STRING}://${deeplink_1.DEEPLINK_PROTOCOL_URL_CURRENT_VERSION.toString()}/${this.toString()}`; + } + toQrString() { + return this.toString(); + } +} +exports.GenericRequest = GenericRequest; +GenericRequest.VERSION_CURRENT = new bn_js_1.BN(1, 10); +GenericRequest.VERSION_FIRSTVALID = new bn_js_1.BN(1, 10); +GenericRequest.VERSION_LASTVALID = new bn_js_1.BN(1, 10); +GenericRequest.BASE_FLAGS = GenericEnvelope_1.GenericEnvelope.BASE_FLAGS; +GenericRequest.FLAG_SIGNED = GenericEnvelope_1.GenericEnvelope.FLAG_SIGNED; +GenericRequest.FLAG_HAS_CREATED_AT = GenericEnvelope_1.GenericEnvelope.FLAG_HAS_CREATED_AT; +GenericRequest.FLAG_MULTI_DETAILS = GenericEnvelope_1.GenericEnvelope.FLAG_MULTI_DETAILS; +GenericRequest.FLAG_IS_TESTNET = GenericEnvelope_1.GenericEnvelope.FLAG_IS_TESTNET; +GenericRequest.FLAG_HAS_SALT = GenericEnvelope_1.GenericEnvelope.FLAG_HAS_SALT; +GenericRequest.FLAG_HAS_APP_OR_DELEGATED_ID = GenericEnvelope_1.GenericEnvelope.FLAG_HAS_APP_OR_DELEGATED_ID; +GenericRequest.FLAG_HAS_RESPONSE_URIS = new bn_js_1.BN(128, 10); +GenericRequest.FLAG_HAS_ENCRYPT_RESPONSE_TO_ADDRESS = new bn_js_1.BN(256, 10); diff --git a/dist/vdxf/classes/requestobjects/AppEncryptionRequestDetails.d.ts b/dist/vdxf/classes/requestobjects/AppEncryptionRequestDetails.d.ts new file mode 100644 index 00000000..757b8af4 --- /dev/null +++ b/dist/vdxf/classes/requestobjects/AppEncryptionRequestDetails.d.ts @@ -0,0 +1,70 @@ +/** + * AppEncryptionRequestDetails - Class for handling application requests for encrypted derived seeds + * + * This class is used when an application is requesting an encrypted derived seed from the user's master seed, + * using specific parameters passed by the application. The request includes: + * - App or delegated ID making the request (mandatory) + * - A target encryption key (zaddress format) for encrypting the reply + * - Derivation number for seed generation + * - Optional derivation ID (defaults to Z-address from ID signing if not present) + * - Optional request ID for tracking + * + * The user's wallet can use these parameters to derive a specific seed from their master seed + * and encrypt it using the provided encryption key, ensuring the application receives only + * the specific derived seed it needs without exposing the master seed. + * + * The RETURN_ESK flag can be set to signal that the Extended Spending Key should be returned. + */ +import { BigNumber } from '../../../utils/types/BigNumber'; +import { SerializableEntity } from '../../../utils/types/SerializableEntity'; +import { CompactAddressObject, CompactAddressObjectJson } from '../CompactAddressObject'; +export interface AppEncryptionRequestInterface { + version?: BigNumber; + flags: BigNumber; + encryptToZAddress: string; + derivationNumber: BigNumber; + derivationID?: CompactAddressObject; + requestID?: string; +} +export interface AppEncryptionRequestJson { + version: number; + flags: number; + encrypttozaddress: string; + derivationnumber: number; + derivationid?: CompactAddressObjectJson; + requestid?: string; +} +/** + * Checks if a string is a valid hexadecimal address + * @param flags - Optional flags for the request + * @flag HAS_REQUEST_ID - Indicates if a request ID is included + * + * @param encryptToZAddress - The encryption key to use for encrypting to + * @param derivationNumber - The derivation number to validate + */ +export declare class AppEncryptionRequestDetails implements SerializableEntity { + static VERSION_INVALID: import("bn.js"); + static FIRST_VERSION: import("bn.js"); + static LAST_VERSION: import("bn.js"); + static DEFAULT_VERSION: import("bn.js"); + static HAS_DERIVATION_ID: import("bn.js"); + static HAS_REQUEST_ID: import("bn.js"); + static RETURN_ESK: import("bn.js"); + version: BigNumber; + flags: BigNumber; + encryptToZAddress: string; + derivationNumber: BigNumber; + derivationID?: CompactAddressObject; + requestID?: string; + constructor(data?: AppEncryptionRequestInterface); + setFlags(): void; + calcFlags(): BigNumber; + isValid(): boolean; + hasDerivationID(flags?: BigNumber): boolean; + hasRequestID(flags?: BigNumber): boolean; + getByteLength(): number; + toBuffer(): Buffer; + fromBuffer(buffer: Buffer, offset?: number): number; + toJson(): AppEncryptionRequestJson; + static fromJson(json: AppEncryptionRequestJson): AppEncryptionRequestDetails; +} diff --git a/dist/vdxf/classes/requestobjects/AppEncryptionRequestDetails.js b/dist/vdxf/classes/requestobjects/AppEncryptionRequestDetails.js new file mode 100644 index 00000000..606652b8 --- /dev/null +++ b/dist/vdxf/classes/requestobjects/AppEncryptionRequestDetails.js @@ -0,0 +1,159 @@ +"use strict"; +/** + * AppEncryptionRequestDetails - Class for handling application requests for encrypted derived seeds + * + * This class is used when an application is requesting an encrypted derived seed from the user's master seed, + * using specific parameters passed by the application. The request includes: + * - App or delegated ID making the request (mandatory) + * - A target encryption key (zaddress format) for encrypting the reply + * - Derivation number for seed generation + * - Optional derivation ID (defaults to Z-address from ID signing if not present) + * - Optional request ID for tracking + * + * The user's wallet can use these parameters to derive a specific seed from their master seed + * and encrypt it using the provided encryption key, ensuring the application receives only + * the specific derived seed it needs without exposing the master seed. + * + * The RETURN_ESK flag can be set to signal that the Extended Spending Key should be returned. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AppEncryptionRequestDetails = void 0; +const bn_js_1 = require("bn.js"); +const bufferutils_1 = require("../../../utils/bufferutils"); +const { BufferReader, BufferWriter } = bufferutils_1.default; +const sapling_1 = require("../../../utils/sapling"); +const CompactAddressObject_1 = require("../CompactAddressObject"); +const varuint_1 = require("../../../utils/varuint"); +const address_1 = require("../../../utils/address"); +const vdxf_1 = require("../../../constants/vdxf"); +/** + * Checks if a string is a valid hexadecimal address + * @param flags - Optional flags for the request + * @flag HAS_REQUEST_ID - Indicates if a request ID is included + * + * @param encryptToZAddress - The encryption key to use for encrypting to + * @param derivationNumber - The derivation number to validate + */ +class AppEncryptionRequestDetails { + constructor(data) { + this.version = (data === null || data === void 0 ? void 0 : data.version) || AppEncryptionRequestDetails.DEFAULT_VERSION; + this.flags = (data === null || data === void 0 ? void 0 : data.flags) || new bn_js_1.BN(0); + this.encryptToZAddress = (data === null || data === void 0 ? void 0 : data.encryptToZAddress) || ''; + this.derivationNumber = (data === null || data === void 0 ? void 0 : data.derivationNumber) || new bn_js_1.BN(0); + this.derivationID = data === null || data === void 0 ? void 0 : data.derivationID; + this.requestID = data === null || data === void 0 ? void 0 : data.requestID; + this.setFlags(); + } + setFlags() { + this.flags = this.calcFlags(); + } + calcFlags() { + let flags = new bn_js_1.BN(0); + if (this.derivationID != null) { + flags = flags.or(AppEncryptionRequestDetails.HAS_DERIVATION_ID); + } + if (this.requestID != null) { + flags = flags.or(AppEncryptionRequestDetails.HAS_REQUEST_ID); + } + return flags; + } + isValid() { + let valid = true; + valid && (valid = this.encryptToZAddress != null && this.encryptToZAddress.length > 0); + valid && (valid = this.derivationNumber != null && this.derivationNumber.gte(new bn_js_1.BN(0))); + return valid; + } + hasDerivationID(flags = this.flags) { + return flags.and(AppEncryptionRequestDetails.HAS_DERIVATION_ID).gt(new bn_js_1.BN(0)); + } + hasRequestID(flags = this.flags) { + return flags.and(AppEncryptionRequestDetails.HAS_REQUEST_ID).gt(new bn_js_1.BN(0)); + } + getByteLength() { + const flags = this.calcFlags(); + let length = 0; + length += varuint_1.default.encodingLength(flags.toNumber()); + // encryptToKey - zaddress encoding (43 bytes for sapling address data) + length += 43; // Sapling address decoded data (11 + 32 bytes) + length += varuint_1.default.encodingLength(this.derivationNumber.toNumber()); + if (this.hasDerivationID(flags)) { + length += this.derivationID.getByteLength(); + } + if (this.hasRequestID(flags)) { + length += vdxf_1.HASH160_BYTE_LENGTH; + } + return length; + } + toBuffer() { + const flags = this.calcFlags(); + const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); + // Write flags + writer.writeCompactSize(flags.toNumber()); + // Write encryptToAddress as decoded sapling address data + const saplingData = (0, sapling_1.decodeSaplingAddress)(this.encryptToZAddress); + writer.writeSlice(Buffer.concat([saplingData.d, saplingData.pk_d])); + // Write mandatory derivation number + writer.writeVarInt(this.derivationNumber); + if (this.hasDerivationID(flags)) { + writer.writeSlice(this.derivationID.toBuffer()); + } + if (this.hasRequestID(flags)) { + writer.writeSlice((0, address_1.fromBase58Check)(this.requestID).hash); + } + return writer.buffer; + } + fromBuffer(buffer, offset) { + const reader = new BufferReader(buffer, offset); + // Read flags + this.flags = new bn_js_1.BN(reader.readCompactSize()); + // Read encryptToAddress as 43-byte sapling data and encode as sapling address + const saplingData = reader.readSlice(43); + this.encryptToZAddress = (0, sapling_1.toBech32)('zs', saplingData); + // Read mandatory derivation number + this.derivationNumber = reader.readVarInt(); + if (this.hasDerivationID()) { + const derivationIDObj = new CompactAddressObject_1.CompactAddressObject(); + reader.offset = derivationIDObj.fromBuffer(reader.buffer, reader.offset); + this.derivationID = derivationIDObj; + } + if (this.hasRequestID()) { + this.requestID = (0, address_1.toBase58Check)(reader.readSlice(20), vdxf_1.I_ADDR_VERSION); + } + return reader.offset; + } + toJson() { + var _a; + // Set flags before serialization + const flags = this.calcFlags(); + return { + version: this.version.toNumber(), + flags: flags.toNumber(), + encrypttozaddress: this.encryptToZAddress, + derivationnumber: this.derivationNumber.toNumber(), + derivationid: (_a = this.derivationID) === null || _a === void 0 ? void 0 : _a.toJson(), + requestid: this.requestID + }; + } + static fromJson(json) { + const instance = new AppEncryptionRequestDetails(); + instance.version = new bn_js_1.BN(json.version); + instance.flags = new bn_js_1.BN(json.flags); + instance.encryptToZAddress = json.encrypttozaddress; + instance.derivationNumber = new bn_js_1.BN(json.derivationnumber); + if (instance.hasDerivationID()) { + instance.derivationID = CompactAddressObject_1.CompactAddressObject.fromJson(json === null || json === void 0 ? void 0 : json.derivationid); + } + if (instance.hasRequestID()) { + instance.requestID = json === null || json === void 0 ? void 0 : json.requestid; + } + return instance; + } +} +exports.AppEncryptionRequestDetails = AppEncryptionRequestDetails; +AppEncryptionRequestDetails.VERSION_INVALID = new bn_js_1.BN(0); +AppEncryptionRequestDetails.FIRST_VERSION = new bn_js_1.BN(1); +AppEncryptionRequestDetails.LAST_VERSION = new bn_js_1.BN(1); +AppEncryptionRequestDetails.DEFAULT_VERSION = new bn_js_1.BN(1); +AppEncryptionRequestDetails.HAS_DERIVATION_ID = new bn_js_1.BN(1); +AppEncryptionRequestDetails.HAS_REQUEST_ID = new bn_js_1.BN(2); +AppEncryptionRequestDetails.RETURN_ESK = new bn_js_1.BN(4); //flag to signal to return the Extended Spending Key diff --git a/dist/vdxf/classes/requestobjects/ProvisionIdentityDetails.d.ts b/dist/vdxf/classes/requestobjects/ProvisionIdentityDetails.d.ts new file mode 100644 index 00000000..9a276b49 --- /dev/null +++ b/dist/vdxf/classes/requestobjects/ProvisionIdentityDetails.d.ts @@ -0,0 +1,57 @@ +/** + * ProvisioningIdentity - Class for handling identity provisioning requests + * + * This class is used when an application is requesting the provisioning or creation of a new identity + * within the Verus blockchain ecosystem. The request includes: + * - System ID (e.g., VRSC@) defining the blockchain system + * - Parent ID (e.g., Token@) defining the parent namespace + * - Identity ID (e.g., john.VRSC@) defining the full identity to be provisioned + * - Flags indicating which components are present and required + * + * The user's wallet can use these parameters to understand the complete identity hierarchy + * and present a clear provisioning request to the user, showing the system context, + * parent namespace, and the specific identity being created. This enables secure, + * user-controlled identity provisioning with proper namespace management. + */ +import { BigNumber } from "../../../utils/types/BigNumber"; +import { SerializableEntity } from "../../../utils/types/SerializableEntity"; +import { CompactIAddressObject, CompactAddressObjectJson } from "../CompactAddressObject"; +export interface ProvisionIdentityDetailsInterface { + version?: BigNumber; + flags: BigNumber; + systemID?: CompactIAddressObject; + parentID?: CompactIAddressObject; + identityID?: CompactIAddressObject; +} +export interface ProvisionIdentityDetailsJson { + version?: number; + flags: number; + systemid?: CompactAddressObjectJson; + parentid?: CompactAddressObjectJson; + identityid?: CompactAddressObjectJson; +} +export declare class ProvisionIdentityDetails implements SerializableEntity { + version: BigNumber; + flags: BigNumber; + systemID?: CompactIAddressObject; + parentID?: CompactIAddressObject; + identityID?: CompactIAddressObject; + static DEFAULT_VERSION: import("bn.js"); + static VERSION_FIRSTVALID: import("bn.js"); + static VERSION_LASTVALID: import("bn.js"); + static FLAG_HAS_SYSTEMID: import("bn.js"); + static FLAG_HAS_PARENTID: import("bn.js"); + static FLAG_IS_A_DEFINED_NAME_TO_PROVISION: import("bn.js"); + constructor(data?: ProvisionIdentityDetailsInterface); + hasSystemId(): boolean; + hasParentId(): boolean; + hasIdentityId(): boolean; + getByteLength(): number; + toBuffer(): Buffer; + fromBuffer(buffer: Buffer, offset?: number): number; + toJson(): ProvisionIdentityDetailsJson; + static fromJson(data: any): ProvisionIdentityDetails; + calcFlags(): BigNumber; + setFlags(): void; + isValid(): boolean; +} diff --git a/dist/vdxf/classes/requestobjects/ProvisionIdentityDetails.js b/dist/vdxf/classes/requestobjects/ProvisionIdentityDetails.js new file mode 100644 index 00000000..0bb24fbb --- /dev/null +++ b/dist/vdxf/classes/requestobjects/ProvisionIdentityDetails.js @@ -0,0 +1,146 @@ +"use strict"; +/** + * ProvisioningIdentity - Class for handling identity provisioning requests + * + * This class is used when an application is requesting the provisioning or creation of a new identity + * within the Verus blockchain ecosystem. The request includes: + * - System ID (e.g., VRSC@) defining the blockchain system + * - Parent ID (e.g., Token@) defining the parent namespace + * - Identity ID (e.g., john.VRSC@) defining the full identity to be provisioned + * - Flags indicating which components are present and required + * + * The user's wallet can use these parameters to understand the complete identity hierarchy + * and present a clear provisioning request to the user, showing the system context, + * parent namespace, and the specific identity being created. This enables secure, + * user-controlled identity provisioning with proper namespace management. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ProvisionIdentityDetails = void 0; +const bufferutils_1 = require("../../../utils/bufferutils"); +const bn_js_1 = require("bn.js"); +const CompactAddressObject_1 = require("../CompactAddressObject"); +const varuint_1 = require("../../../utils/varuint"); +class ProvisionIdentityDetails { + constructor(data) { + this.version = (data === null || data === void 0 ? void 0 : data.version) || ProvisionIdentityDetails.DEFAULT_VERSION; + this.flags = (data === null || data === void 0 ? void 0 : data.flags) || new bn_js_1.BN(0, 10); + this.systemID = data === null || data === void 0 ? void 0 : data.systemID; + this.parentID = data === null || data === void 0 ? void 0 : data.parentID; + this.identityID = data === null || data === void 0 ? void 0 : data.identityID; + this.setFlags(); + } + hasSystemId() { + return this.flags.and(ProvisionIdentityDetails.FLAG_HAS_SYSTEMID).eq(ProvisionIdentityDetails.FLAG_HAS_SYSTEMID); + } + hasParentId() { + return this.flags.and(ProvisionIdentityDetails.FLAG_HAS_PARENTID).eq(ProvisionIdentityDetails.FLAG_HAS_PARENTID); + } + hasIdentityId() { + return this.flags.and(ProvisionIdentityDetails.FLAG_IS_A_DEFINED_NAME_TO_PROVISION).eq(ProvisionIdentityDetails.FLAG_IS_A_DEFINED_NAME_TO_PROVISION); + } + getByteLength() { + let length = 0; + length += varuint_1.default.encodingLength(this.flags.toNumber()); + if (this.hasSystemId()) { + length += this.systemID.getByteLength(); + } + if (this.hasParentId()) { + length += this.parentID.getByteLength(); + } + if (this.hasIdentityId()) { + length += this.identityID.getByteLength(); + } + return length; + } + toBuffer() { + const writer = new bufferutils_1.default.BufferWriter(Buffer.alloc(this.getByteLength())); + writer.writeCompactSize(this.flags.toNumber()); + if (this.hasSystemId()) { + writer.writeSlice(this.systemID.toBuffer()); + } + if (this.hasParentId()) { + writer.writeSlice(this.parentID.toBuffer()); + } + if (this.hasIdentityId()) { + writer.writeSlice(this.identityID.toBuffer()); + } + return writer.buffer; + } + fromBuffer(buffer, offset) { + const reader = new bufferutils_1.default.BufferReader(buffer, offset); + if (buffer.length == 0) + throw new Error("Cannot create provision identity from empty buffer"); + this.flags = new bn_js_1.BN(reader.readCompactSize()); + if (this.hasSystemId()) { + const systemID = new CompactAddressObject_1.CompactIAddressObject(); + reader.offset = systemID.fromBuffer(reader.buffer, reader.offset); + this.systemID = systemID; + } + if (this.hasParentId()) { + const parentID = new CompactAddressObject_1.CompactIAddressObject(); + reader.offset = parentID.fromBuffer(reader.buffer, reader.offset); + this.parentID = parentID; + } + if (this.hasIdentityId()) { + const identityID = new CompactAddressObject_1.CompactIAddressObject(); + reader.offset = identityID.fromBuffer(reader.buffer, reader.offset); + this.identityID = identityID; + } + return reader.offset; + } + toJson() { + const flags = this.calcFlags(); + return { + version: this.version.toNumber(), + flags: flags.toNumber(), + systemid: this.systemID ? this.systemID.toJson() : null, + parentid: this.parentID ? this.parentID.toJson() : null, + identityid: this.identityID ? this.identityID.toJson() : null, + }; + } + static fromJson(data) { + const provision = new ProvisionIdentityDetails(); + provision.version = new bn_js_1.BN((data === null || data === void 0 ? void 0 : data.version) || 0); + provision.flags = new bn_js_1.BN((data === null || data === void 0 ? void 0 : data.flags) || 0); + if (provision.hasSystemId()) { + provision.systemID = CompactAddressObject_1.CompactIAddressObject.fromCompactAddressObjectJson(data.systemid); + } + if (provision.hasParentId()) { + provision.parentID = CompactAddressObject_1.CompactIAddressObject.fromCompactAddressObjectJson(data.parentid); + } + if (provision.hasIdentityId()) { + provision.identityID = CompactAddressObject_1.CompactIAddressObject.fromCompactAddressObjectJson(data.identityid); + } + return provision; + } + calcFlags() { + let flags = new bn_js_1.BN(0, 10); + if (this.systemID) { + flags = flags.or(ProvisionIdentityDetails.FLAG_HAS_SYSTEMID); + } + if (this.parentID) { + flags = flags.or(ProvisionIdentityDetails.FLAG_HAS_PARENTID); + } + if (this.identityID) { + flags = flags.or(ProvisionIdentityDetails.FLAG_IS_A_DEFINED_NAME_TO_PROVISION); + } + return flags; + } + setFlags() { + this.flags = this.calcFlags(); + } + isValid() { + let valid = this.flags != null && this.flags.gte(new bn_js_1.BN(0)); + valid && (valid = this.version != null); + return valid; + } +} +exports.ProvisionIdentityDetails = ProvisionIdentityDetails; +// Version +ProvisionIdentityDetails.DEFAULT_VERSION = new bn_js_1.BN(1, 10); +ProvisionIdentityDetails.VERSION_FIRSTVALID = new bn_js_1.BN(1, 10); +ProvisionIdentityDetails.VERSION_LASTVALID = new bn_js_1.BN(1, 10); +// flags include params // parent same as signer +ProvisionIdentityDetails.FLAG_HAS_SYSTEMID = new bn_js_1.BN(1, 10); +ProvisionIdentityDetails.FLAG_HAS_PARENTID = new bn_js_1.BN(2, 10); +ProvisionIdentityDetails.FLAG_IS_A_DEFINED_NAME_TO_PROVISION = new bn_js_1.BN(4, 10); diff --git a/dist/vdxf/classes/requestobjects/UserDataRequestDetails.d.ts b/dist/vdxf/classes/requestobjects/UserDataRequestDetails.d.ts new file mode 100644 index 00000000..9eb0b365 --- /dev/null +++ b/dist/vdxf/classes/requestobjects/UserDataRequestDetails.d.ts @@ -0,0 +1,88 @@ +/** + * InformationRequest - Class for handling application requests for specific user information/data + * + * This class is used when an application is requesting specific information or data from the user's + * identity or data stores. The request includes: + * - Search data keys (VDXF keys) to identify the specific data being requested + * - Optional specific keys within the data object for partial data requests + * - Signer information to identify wanted signer of the data + * - Optional statement for boundhashes in the signature + * + * The user's wallet can use these parameters to locate the signed object information and present + * it to the user for approval before sharing with the requesting application. This enables + * selective disclosure of personal information while maintaining user privacy and control. + * + * Flags determine the type and scope of the request: + * - FULL_DATA vs PARTIAL_DATA: Whether complete objects or specific fields are requested + * - COLLECTION: Whether multiple data objects are being requested + * - HAS_STATEMENT: Whether the request includes an attestation statement + * - ATTESTATION/CLAIM/CREDENTIAL: Type of verification being requested + */ +import { BigNumber } from '../../../utils/types/BigNumber'; +import { SerializableEntity } from '../../../utils/types/SerializableEntity'; +import { CompactIAddressObject, CompactAddressObjectJson } from '../CompactAddressObject'; +export interface UserDataRequestInterface { + version?: BigNumber; + flags: BigNumber; + searchDataKey: Array<{ + [key: string]: string; + }>; + signer?: CompactIAddressObject; + requestedKeys?: string[]; + requestID?: string; +} +export interface UserDataRequestJson { + version: number; + flags: number; + searchdatakey: Array<{ + [key: string]: string; + }>; + signer?: CompactAddressObjectJson; + requestedkeys?: string[]; + requestid?: string; +} +export declare class UserDataRequestDetails implements SerializableEntity { + static VERSION_INVALID: import("bn.js"); + static FIRST_VERSION: import("bn.js"); + static LAST_VERSION: import("bn.js"); + static DEFAULT_VERSION: import("bn.js"); + static FULL_DATA: import("bn.js"); + static PARTIAL_DATA: import("bn.js"); + static COLLECTION: import("bn.js"); + static ATTESTATION: import("bn.js"); + static CLAIM: import("bn.js"); + static CREDENTIAL: import("bn.js"); + static HAS_SIGNER: import("bn.js"); + static HAS_REQUESTED_KEYS: import("bn.js"); + static HAS_REQUEST_ID: import("bn.js"); + version: BigNumber; + flags: BigNumber; + searchDataKey: Array<{ + [key: string]: string; + }>; + signer?: CompactIAddressObject; + requestedKeys?: string[]; + requestID?: string; + constructor(data?: UserDataRequestInterface); + calcFlags(): BigNumber; + setFlags(): void; + hasSigner(): boolean; + hasRequestedKeys(): boolean; + hasRequestID(): boolean; + /** + * Checks if exactly one data type flag is set (FULL_DATA, PARTIAL_DATA, or COLLECTION) + * @returns True if exactly one data type flag is set + */ + hasDataTypeSet(): boolean; + /** + * Checks if exactly one request type flag is set (ATTESTATION, CLAIM, or CREDENTIAL) + * @returns True if exactly one request type flag is set + */ + hasRequestTypeSet(): boolean; + isValid(): boolean; + getByteLength(): number; + toBuffer(): Buffer; + fromBuffer(buffer: Buffer, offset?: number): number; + toJson(): UserDataRequestJson; + static fromJson(json: UserDataRequestJson): UserDataRequestDetails; +} diff --git a/dist/vdxf/classes/requestobjects/UserDataRequestDetails.js b/dist/vdxf/classes/requestobjects/UserDataRequestDetails.js new file mode 100644 index 00000000..b65ca506 --- /dev/null +++ b/dist/vdxf/classes/requestobjects/UserDataRequestDetails.js @@ -0,0 +1,214 @@ +"use strict"; +/** + * InformationRequest - Class for handling application requests for specific user information/data + * + * This class is used when an application is requesting specific information or data from the user's + * identity or data stores. The request includes: + * - Search data keys (VDXF keys) to identify the specific data being requested + * - Optional specific keys within the data object for partial data requests + * - Signer information to identify wanted signer of the data + * - Optional statement for boundhashes in the signature + * + * The user's wallet can use these parameters to locate the signed object information and present + * it to the user for approval before sharing with the requesting application. This enables + * selective disclosure of personal information while maintaining user privacy and control. + * + * Flags determine the type and scope of the request: + * - FULL_DATA vs PARTIAL_DATA: Whether complete objects or specific fields are requested + * - COLLECTION: Whether multiple data objects are being requested + * - HAS_STATEMENT: Whether the request includes an attestation statement + * - ATTESTATION/CLAIM/CREDENTIAL: Type of verification being requested + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.UserDataRequestDetails = void 0; +const bn_js_1 = require("bn.js"); +const varuint_1 = require("../../../utils/varuint"); +const bufferutils_1 = require("../../../utils/bufferutils"); +const { BufferReader, BufferWriter } = bufferutils_1.default; +const CompactAddressObject_1 = require("../CompactAddressObject"); +const address_1 = require("../../../utils/address"); +const vdxf_1 = require("../../../constants/vdxf"); +class UserDataRequestDetails { + constructor(data) { + this.version = (data === null || data === void 0 ? void 0 : data.version) || UserDataRequestDetails.DEFAULT_VERSION; + this.flags = (data === null || data === void 0 ? void 0 : data.flags) || new bn_js_1.BN(0); + this.searchDataKey = (data === null || data === void 0 ? void 0 : data.searchDataKey) || []; + this.signer = data === null || data === void 0 ? void 0 : data.signer; + this.requestedKeys = data === null || data === void 0 ? void 0 : data.requestedKeys; + this.requestID = data === null || data === void 0 ? void 0 : data.requestID; + this.setFlags(); + } + calcFlags() { + let flags = new bn_js_1.BN(0); + if (this.requestedKeys && this.requestedKeys.length > 0) { + flags = flags.or(UserDataRequestDetails.HAS_REQUESTED_KEYS); + } + if (this.signer) { + flags = flags.or(UserDataRequestDetails.HAS_SIGNER); + } + if (this.requestID) { + flags = flags.or(UserDataRequestDetails.HAS_REQUEST_ID); + } + return flags; + } + setFlags() { + this.flags = this.calcFlags(); + } + hasSigner() { + return this.flags.and(UserDataRequestDetails.HAS_SIGNER).eq(UserDataRequestDetails.HAS_SIGNER); + } + hasRequestedKeys() { + return this.flags.and(UserDataRequestDetails.HAS_REQUESTED_KEYS).eq(UserDataRequestDetails.HAS_REQUESTED_KEYS); + } + hasRequestID() { + return this.flags.and(UserDataRequestDetails.HAS_REQUEST_ID).eq(UserDataRequestDetails.HAS_REQUEST_ID); + } + /** + * Checks if exactly one data type flag is set (FULL_DATA, PARTIAL_DATA, or COLLECTION) + * @returns True if exactly one data type flag is set + */ + hasDataTypeSet() { + const dataTypeFlags = UserDataRequestDetails.FULL_DATA.or(UserDataRequestDetails.PARTIAL_DATA).or(UserDataRequestDetails.COLLECTION); + const setDataFlags = this.flags.and(dataTypeFlags); + // Check if exactly one flag is set by verifying it's a power of 2 + return !setDataFlags.isZero() && setDataFlags.and(setDataFlags.sub(new bn_js_1.BN(1))).isZero(); + } + /** + * Checks if exactly one request type flag is set (ATTESTATION, CLAIM, or CREDENTIAL) + * @returns True if exactly one request type flag is set + */ + hasRequestTypeSet() { + const requestTypeFlags = UserDataRequestDetails.ATTESTATION.or(UserDataRequestDetails.CLAIM).or(UserDataRequestDetails.CREDENTIAL); + const setRequestFlags = this.flags.and(requestTypeFlags); + // Check if exactly one flag is set by verifying it's a power of 2 + return !setRequestFlags.isZero() && setRequestFlags.and(setRequestFlags.sub(new bn_js_1.BN(1))).isZero(); + } + isValid() { + let valid = this.version.gte(UserDataRequestDetails.FIRST_VERSION) && this.version.lte(UserDataRequestDetails.LAST_VERSION); + // Check that exactly one data type flag is set + valid && (valid = this.hasDataTypeSet()); + // Check that exactly one request type flag is set + valid && (valid = this.hasRequestTypeSet()); + // Check that searchDataKey is present + valid && (valid = Object.keys(this.searchDataKey).length > 0); + return valid; + } + getByteLength() { + let length = 0; + length += varuint_1.default.encodingLength(this.flags.toNumber()); + length += varuint_1.default.encodingLength(this.searchDataKey.length); + for (const item of this.searchDataKey) { + const key = Object.keys(item)[0]; + const value = item[key]; + length += vdxf_1.HASH160_BYTE_LENGTH; + length += varuint_1.default.encodingLength(Buffer.byteLength(value, 'utf8')); + length += Buffer.byteLength(value, 'utf8'); + } + if (this.hasSigner()) { + length += this.signer.getByteLength(); + } + if (this.hasRequestedKeys()) { + length += varuint_1.default.encodingLength(this.requestedKeys ? this.requestedKeys.length : 0); + if (this.requestedKeys) { + for (const key of this.requestedKeys) { + length += vdxf_1.HASH160_BYTE_LENGTH; + } + } + } + if (this.hasRequestID()) { + length += vdxf_1.HASH160_BYTE_LENGTH; + } + return length; + } + toBuffer() { + const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); + writer.writeCompactSize(this.flags.toNumber()); + writer.writeCompactSize(this.searchDataKey.length); + for (const item of this.searchDataKey) { + const key = Object.keys(item)[0]; + const value = item[key]; + writer.writeSlice((0, address_1.fromBase58Check)(key).hash); // 20-byte VDXF key + writer.writeVarSlice(Buffer.from(value, 'utf8')); + } + if (this.hasSigner()) { + writer.writeSlice(this.signer.toBuffer()); + } + if (this.hasRequestedKeys()) { + writer.writeCompactSize(this.requestedKeys.length); + for (const key of this.requestedKeys) { + writer.writeSlice((0, address_1.fromBase58Check)(key).hash); // 20-byte VDXF key + } + } + if (this.hasRequestID()) { + writer.writeSlice((0, address_1.fromBase58Check)(this.requestID).hash); + } + return writer.buffer; + } + fromBuffer(buffer, offset) { + const reader = new BufferReader(buffer, offset); + this.flags = new bn_js_1.BN(reader.readCompactSize()); + const searchDataKeyLength = reader.readCompactSize(); + this.searchDataKey = []; + for (let i = 0; i < searchDataKeyLength; i++) { + const keyHash = reader.readSlice(vdxf_1.HASH160_BYTE_LENGTH); // 20-byte VDXF key + const valueBuffer = reader.readVarSlice(); + const value = valueBuffer.toString('utf8'); + const key = (0, address_1.toBase58Check)(keyHash, vdxf_1.I_ADDR_VERSION); + this.searchDataKey.push({ [key]: value }); + } + if (this.hasSigner()) { + const signer = new CompactAddressObject_1.CompactIAddressObject(); + reader.offset = signer.fromBuffer(reader.buffer, reader.offset); + this.signer = signer; + } + if (this.hasRequestedKeys()) { + const requestedKeysLength = reader.readCompactSize(); + this.requestedKeys = []; + for (let i = 0; i < requestedKeysLength; i++) { + const keyHash = reader.readSlice(20); // 20-byte VDXF key + const key = (0, address_1.toBase58Check)(keyHash, vdxf_1.I_ADDR_VERSION); + this.requestedKeys.push(key); + } + } + if (this.hasRequestID()) { + this.requestID = (0, address_1.toBase58Check)(reader.readSlice(20), vdxf_1.I_ADDR_VERSION); + } + return reader.offset; + } + toJson() { + var _a; + const flags = this.calcFlags(); + return { + version: this.version.toNumber(), + flags: flags.toNumber(), + searchdatakey: this.searchDataKey, + signer: (_a = this.signer) === null || _a === void 0 ? void 0 : _a.toJson(), + requestedkeys: this.requestedKeys, + requestid: this.requestID + }; + } + static fromJson(json) { + const requestData = new UserDataRequestDetails(); + requestData.version = new bn_js_1.BN(json.version); + requestData.flags = new bn_js_1.BN(json.flags); + requestData.searchDataKey = json.searchdatakey; + requestData.signer = json.signer ? CompactAddressObject_1.CompactIAddressObject.fromCompactAddressObjectJson(json.signer) : undefined; + requestData.requestedKeys = json.requestedkeys; + requestData.requestID = json.requestid; + return requestData; + } +} +exports.UserDataRequestDetails = UserDataRequestDetails; +UserDataRequestDetails.VERSION_INVALID = new bn_js_1.BN(0); +UserDataRequestDetails.FIRST_VERSION = new bn_js_1.BN(1); +UserDataRequestDetails.LAST_VERSION = new bn_js_1.BN(1); +UserDataRequestDetails.DEFAULT_VERSION = new bn_js_1.BN(1); +UserDataRequestDetails.FULL_DATA = new bn_js_1.BN(1); +UserDataRequestDetails.PARTIAL_DATA = new bn_js_1.BN(2); +UserDataRequestDetails.COLLECTION = new bn_js_1.BN(4); +UserDataRequestDetails.ATTESTATION = new bn_js_1.BN(8); +UserDataRequestDetails.CLAIM = new bn_js_1.BN(16); +UserDataRequestDetails.CREDENTIAL = new bn_js_1.BN(32); +UserDataRequestDetails.HAS_SIGNER = new bn_js_1.BN(64); +UserDataRequestDetails.HAS_REQUESTED_KEYS = new bn_js_1.BN(128); +UserDataRequestDetails.HAS_REQUEST_ID = new bn_js_1.BN(256); diff --git a/dist/vdxf/classes/requestobjects/UserSpecificDataPacketDetails.d.ts b/dist/vdxf/classes/requestobjects/UserSpecificDataPacketDetails.d.ts new file mode 100644 index 00000000..6d52a609 --- /dev/null +++ b/dist/vdxf/classes/requestobjects/UserSpecificDataPacketDetails.d.ts @@ -0,0 +1,69 @@ +/** + * UserSpecificDataPacketDetails - Class for sending personal data to user or requesting the user + * signature on personal data + * + * This class is used when an application is requesting to transfer or receive personal + * user data. The request includes: + * - Data objects as DataDescriptor instances containing the user's personal data + * - Optional statements array for additional context or transfer conditions + * - Optional signature data for verification of the transfer + * - Flags indicating transfer direction and optional components + * + * The user's wallet can use these parameters to present the data transfer request + * to the user, showing what personal data is being transferred, any associated + * statements or conditions, and whether it's for the user's signature or being + * transmitted to/from the user. This enables secure, user-controlled personal + * data sharing with clear visibility into what data is being transferred. + * + + */ +import { BigNumber } from '../../../utils/types/BigNumber'; +import { SerializableEntity } from '../../../utils/types/SerializableEntity'; +import { DataDescriptor, DataDescriptorJson } from '../../../pbaas'; +import { VerifiableSignatureData, VerifiableSignatureDataJson } from '../VerifiableSignatureData'; +export interface UserSpecificDataPacketDetailsInterface { + version?: BigNumber; + flags: BigNumber; + signableObjects: Array; + statements?: Array; + signature?: VerifiableSignatureData; + detailsID?: string; +} +export interface UserSpecificDataPacketDetailsJson { + version: number; + flags: number; + signableobjects: Array; + statements?: Array; + signature?: VerifiableSignatureDataJson; + detailsid?: string; +} +export declare class UserSpecificDataPacketDetails implements SerializableEntity { + static VERSION_INVALID: import("bn.js"); + static FIRST_VERSION: import("bn.js"); + static LAST_VERSION: import("bn.js"); + static DEFAULT_VERSION: import("bn.js"); + static HAS_STATEMENTS: import("bn.js"); + static HAS_SIGNATURE: import("bn.js"); + static FOR_USERS_SIGNATURE: import("bn.js"); + static FOR_TRANSMITTAL_TO_USER: import("bn.js"); + static HAS_URL_FOR_DOWNLOAD: import("bn.js"); + static HAS_DETAILS_ID: import("bn.js"); + version: BigNumber; + flags: BigNumber; + signableObjects: Array; + statements?: Array; + signature?: VerifiableSignatureData; + detailsID?: string; + constructor(data?: UserSpecificDataPacketDetailsInterface); + setFlags(): void; + calcFlags(): BigNumber; + hasStatements(): boolean; + hasSignature(): boolean; + hasDetailsID(): boolean; + isValid(): boolean; + getByteLength(): number; + toBuffer(): Buffer; + fromBuffer(buffer: Buffer, offset?: number): number; + toJson(): UserSpecificDataPacketDetailsJson; + static fromJson(json: UserSpecificDataPacketDetailsJson): UserSpecificDataPacketDetails; +} diff --git a/dist/vdxf/classes/requestobjects/UserSpecificDataPacketDetails.js b/dist/vdxf/classes/requestobjects/UserSpecificDataPacketDetails.js new file mode 100644 index 00000000..a4d68238 --- /dev/null +++ b/dist/vdxf/classes/requestobjects/UserSpecificDataPacketDetails.js @@ -0,0 +1,195 @@ +"use strict"; +/** + * UserSpecificDataPacketDetails - Class for sending personal data to user or requesting the user + * signature on personal data + * + * This class is used when an application is requesting to transfer or receive personal + * user data. The request includes: + * - Data objects as DataDescriptor instances containing the user's personal data + * - Optional statements array for additional context or transfer conditions + * - Optional signature data for verification of the transfer + * - Flags indicating transfer direction and optional components + * + * The user's wallet can use these parameters to present the data transfer request + * to the user, showing what personal data is being transferred, any associated + * statements or conditions, and whether it's for the user's signature or being + * transmitted to/from the user. This enables secure, user-controlled personal + * data sharing with clear visibility into what data is being transferred. + * + + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.UserSpecificDataPacketDetails = void 0; +const bn_js_1 = require("bn.js"); +const varuint_1 = require("../../../utils/varuint"); +const bufferutils_1 = require("../../../utils/bufferutils"); +const { BufferReader, BufferWriter } = bufferutils_1.default; +const pbaas_1 = require("../../../pbaas"); +const VerifiableSignatureData_1 = require("../VerifiableSignatureData"); +const address_1 = require("../../../utils/address"); +const vdxf_1 = require("../../../constants/vdxf"); +// User_specific_data_packet +class UserSpecificDataPacketDetails { + constructor(data) { + this.version = (data === null || data === void 0 ? void 0 : data.version) || UserSpecificDataPacketDetails.DEFAULT_VERSION; + this.flags = (data === null || data === void 0 ? void 0 : data.flags) || new bn_js_1.BN(0); + this.signableObjects = (data === null || data === void 0 ? void 0 : data.signableObjects) || []; + this.statements = (data === null || data === void 0 ? void 0 : data.statements) || []; + this.signature = (data === null || data === void 0 ? void 0 : data.signature) || undefined; + this.detailsID = data === null || data === void 0 ? void 0 : data.detailsID; + this.setFlags(); + } + setFlags() { + this.flags = this.calcFlags(); + } + calcFlags() { + let flags = new bn_js_1.BN(0); + if (this.statements && this.statements.length > 0) { + flags = flags.or(UserSpecificDataPacketDetails.HAS_STATEMENTS); + } + if (this.signature) { + flags = flags.or(UserSpecificDataPacketDetails.HAS_SIGNATURE); + } + if (this.detailsID) { + flags = flags.or(UserSpecificDataPacketDetails.HAS_DETAILS_ID); + } + return flags; + } + hasStatements() { + return this.flags.and(UserSpecificDataPacketDetails.HAS_STATEMENTS).eq(UserSpecificDataPacketDetails.HAS_STATEMENTS); + } + hasSignature() { + return this.flags.and(UserSpecificDataPacketDetails.HAS_SIGNATURE).eq(UserSpecificDataPacketDetails.HAS_SIGNATURE); + } + hasDetailsID() { + return this.flags.and(UserSpecificDataPacketDetails.HAS_DETAILS_ID).eq(UserSpecificDataPacketDetails.HAS_DETAILS_ID); + } + isValid() { + let valid = this.version.gte(UserSpecificDataPacketDetails.FIRST_VERSION) && + this.version.lte(UserSpecificDataPacketDetails.LAST_VERSION); + // Check that we have signable objects + valid && (valid = this.signableObjects.length > 0); + if (this.hasStatements()) { + valid && (valid = this.statements !== undefined && this.statements.length > 0); + } + if (this.hasSignature()) { + valid && (valid = this.signature !== undefined); // TODO: && this.signature.isValid(); + } + return valid; + } + getByteLength() { + let length = 0; + length += varuint_1.default.encodingLength(this.flags.toNumber()); + // Add length for signableObjects array + length += varuint_1.default.encodingLength(this.signableObjects.length); + for (const obj of this.signableObjects) { + length += obj.getByteLength(); + } + // Add signer length if present + if (this.hasStatements()) { + length += varuint_1.default.encodingLength(this.statements.length); + for (const stmt of this.statements) { + length += varuint_1.default.encodingLength(Buffer.byteLength(stmt, 'utf8')); + length += Buffer.byteLength(stmt, 'utf8'); + } + } + if (this.hasSignature() && this.signature) { + length += this.signature.getByteLength(); + } + if (this.hasDetailsID()) { + length += vdxf_1.HASH160_BYTE_LENGTH; + } + return length; + } + toBuffer() { + const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); + writer.writeCompactSize(this.flags.toNumber()); + // Write signableObjects array + writer.writeCompactSize(this.signableObjects.length); + for (const obj of this.signableObjects) { + writer.writeSlice(obj.toBuffer()); + } + // Write statements if present + if (this.hasStatements()) { + writer.writeCompactSize(this.statements.length); + for (const stmt of this.statements) { + writer.writeVarSlice(Buffer.from(stmt, 'utf8')); + } + } + if (this.hasSignature() && this.signature) { + writer.writeSlice(this.signature.toBuffer()); + } + if (this.hasDetailsID()) { + writer.writeSlice((0, address_1.fromBase58Check)(this.detailsID).hash); + } + return writer.buffer; + } + fromBuffer(buffer, offset) { + const reader = new BufferReader(buffer, offset); + this.flags = new bn_js_1.BN(reader.readCompactSize()); + // Read signableObjects array + const objectCount = reader.readCompactSize(); + this.signableObjects = []; + for (let i = 0; i < objectCount; i++) { + const obj = new pbaas_1.DataDescriptor(); + reader.offset = obj.fromBuffer(reader.buffer, reader.offset); + this.signableObjects.push(obj); + } + // Read statements if flag is set + if (this.hasStatements()) { + this.statements = []; + const statementCount = reader.readCompactSize(); + for (let i = 0; i < statementCount; i++) { + const stmt = reader.readVarSlice().toString('utf8'); + this.statements.push(stmt); + } + } + if (this.hasSignature()) { + const signature = new VerifiableSignatureData_1.VerifiableSignatureData(); + reader.offset = signature.fromBuffer(reader.buffer, reader.offset); + this.signature = signature; + } + if (this.hasDetailsID()) { + this.detailsID = (0, address_1.toBase58Check)(reader.readSlice(20), vdxf_1.I_ADDR_VERSION); + } + return reader.offset; + } + toJson() { + const flags = this.calcFlags(); + return { + version: this.version.toNumber(), + flags: flags.toNumber(), + signableobjects: this.signableObjects.map(obj => obj.toJson()), + statements: this.statements, + signature: this.signature ? this.signature.toJson() : undefined, + detailsid: this.detailsID + }; + } + static fromJson(json) { + const instance = new UserSpecificDataPacketDetails(); + instance.version = new bn_js_1.BN(json.version); + instance.flags = new bn_js_1.BN(json.flags); + const dataDescriptorObjects = []; + for (const objJson of json.signableobjects) { + const dataDescriptor = pbaas_1.DataDescriptor.fromJson(objJson); + dataDescriptorObjects.push(dataDescriptor); + } + instance.signableObjects = dataDescriptorObjects; + instance.statements = json.statements || []; + instance.signature = json.signature ? VerifiableSignatureData_1.VerifiableSignatureData.fromJson(json.signature) : undefined; + instance.detailsID = json.detailsid; + return instance; + } +} +exports.UserSpecificDataPacketDetails = UserSpecificDataPacketDetails; +UserSpecificDataPacketDetails.VERSION_INVALID = new bn_js_1.BN(0); +UserSpecificDataPacketDetails.FIRST_VERSION = new bn_js_1.BN(1); +UserSpecificDataPacketDetails.LAST_VERSION = new bn_js_1.BN(1); +UserSpecificDataPacketDetails.DEFAULT_VERSION = new bn_js_1.BN(1); +// types of data to sign +UserSpecificDataPacketDetails.HAS_STATEMENTS = new bn_js_1.BN(1); +UserSpecificDataPacketDetails.HAS_SIGNATURE = new bn_js_1.BN(2); +UserSpecificDataPacketDetails.FOR_USERS_SIGNATURE = new bn_js_1.BN(4); +UserSpecificDataPacketDetails.FOR_TRANSMITTAL_TO_USER = new bn_js_1.BN(8); +UserSpecificDataPacketDetails.HAS_URL_FOR_DOWNLOAD = new bn_js_1.BN(16); +UserSpecificDataPacketDetails.HAS_DETAILS_ID = new bn_js_1.BN(32); diff --git a/dist/vdxf/classes/response/AppEncryptionResponseDetails.d.ts b/dist/vdxf/classes/response/AppEncryptionResponseDetails.d.ts new file mode 100644 index 00000000..b9ba93c6 --- /dev/null +++ b/dist/vdxf/classes/response/AppEncryptionResponseDetails.d.ts @@ -0,0 +1,45 @@ +import { BigNumber } from '../../../utils/types/BigNumber'; +import { SerializableEntity } from '../../../utils/types/SerializableEntity'; +import { SaplingPaymentAddress } from '../../../pbaas'; +import { SaplingExtendedSpendingKey } from '../../../pbaas/SaplingExtendedSpendingKey'; +import { SaplingExtendedViewingKey } from '../../../pbaas/SaplingExtendedViewingKey'; +export interface AppEncryptionResponseDetailsInterface { + version: BigNumber; + flags?: BigNumber; + requestID?: string; + incomingViewingKey: Buffer; + extendedViewingKey: SaplingExtendedViewingKey; + address: SaplingPaymentAddress; + extendedSpendingKey?: SaplingExtendedSpendingKey; +} +export interface AppEncryptionResponseDetailsJson { + version: number; + flags?: number; + requestid?: string; + incomingviewingkey: string; + extendedviewingkey: string; + address: string; + extendedspendingkey?: string; +} +export declare class AppEncryptionResponseDetails implements SerializableEntity { + version: BigNumber; + flags: BigNumber; + requestID?: string; + incomingViewingKey: Buffer; + extendedViewingKey: SaplingExtendedViewingKey; + address: SaplingPaymentAddress; + extendedSpendingKey?: SaplingExtendedSpendingKey; + static RESPONSE_CONTAINS_REQUEST_ID: import("bn.js"); + static RESPONSE_CONTAINS_EXTENDED_SPENDING_KEY: import("bn.js"); + constructor(data?: AppEncryptionResponseDetailsInterface); + containsRequestID(): boolean; + toggleContainsRequestID(): void; + containsExtendedSpendingKey(): boolean; + toggleContainsExtendedSpendingKey(): void; + toSha256(): Buffer; + getByteLength(): number; + toBuffer(): Buffer; + fromBuffer(buffer: Buffer, offset?: number): number; + toJson(): AppEncryptionResponseDetailsJson; + static fromJson(json: AppEncryptionResponseDetailsJson): AppEncryptionResponseDetails; +} diff --git a/dist/vdxf/classes/response/AppEncryptionResponseDetails.js b/dist/vdxf/classes/response/AppEncryptionResponseDetails.js new file mode 100644 index 00000000..9e1f08ed --- /dev/null +++ b/dist/vdxf/classes/response/AppEncryptionResponseDetails.js @@ -0,0 +1,119 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AppEncryptionResponseDetails = void 0; +const bn_js_1 = require("bn.js"); +const varint_1 = require("../../../utils/varint"); +const bufferutils_1 = require("../../../utils/bufferutils"); +const { BufferReader, BufferWriter } = bufferutils_1.default; +const address_1 = require("../../../utils/address"); +const vdxf_1 = require("../../../constants/vdxf"); +const pbaas_1 = require("../../../pbaas"); +const createHash = require("create-hash"); +const SaplingExtendedSpendingKey_1 = require("../../../pbaas/SaplingExtendedSpendingKey"); +const SaplingExtendedViewingKey_1 = require("../../../pbaas/SaplingExtendedViewingKey"); +class AppEncryptionResponseDetails { + constructor(data) { + var _a, _b, _c, _d, _e; + this.version = (_a = data === null || data === void 0 ? void 0 : data.version) !== null && _a !== void 0 ? _a : new bn_js_1.BN(1); + this.flags = (_b = data === null || data === void 0 ? void 0 : data.flags) !== null && _b !== void 0 ? _b : new bn_js_1.BN(0, 10); + this.incomingViewingKey = (_c = data === null || data === void 0 ? void 0 : data.incomingViewingKey) !== null && _c !== void 0 ? _c : Buffer.alloc(32); + this.extendedViewingKey = (_d = data === null || data === void 0 ? void 0 : data.extendedViewingKey) !== null && _d !== void 0 ? _d : new SaplingExtendedViewingKey_1.SaplingExtendedViewingKey(); + this.address = (_e = data === null || data === void 0 ? void 0 : data.address) !== null && _e !== void 0 ? _e : new pbaas_1.SaplingPaymentAddress(); + if (data === null || data === void 0 ? void 0 : data.requestID) { + if (!this.containsRequestID()) + this.toggleContainsRequestID(); + this.requestID = data.requestID; + } + if (data === null || data === void 0 ? void 0 : data.extendedSpendingKey) { + if (!this.containsExtendedSpendingKey()) + this.toggleContainsExtendedSpendingKey(); + this.extendedSpendingKey = data.extendedSpendingKey; + } + } + containsRequestID() { + return !!(this.flags.and(AppEncryptionResponseDetails.RESPONSE_CONTAINS_REQUEST_ID).toNumber()); + } + toggleContainsRequestID() { + this.flags = this.flags.xor(AppEncryptionResponseDetails.RESPONSE_CONTAINS_REQUEST_ID); + } + containsExtendedSpendingKey() { + return !!(this.flags.and(AppEncryptionResponseDetails.RESPONSE_CONTAINS_EXTENDED_SPENDING_KEY).toNumber()); + } + toggleContainsExtendedSpendingKey() { + this.flags = this.flags.xor(AppEncryptionResponseDetails.RESPONSE_CONTAINS_EXTENDED_SPENDING_KEY); + } + toSha256() { + return createHash("sha256").update(this.toBuffer()).digest(); + } + getByteLength() { + let length = 0; + length += varint_1.default.encodingLength(this.flags); + if (this.containsRequestID()) { + length += vdxf_1.HASH160_BYTE_LENGTH; + } + length += 32; // incomingViewingKey + length += this.extendedViewingKey.getByteLength(); + length += this.address.getByteLength(); + if (this.containsExtendedSpendingKey()) { + length += this.extendedSpendingKey.getByteLength(); + } + return length; + } + toBuffer() { + const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); + writer.writeVarInt(this.flags); + if (this.containsRequestID()) { + writer.writeSlice((0, address_1.fromBase58Check)(this.requestID).hash); + } + writer.writeSlice(this.incomingViewingKey); + writer.writeSlice(this.extendedViewingKey.toBuffer()); + writer.writeSlice(this.address.toBuffer()); + if (this.containsExtendedSpendingKey()) { + writer.writeSlice(this.extendedSpendingKey.toBuffer()); + } + return writer.buffer; + } + fromBuffer(buffer, offset = 0) { + const reader = new BufferReader(buffer, offset); + this.flags = reader.readVarInt(); + if (this.containsRequestID()) { + this.requestID = (0, address_1.toBase58Check)(reader.readSlice(vdxf_1.HASH160_BYTE_LENGTH), vdxf_1.I_ADDR_VERSION); + } + this.incomingViewingKey = reader.readSlice(32); + this.extendedViewingKey = new SaplingExtendedViewingKey_1.SaplingExtendedViewingKey(); + reader.offset = this.extendedViewingKey.fromBuffer(reader.buffer, reader.offset); + this.address = new pbaas_1.SaplingPaymentAddress(); + reader.offset = this.address.fromBuffer(reader.buffer, reader.offset); + if (this.containsExtendedSpendingKey()) { + this.extendedSpendingKey = new SaplingExtendedSpendingKey_1.SaplingExtendedSpendingKey(); + reader.offset = this.extendedSpendingKey.fromBuffer(reader.buffer, reader.offset); + } + return reader.offset; + } + toJson() { + return { + version: this.version.toNumber(), + flags: this.flags.toNumber(), + requestid: this.containsRequestID() ? this.requestID : undefined, + incomingviewingkey: this.incomingViewingKey.toString('hex'), + extendedviewingkey: this.extendedViewingKey.toKeyString(), + address: this.address.toAddressString(), + extendedspendingkey: this.containsExtendedSpendingKey() ? this.extendedSpendingKey.toKeyString() : undefined + }; + } + static fromJson(json) { + var _a; + return new AppEncryptionResponseDetails({ + version: new bn_js_1.BN(json.version, 10), + flags: new bn_js_1.BN((_a = json.flags) !== null && _a !== void 0 ? _a : 0, 10), + requestID: json.requestid, + incomingViewingKey: Buffer.from(json.incomingviewingkey, 'hex'), + extendedViewingKey: SaplingExtendedViewingKey_1.SaplingExtendedViewingKey.fromKeyString(json.extendedviewingkey), + address: pbaas_1.SaplingPaymentAddress.fromAddressString(json.address), + extendedSpendingKey: json.extendedspendingkey ? SaplingExtendedSpendingKey_1.SaplingExtendedSpendingKey.fromKeyString(json.extendedspendingkey) : undefined + }); + } +} +exports.AppEncryptionResponseDetails = AppEncryptionResponseDetails; +AppEncryptionResponseDetails.RESPONSE_CONTAINS_REQUEST_ID = new bn_js_1.BN(1, 10); +AppEncryptionResponseDetails.RESPONSE_CONTAINS_EXTENDED_SPENDING_KEY = new bn_js_1.BN(2, 10); diff --git a/dist/vdxf/classes/response/GenericResponse.d.ts b/dist/vdxf/classes/response/GenericResponse.d.ts new file mode 100644 index 00000000..e73f3e6a --- /dev/null +++ b/dist/vdxf/classes/response/GenericResponse.d.ts @@ -0,0 +1,34 @@ +import { SerializableEntity } from "../../../utils/types/SerializableEntity"; +import { GenericEnvelope, GenericEnvelopeInterface, GenericEnvelopeJson } from "../envelope/GenericEnvelope"; +import { BigNumber } from '../../../utils/types/BigNumber'; +export type GenericResponseJson = GenericEnvelopeJson & { + requesthash?: string; + requesthashtype?: number; +}; +export type GenericResponseInterface = GenericEnvelopeInterface & { + requestHash?: Buffer; + requestHashType?: BigNumber; +}; +export declare class GenericResponse extends GenericEnvelope implements SerializableEntity { + requestHash?: Buffer; + requestHashType?: BigNumber; + static VERSION_CURRENT: import("bn.js"); + static VERSION_FIRSTVALID: import("bn.js"); + static VERSION_LASTVALID: import("bn.js"); + static BASE_FLAGS: import("bn.js"); + static FLAG_SIGNED: import("bn.js"); + static FLAG_HAS_CREATED_AT: import("bn.js"); + static FLAG_MULTI_DETAILS: import("bn.js"); + static FLAG_IS_TESTNET: import("bn.js"); + static FLAG_HAS_SALT: import("bn.js"); + static FLAG_HAS_APP_OR_DELEGATED_ID: import("bn.js"); + static FLAG_HAS_REQUEST_HASH: import("bn.js"); + constructor(envelope?: GenericResponseInterface); + hasRequestHash(): boolean; + setHasRequestHash(): void; + setFlags(): void; + getByteLengthOptionalSig(includeSig?: boolean): number; + protected toBufferOptionalSig(includeSig?: boolean): Buffer; + fromBuffer(buffer: Buffer, offset?: number): number; + toJson(): GenericResponseJson; +} diff --git a/dist/vdxf/classes/response/GenericResponse.js b/dist/vdxf/classes/response/GenericResponse.js new file mode 100644 index 00000000..cbd283ea --- /dev/null +++ b/dist/vdxf/classes/response/GenericResponse.js @@ -0,0 +1,84 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.GenericResponse = void 0; +const bn_js_1 = require("bn.js"); +const GenericEnvelope_1 = require("../envelope/GenericEnvelope"); +const bufferutils_1 = require("../../../utils/bufferutils"); +const DataDescriptor_1 = require("../../../pbaas/DataDescriptor"); +const varuint_1 = require("../../../utils/varuint"); +class GenericResponse extends GenericEnvelope_1.GenericEnvelope { + constructor(envelope = { + details: [], + flags: GenericResponse.BASE_FLAGS + }) { + super(envelope); + this.requestHash = envelope.requestHash; + this.setFlags(); + this.requestHashType = envelope.requestHashType; + if (this.requestHashType == null && this.hasRequestHash()) { + this.requestHashType = new bn_js_1.BN(DataDescriptor_1.EHashTypes.HASH_SHA256); + } + } + hasRequestHash() { + return !!(this.flags.and(GenericResponse.FLAG_HAS_REQUEST_HASH).toNumber()); + } + setHasRequestHash() { + this.flags = this.flags.or(GenericResponse.FLAG_HAS_REQUEST_HASH); + } + setFlags() { + super.setFlags(); + if (this.requestHash) + this.setHasRequestHash(); + } + getByteLengthOptionalSig(includeSig = true) { + let length = super.getByteLengthOptionalSig(includeSig); + if (this.hasRequestHash()) { + const hashLen = this.requestHash.length; + length += varuint_1.default.encodingLength(this.requestHashType.toNumber()); + length += varuint_1.default.encodingLength(this.requestHash.length); + length += hashLen; + } + return length; + } + toBufferOptionalSig(includeSig = true) { + const writer = new bufferutils_1.default.BufferWriter(Buffer.alloc(this.getByteLengthOptionalSig(includeSig))); + const superBuf = super.toBufferOptionalSig(includeSig); + writer.writeSlice(superBuf); + if (this.hasRequestHash()) { + writer.writeCompactSize(this.requestHashType.toNumber()); + writer.writeVarSlice(this.requestHash); + } + return writer.buffer; + } + fromBuffer(buffer, offset) { + if (buffer.length == 0) + throw new Error("Cannot create response from empty buffer"); + const reader = new bufferutils_1.default.BufferReader(buffer, offset); + reader.offset = super.fromBuffer(reader.buffer, reader.offset); + if (this.hasRequestHash()) { + this.requestHashType = new bn_js_1.BN(reader.readCompactSize()); + this.requestHash = reader.readVarSlice(); + } + return reader.offset; + } + toJson() { + const parentJson = super.toJson(); + if (this.hasRequestHash()) { + parentJson["requesthash"] = this.requestHash.toString('hex'); + parentJson["requesthashtype"] = this.requestHashType.toNumber(); + } + return parentJson; + } +} +exports.GenericResponse = GenericResponse; +GenericResponse.VERSION_CURRENT = new bn_js_1.BN(1, 10); +GenericResponse.VERSION_FIRSTVALID = new bn_js_1.BN(1, 10); +GenericResponse.VERSION_LASTVALID = new bn_js_1.BN(1, 10); +GenericResponse.BASE_FLAGS = GenericEnvelope_1.GenericEnvelope.BASE_FLAGS; +GenericResponse.FLAG_SIGNED = GenericEnvelope_1.GenericEnvelope.FLAG_SIGNED; +GenericResponse.FLAG_HAS_CREATED_AT = GenericEnvelope_1.GenericEnvelope.FLAG_HAS_CREATED_AT; +GenericResponse.FLAG_MULTI_DETAILS = GenericEnvelope_1.GenericEnvelope.FLAG_MULTI_DETAILS; +GenericResponse.FLAG_IS_TESTNET = GenericEnvelope_1.GenericEnvelope.FLAG_IS_TESTNET; +GenericResponse.FLAG_HAS_SALT = GenericEnvelope_1.GenericEnvelope.FLAG_HAS_SALT; +GenericResponse.FLAG_HAS_APP_OR_DELEGATED_ID = GenericEnvelope_1.GenericEnvelope.FLAG_HAS_APP_OR_DELEGATED_ID; +GenericResponse.FLAG_HAS_REQUEST_HASH = new bn_js_1.BN(128, 10); diff --git a/dist/vdxf/index.d.ts b/dist/vdxf/index.d.ts index 741381b8..58b683bd 100644 --- a/dist/vdxf/index.d.ts +++ b/dist/vdxf/index.d.ts @@ -55,6 +55,10 @@ export declare class BufferDataVdxfObject extends VDXFObject { data: string; vdxfkey: string; }; + static fromJson(json: { + data: string; + vdxfkey: string; + }): BufferDataVdxfObject; } export declare class VDXFData extends VDXFObject { data: Buffer; diff --git a/dist/vdxf/index.js b/dist/vdxf/index.js index 49fd56f0..4a88a26a 100644 --- a/dist/vdxf/index.js +++ b/dist/vdxf/index.js @@ -123,6 +123,9 @@ class BufferDataVdxfObject extends VDXFObject { vdxfkey: this.vdxfkey, }; } + static fromJson(json) { + return new BufferDataVdxfObject(json.data, json.vdxfkey); + } } exports.BufferDataVdxfObject = BufferDataVdxfObject; class VDXFData extends VDXFObject { diff --git a/dist/vdxf/keys.d.ts b/dist/vdxf/keys.d.ts index 8f3caf79..0a85d482 100644 --- a/dist/vdxf/keys.d.ts +++ b/dist/vdxf/keys.d.ts @@ -11,6 +11,10 @@ export interface VDXFKeyInterface { indexid?: string; } export declare const VERUSPAY_INVOICE_VDXF_KEY: VDXFKeyInterface; +export declare const VERUSPAY_INVOICE_DETAILS_VDXF_KEY: VDXFKeyInterface; +export declare const GENERIC_ENVELOPE_DEEPLINK_VDXF_KEY: VDXFKeyInterface; +export declare const GENERIC_REQUEST_DEEPLINK_VDXF_KEY: VDXFKeyInterface; +export declare const GENERIC_RESPONSE_DEEPLINK_VDXF_KEY: VDXFKeyInterface; export declare const IDENTITY_UPDATE_REQUEST_VDXF_KEY: VDXFKeyInterface; export declare const IDENTITY_UPDATE_RESPONSE_VDXF_KEY: VDXFKeyInterface; export declare const IDENTITY_AUTH_SIG_VDXF_KEY: VDXFKeyInterface; @@ -78,3 +82,12 @@ export declare const PROOFS_CONTROLLER_GITHUB: VDXFKeyInterface; export declare const PROOFS_CONTROLLER_LINKEDIN: VDXFKeyInterface; export declare const PROOFS_CONTROLLER_REDDIT: VDXFKeyInterface; export declare const PROOFS_CONTROLLER_BLUESKY: VDXFKeyInterface; +export declare const ATTESTATION_VIEW_REQUEST_MULTIPLEATTESTATIONS: VDXFKeyInterface; +export declare const AUTHENTICATION_REQUEST_VDXF_KEY: VDXFKeyInterface; +export declare const AUTHENTICATION_RESPONSE_VDXF_KEY: VDXFKeyInterface; +export declare const PROVISION_IDENTITY_DETAILS_VDXF_KEY: VDXFKeyInterface; +export declare const APP_ENCRYPTION_REQUEST_VDXF_KEY: VDXFKeyInterface; +export declare const DATA_RESPONSE_VDXF_KEY: VDXFKeyInterface; +export declare const USER_DATA_REQUEST_VDXF_KEY: VDXFKeyInterface; +export declare const USER_SPECIFIC_DATA_PACKET_VDXF_KEY: VDXFKeyInterface; +export declare const APP_ENCRYPTION_RESPONSE_VDXF_KEY: VDXFKeyInterface; diff --git a/dist/vdxf/keys.js b/dist/vdxf/keys.js index a0df8164..0374f0c9 100644 --- a/dist/vdxf/keys.js +++ b/dist/vdxf/keys.js @@ -1,15 +1,52 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.ATTESTATION_VIEW_REQUEST_NAME = exports.ATTESTATION_VIEW_REQUEST_KEY = exports.ATTESTATION_TYPE = exports.ATTESTATION_NAME = exports.ATTESTATION_ID = exports.ATTESTATION_VIEW_RESPONSE = exports.ATTESTATION_VIEW_REQUEST = exports.ATTESTATION_PROVISION_OBJECT = exports.ATTESTATION_PROVISION_TYPE = exports.ATTESTATION_PROVISION_URL = exports.CURRENCY_ADDRESS = exports.SIGNED_SESSION_OBJECT = exports.SIGNED_SESSION_OBJECT_DATA = exports.LOGIN_CONSENT_PROVISIONING_ERROR_KEY_TRANSFER_FAILED = exports.LOGIN_CONSENT_PROVISIONING_ERROR_KEY_CREATION_FAILED = exports.LOGIN_CONSENT_PROVISIONING_ERROR_KEY_COMMIT_FAILED = exports.LOGIN_CONSENT_PROVISIONING_ERROR_KEY_UNKNOWN = exports.LOGIN_CONSENT_PROVISIONING_ERROR_KEY_NAMETAKEN = exports.LOGIN_CONSENT_PROVISIONING_RESULT_STATE_FAILED = exports.LOGIN_CONSENT_PROVISIONING_RESULT_STATE_COMPLETE = exports.LOGIN_CONSENT_PROVISIONING_RESULT_STATE_PENDINGAPPROVAL = exports.LOGIN_CONSENT_PROVISIONING_RESULT_STATE_PENDINGREQUIREDINFO = exports.IDENTITY_UPDATE_TXID = exports.IDENTITY_REGISTRATION_TXID = exports.IDENTITY_NAME_COMMITMENT_TXID = exports.LOGIN_CONSENT_PROVISIONING_RESULT_VDXF_KEY = exports.LOGIN_CONSENT_PROVISIONING_RESPONSE_VDXF_KEY = exports.LOGIN_CONSENT_PROVISIONING_DECISION_VDXF_KEY = exports.LOGIN_CONSENT_PROVISIONING_CHALLENGE_VDXF_KEY = exports.LOGIN_CONSENT_PROVISIONING_REQUEST_VDXF_KEY = exports.ID_PARENT_VDXF_KEY = exports.ID_FULLYQUALIFIEDNAME_VDXF_KEY = exports.ID_SYSTEMID_VDXF_KEY = exports.ID_ADDRESS_VDXF_KEY = exports.LOGIN_CONSENT_ID_PROVISIONING_WEBHOOK_VDXF_KEY = exports.LOGIN_CONSENT_CONTEXT_VDXF_KEY = exports.LOGIN_CONSENT_PERSONALINFO_WEBHOOK_VDXF_KEY = exports.LOGIN_CONSENT_ATTESTATION_WEBHOOK_VDXF_KEY = exports.LOGIN_CONSENT_WEBHOOK_VDXF_KEY = exports.LOGIN_CONSENT_REDIRECT_VDXF_KEY = exports.WALLET_VDXF_KEY = exports.LOGIN_CONSENT_DECISION_VDXF_KEY = exports.LOGIN_CONSENT_CHALLENGE_VDXF_KEY = exports.LOGIN_CONSENT_RESPONSE_VDXF_KEY = exports.LOGIN_CONSENT_REQUEST_VDXF_KEY = exports.LOGIN_CONSENT_RESPONSE_SIG_VDXF_KEY = exports.IDENTITY_AUTH_SIG_VDXF_KEY = exports.IDENTITY_UPDATE_RESPONSE_VDXF_KEY = exports.IDENTITY_UPDATE_REQUEST_VDXF_KEY = exports.VERUSPAY_INVOICE_VDXF_KEY = void 0; -exports.PROOFS_CONTROLLER_BLUESKY = exports.PROOFS_CONTROLLER_REDDIT = exports.PROOFS_CONTROLLER_LINKEDIN = exports.PROOFS_CONTROLLER_GITHUB = exports.PROOFS_CONTROLLER_FACEBOOK = exports.PROOFS_CONTROLLER_DISCORD = exports.PROOFS_CONTROLLER = exports.IDENTITY_CREDENTIAL_USERNAME = exports.IDENTITY_CREDENTIAL_PLAINLOGIN = exports.IDENTITY_CREDENTIAL = exports.DATA_TYPE_OBJECT_CREDENTIAL = exports.DATA_TYPE_OBJECT_DATADESCRIPTOR = exports.DATA_TYPE_DEFINEDKEY = exports.DATA_TYPE_STRING = exports.IDENTITY_SIGNDATA_REQUEST = exports.PROFILE_DATA_VIEW_REQUEST = exports.ATTESTATION_VIEW_REQUEST_ID = exports.ATTESTATION_VIEW_REQUEST_ATTESTOR = void 0; +exports.ATTESTATION_ID = exports.ATTESTATION_VIEW_RESPONSE = exports.ATTESTATION_VIEW_REQUEST = exports.ATTESTATION_PROVISION_OBJECT = exports.ATTESTATION_PROVISION_TYPE = exports.ATTESTATION_PROVISION_URL = exports.CURRENCY_ADDRESS = exports.SIGNED_SESSION_OBJECT = exports.SIGNED_SESSION_OBJECT_DATA = exports.LOGIN_CONSENT_PROVISIONING_ERROR_KEY_TRANSFER_FAILED = exports.LOGIN_CONSENT_PROVISIONING_ERROR_KEY_CREATION_FAILED = exports.LOGIN_CONSENT_PROVISIONING_ERROR_KEY_COMMIT_FAILED = exports.LOGIN_CONSENT_PROVISIONING_ERROR_KEY_UNKNOWN = exports.LOGIN_CONSENT_PROVISIONING_ERROR_KEY_NAMETAKEN = exports.LOGIN_CONSENT_PROVISIONING_RESULT_STATE_FAILED = exports.LOGIN_CONSENT_PROVISIONING_RESULT_STATE_COMPLETE = exports.LOGIN_CONSENT_PROVISIONING_RESULT_STATE_PENDINGAPPROVAL = exports.LOGIN_CONSENT_PROVISIONING_RESULT_STATE_PENDINGREQUIREDINFO = exports.IDENTITY_UPDATE_TXID = exports.IDENTITY_REGISTRATION_TXID = exports.IDENTITY_NAME_COMMITMENT_TXID = exports.LOGIN_CONSENT_PROVISIONING_RESULT_VDXF_KEY = exports.LOGIN_CONSENT_PROVISIONING_RESPONSE_VDXF_KEY = exports.LOGIN_CONSENT_PROVISIONING_DECISION_VDXF_KEY = exports.LOGIN_CONSENT_PROVISIONING_CHALLENGE_VDXF_KEY = exports.LOGIN_CONSENT_PROVISIONING_REQUEST_VDXF_KEY = exports.ID_PARENT_VDXF_KEY = exports.ID_FULLYQUALIFIEDNAME_VDXF_KEY = exports.ID_SYSTEMID_VDXF_KEY = exports.ID_ADDRESS_VDXF_KEY = exports.LOGIN_CONSENT_ID_PROVISIONING_WEBHOOK_VDXF_KEY = exports.LOGIN_CONSENT_CONTEXT_VDXF_KEY = exports.LOGIN_CONSENT_PERSONALINFO_WEBHOOK_VDXF_KEY = exports.LOGIN_CONSENT_ATTESTATION_WEBHOOK_VDXF_KEY = exports.LOGIN_CONSENT_WEBHOOK_VDXF_KEY = exports.LOGIN_CONSENT_REDIRECT_VDXF_KEY = exports.WALLET_VDXF_KEY = exports.LOGIN_CONSENT_DECISION_VDXF_KEY = exports.LOGIN_CONSENT_CHALLENGE_VDXF_KEY = exports.LOGIN_CONSENT_RESPONSE_VDXF_KEY = exports.LOGIN_CONSENT_REQUEST_VDXF_KEY = exports.LOGIN_CONSENT_RESPONSE_SIG_VDXF_KEY = exports.IDENTITY_AUTH_SIG_VDXF_KEY = exports.IDENTITY_UPDATE_RESPONSE_VDXF_KEY = exports.IDENTITY_UPDATE_REQUEST_VDXF_KEY = exports.GENERIC_RESPONSE_DEEPLINK_VDXF_KEY = exports.GENERIC_REQUEST_DEEPLINK_VDXF_KEY = exports.GENERIC_ENVELOPE_DEEPLINK_VDXF_KEY = exports.VERUSPAY_INVOICE_DETAILS_VDXF_KEY = exports.VERUSPAY_INVOICE_VDXF_KEY = void 0; +exports.APP_ENCRYPTION_RESPONSE_VDXF_KEY = exports.USER_SPECIFIC_DATA_PACKET_VDXF_KEY = exports.USER_DATA_REQUEST_VDXF_KEY = exports.DATA_RESPONSE_VDXF_KEY = exports.APP_ENCRYPTION_REQUEST_VDXF_KEY = exports.PROVISION_IDENTITY_DETAILS_VDXF_KEY = exports.AUTHENTICATION_RESPONSE_VDXF_KEY = exports.AUTHENTICATION_REQUEST_VDXF_KEY = exports.ATTESTATION_VIEW_REQUEST_MULTIPLEATTESTATIONS = exports.PROOFS_CONTROLLER_BLUESKY = exports.PROOFS_CONTROLLER_REDDIT = exports.PROOFS_CONTROLLER_LINKEDIN = exports.PROOFS_CONTROLLER_GITHUB = exports.PROOFS_CONTROLLER_FACEBOOK = exports.PROOFS_CONTROLLER_DISCORD = exports.PROOFS_CONTROLLER = exports.IDENTITY_CREDENTIAL_USERNAME = exports.IDENTITY_CREDENTIAL_PLAINLOGIN = exports.IDENTITY_CREDENTIAL = exports.DATA_TYPE_OBJECT_CREDENTIAL = exports.DATA_TYPE_OBJECT_DATADESCRIPTOR = exports.DATA_TYPE_DEFINEDKEY = exports.DATA_TYPE_STRING = exports.IDENTITY_SIGNDATA_REQUEST = exports.PROFILE_DATA_VIEW_REQUEST = exports.ATTESTATION_VIEW_REQUEST_ID = exports.ATTESTATION_VIEW_REQUEST_ATTESTOR = exports.ATTESTATION_VIEW_REQUEST_NAME = exports.ATTESTATION_VIEW_REQUEST_KEY = exports.ATTESTATION_TYPE = exports.ATTESTATION_NAME = void 0; exports.VERUSPAY_INVOICE_VDXF_KEY = { hash160result: "628efc28c2e2d40050e1a9de7a93e7ddf2aa0076", + indexid: "xK4aRumetZg2ecW4Z45qdDBH769xxnaiEH", qualifiedname: { name: "veruspay.vrsc::invoice", namespace: "iAisVse7piEiE2VsixZx4SARyHzSpxYxgq" }, vdxfid: "iEETy7La3FTN2Sd2hNRgepek5S8x8eeUeQ" }; +exports.VERUSPAY_INVOICE_DETAILS_VDXF_KEY = { + "hash160result": "743a23f19531686d70b26a2e220b50a9c70d78a3", + "indexid": "xPCyrdbnb89NftNSuPaVFENwzGDmAukVbS", + "qualifiedname": { + "name": "veruspay.vrsc::invoice.details", + "namespace": "iAisVse7piEiE2VsixZx4SARyHzSpxYxgq" + }, + "vdxfid": "iJNsPqAhjovi3iVR3hvLGqrQxcCkHq9n9H" +}; +exports.GENERIC_ENVELOPE_DEEPLINK_VDXF_KEY = { + "hash160result": "bc05c4263031cc791296fa8bd15553ccef3de4ba", + "indexid": "xRLq15vpenCUGVpmZgqEtoygZW2b32oVgX", + "qualifiedname": { + "name": "vrsc::envelope.generic", + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV" + }, + "vdxfid": "iLWiYHVjoTyoeKwji1B5vRT9Xr1aA9yyvX" +}; +exports.GENERIC_REQUEST_DEEPLINK_VDXF_KEY = { + "hash160result": "bc05c4263031cc791296fa8bd15553ccef3de4ba", + "indexid": "xRLq15vpenCUGVpmZgqEtoygZW2b32oVgX", + "qualifiedname": { + "name": "vrsc::request.generic", + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV" + }, + "vdxfid": "iLWiYHVjoTyoeKwji1B5vRT9Xr1aA9yyvX" +}; +exports.GENERIC_RESPONSE_DEEPLINK_VDXF_KEY = { + "hash160result": "4eb641e76ca30947a0782a7c9b5d79e934300340", + "indexid": "xE96xgWEcUhxTuVAMr4TvW7mGpR5c2SFy4", + "qualifiedname": { + "name": "vrsc::response.generic", + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV" + }, + "vdxfid": "i9JzVt59mAVHqjc8WAQJx7bEFAQ4ffuhrC" +}; exports.IDENTITY_UPDATE_REQUEST_VDXF_KEY = { "hash160result": "0bcef8b06c211828d16dc038e4d34d097aeb64e4", "indexid": "xV8GreW8nt1Py99r8KPsLxDyy6UYJQvXja", @@ -83,6 +120,7 @@ exports.WALLET_VDXF_KEY = { namespace: "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV", name: "vrsc::applications.wallet", }, + indexid: "xA91QPpBrHZto92NCU5KEjCqRveS4dAPrf" }; exports.LOGIN_CONSENT_REDIRECT_VDXF_KEY = { vdxfid: "iDXvHYhRpWcoARCEYeLv8GwkVdrbvSFuam", @@ -562,3 +600,84 @@ exports.PROOFS_CONTROLLER_BLUESKY = { name: "vrsc::system.proofs.controller.bluesky" } }; +exports.ATTESTATION_VIEW_REQUEST_MULTIPLEATTESTATIONS = { + "vdxfid": "i4BWC5Lr7gAT7KzyDx82Ye5DeFQD8ckcXe", + "indexid": "x91cesmvxzP7jVt15dnBX2bkfuRDya9TPq", + "hash160result": "3c520f0bde6be181461ebbff11bce396a604c007", + "qualifiedname": { + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV", + "name": "vrsc::attestation.view.request.multipleattestations" + } +}; +exports.AUTHENTICATION_REQUEST_VDXF_KEY = { + "hash160result": "d989dfa450a2bcd597fff2409a62c00640644cba", + "indexid": "xRHh6LdgnyNjv5vhoUYbdPaDE5b1Asnykb", + "qualifiedname": { + "name": "vrsc::identity.authentication.request", + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV" + }, + "vdxfid": "iLTadYCbwfA5Hv3fwntSf13gCRZzF8Qedv" +}; +exports.AUTHENTICATION_RESPONSE_VDXF_KEY = { + "hash160result": "70db17c46d4aebbf0023ac0e23dd3d85c196eee8", + "indexid": "xVYGUq1veNvX7bQMPkysn77RwfXbLcjhnJ", + "qualifiedname": { + "name": "vrsc::identity.authentication.response", + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV" + }, + "vdxfid": "iQiA22aqo4hrVRXKY5Kioiatv1WaSL2EEw" +}; +exports.PROVISION_IDENTITY_DETAILS_VDXF_KEY = { + "hash160result": "1ed843dce0f4d9a2bbb839994e3927807eb1878c", + "indexid": "xM7h3sXBovFXuwGQ3wvK2ibtUmMHn3mYkM", + "qualifiedname": { + "name": "vrsc::identity.provision.details", + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV" + }, + "vdxfid": "iGHab566xc2sHmPNCGGA4L5MT7LGoJzmCa" +}; +exports.APP_ENCRYPTION_REQUEST_VDXF_KEY = { + "vdxfid": "iL5nfPuV8Ekiz1EeW5KE3pXHuUTfQf6QC9", + "indexid": "xQuu8CLZyYyPcB7gMkyP2D3pw8UgHevmcM", + "hash160result": "5f398b165b8ea8c547b5f473f951178fc5482db6", + "qualifiedname": { + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV", + "name": "application.encryption.request" + } +}; +exports.DATA_RESPONSE_VDXF_KEY = { + "vdxfid": "i5L8SNcCqY68X3KZEPgJEjGxY2zvMPzutN", + "indexid": "xAAEuB3HgrJo9DCb65LTD7oVZh1wAjCfTC", + "hash160result": "47ecd4c56c93486380a1ec0d06e186ae8cba5914", + "qualifiedname": { + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV", + "name": "vrsc::generic.data.packet.response" + } +}; +exports.USER_DATA_REQUEST_VDXF_KEY = { + "vdxfid": "iC7kqU8mfKtqe2gcE2qpuyN4CEcPFTxKGL", + "indexid": "xGwsJGZrWe7WGCZe5iVytMtbDtdQCPvmno", + "hash160result": "d1fba3d9bf18a5293ff912374fc64725db95cb5e", + "qualifiedname": { + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV", + "name": "user.data.request" + } +}; +exports.USER_SPECIFIC_DATA_PACKET_VDXF_KEY = { + "vdxfid": "i6JYTdVNLz4Sb6515B73BSX6C1Xba63tNQ", + "indexid": "xB8evRvTCJH7DFx2vrmC9q3dDfYcXW1F15", + "hash160result": "34dfdf234ec37a8451790a19538dbd162913051f", + "qualifiedname": { + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV", + "name": "user.data.packet.details" + } +}; +exports.APP_ENCRYPTION_RESPONSE_VDXF_KEY = { + "vdxfid": "iLgnRLninDtMa7f7EbH7zsDqHRknC4CUpB", + "indexid": "xRWtt9DodY72CHY96GwGyFkNK5mo1n7Jxe", + "hash160result": "0d3c42aec1d154f1678e0585e557e75202a4cbbc", + "qualifiedname": { + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV", + "name": "application.encryption.response" + } +}; diff --git a/src/__tests__/constants/fixtures.ts b/src/__tests__/constants/fixtures.ts index 4c92809a..eef2fc9d 100644 --- a/src/__tests__/constants/fixtures.ts +++ b/src/__tests__/constants/fixtures.ts @@ -1,3 +1,10 @@ +import { BN } from "bn.js" +import { ContentMultiMap, IDENTITY_VERSION_PBAAS, IdentityID, KeyID, SaplingPaymentAddress } from "../../pbaas" +import { PartialIdentity } from "../../pbaas/PartialIdentity" +import { PartialMMRData } from "../../pbaas/PartialMMRData" +import { PartialSignData, PartialSignDataInitData } from "../../pbaas/PartialSignData" +import { DATA_TYPE_MMRDATA } from "../../constants/pbaas" + export const manyContentMultimapData = { "iGdWifeNFcN69JiFwmcZTYT1zPYpFumGhq": [ // String @@ -320,4 +327,131 @@ export const mmrDescriptorForRootProof = { } ] } -} \ No newline at end of file +} + +export const TEST_IDENTITY_ID = "i8jHXEEYEQ7KEoYe6eKXBib8cUBZ6vjWSd" + +export const TEST_SYSTEMID = IdentityID.fromAddress("iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq"); +export const TEST_SIGNINGID = IdentityID.fromAddress("iPsFBfFoCcxtuZNzE8yxPQhXVn4dmytf8j"); +export const TEST_REQUESTID = "iPsFBfFoCcxtuZNzE8yxPQhXVn4dmytf8j"; +export const TEST_CREATEDAT = new BN("1700000000", 10); +export const TEST_EXPIRYHEIGHT = new BN("123456"); +export const TEST_SALT = Buffer.from('=H319X:)@H2Z'); +export const TEST_TXID = "2474d2c7b3586cedd8bf7f4a9af7c26e794ea2fc44853f17a30148e2ed857a95"; + +export const TEST_CONTENTMAP = new Map(); +TEST_CONTENTMAP.set("iPsFBfFoCcxtuZNzE8yxPQhXVn4dmytf8j", Buffer.alloc(32)); +TEST_CONTENTMAP.set("iK7a5JNJnbeuYWVHCDRpJosj3irGJ5Qa8c", Buffer.alloc(32)); + +export const TEST_CLI_ID_UPDATE_REQUEST_JSON = { + "name": "data", + "contentmultimap": { + "i5CXAPoCLothTntExgvc5kK38u2wyHtFCg": { + "data": {"createmmr":true, "mmrdata":[{"message": "{\"rail_transport\": 43326.71, \"public_bus_transport\": 83452.4, \"air_transport\": 1306.83, \"urban_public_transport\": -1, \"time\": 993945600}", "mimetype": "application/json", "label": "quarter_3_2001_transport_passenger_data_cz"}]} + } + } +} + +export const TEST_CLI_ID_UPDATE_REQUEST_JSON_HEX = { + "name":"[32][32]", + "parent":"iF6hHpRXpmhLq77eksQzqQrWuminKtzmxT", + "contentmultimap": { + "i4d7U1aZhmoxZbWx8AVezh6z1YewAnuw3V": [ + { + "i4GC1YGEVD21afWudGoFJVdnfjJ5XWnCQv": { + "version": 1, + "flags": 32, + "label": "i3bgiLuaxTr6smF8q6xLG4jvvhF1mmrkM2", + "objectdata": { + "serializedhex": "08a2ebb2c55f83a8e2a426a53320ed4d42124f4d010c012001010776657273696f6e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d011d01600a656d706c6f796d656e7404747970650a746578742f706c61696e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d011d016009446576656c6f706572057469746c650a746578742f706c61696e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d0157016044426f6479206f6620636c61696d20676f657320686572652c207768617420796f75206861766520646f6e652c207768617420796f7520686176652061636869657665642e04626f64790a746578742f706c61696e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d011d016009323031392d323032300564617465730a746578742f706c61696e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d011f01600a323032352d30312d3330066973737565640a746578742f706c61696e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d012f012020cc2b8109fb5566cf98297aaf5c80e2fb0a5051c3252a7957b13ba5433767e23a0b7265666572656e63654944" + } + } + }, + { + "i4GC1YGEVD21afWudGoFJVdnfjJ5XWnCQv": { + "version": 1, + "flags": 32, + "label": "i3bgiLuaxTr6smF8q6xLG4jvvhF1mmrkM2", + "objectdata": { + "serializedhex": "08a2ebb2c55f83a8e2a426a53320ed4d42124f4d010c012001010776657273696f6e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d011d01600a656d706c6f796d656e7404747970650a746578742f706c61696e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d012301600f436869656620446576656c6f706572057469746c650a746578742f706c61696e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d0157016044426f6479206f6620636c61696d20676f657320686572652c207768617420796f75206861766520646f6e652c207768617420796f7520686176652061636869657665642e04626f64790a746578742f706c61696e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d011d016009323032312d323032340564617465730a746578742f706c61696e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d011f01600a323032352d30312d3239066973737565640a746578742f706c61696e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d015a016040373962343830376333303465383035333831666438653165376234383865353062363032613033333366663266663633636264313564363362366163383835650b7265666572656e636549440a746578742f706c61696e" + } + } + } + ] + } +} + +export const TEST_PARTIAL_IDENTITY = new PartialIdentity({ + flags: new BN("0"), + version: IDENTITY_VERSION_PBAAS, + min_sigs: new BN(1), + primary_addresses: [ + KeyID.fromAddress("RQVsJRf98iq8YmRQdehzRcbLGHEx6YfjdH"), + KeyID.fromAddress("RP4Qct9197i5vrS11qHVtdyRRoAHVNJS47") + ], + parent: IdentityID.fromAddress("iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq"), + system_id: IdentityID.fromAddress("iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq"), + name: "TestID", + content_map: TEST_CONTENTMAP, + content_multimap: ContentMultiMap.fromJson({ + iPsFBfFoCcxtuZNzE8yxPQhXVn4dmytf8j: [ + { iK7a5JNJnbeuYWVHCDRpJosj3irGJ5Qa8c: 'Test String 123454321' }, + { iK7a5JNJnbeuYWVHCDRpJosj3irGJ5Qa8c: 'Test String 123454321' }, + { iK7a5JNJnbeuYWVHCDRpJosj3irGJ5Qa8c: 'Test String 123454321' }, + { iK7a5JNJnbeuYWVHCDRpJosj3irGJ5Qa8c: 'Test String 123454321' } + ], + iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq: '6868686868686868686868686868686868686868', + i5v3h9FWVdRFbNHU7DfcpGykQjRaHtMqu7: [ + '6868686868686868686868686868686868686868', + '6868686868686868686868686868686868686868', + '6868686868686868686868686868686868686868' + ], + i81XL8ZpuCo9jmWLv5L5ikdxrGuHrrpQLz: { iK7a5JNJnbeuYWVHCDRpJosj3irGJ5Qa8c: 'Test String 123454321' } + }), + recovery_authority: IdentityID.fromAddress("i81XL8ZpuCo9jmWLv5L5ikdxrGuHrrpQLz"), + revocation_authority: IdentityID.fromAddress("i5v3h9FWVdRFbNHU7DfcpGykQjRaHtMqu7"), + unlock_after: new BN("123456", 10), + private_addresses: [SaplingPaymentAddress.fromAddressString("zs1wczplx4kegw32h8g0f7xwl57p5tvnprwdmnzmdnsw50chcl26f7tws92wk2ap03ykaq6jyyztfa")] +}); + +export const TEST_MMR_DATA = new PartialMMRData({ + flags: new BN('0', 10), + data: [ + { type: new BN('2', 10), data: Buffer.from('src/__tests__/pbaas/partialmmrdata.test.ts', 'utf-8') }, + { type: new BN('3', 10), data: Buffer.from('Hello test message 12345', 'utf-8') }, + ], + salt: [Buffer.from('=H319X:)@H2Z'), Buffer.from('s*1UHmVr?feI')], + mmrhashtype: new BN('1', 10), // e.g. PartialMMRData.HASH_TYPE_SHA256 + priormmr: [ + Buffer.from('80a28cdff6bd91a2e96a473c234371fd8b67705a8c4956255ce7b8c7bf20470f02381c9a935f06cdf986a7c5facd77625befa11cf9fd4b59857b457394a8af979ab2830087a3b27041b37bc318484175'), + Buffer.from('d97fd4bbd9e88ca0c5822c12d5c9b272b2044722aa48b1c8fde178be6b59ccea509f403d3acd226c16ba3c32f0cb92e2fcaaa02b40d0bc5257e0fbf2e6c3d3d7f1a1df066967b193d131158ba5bef732') + ], +}) + +export const TEST_BASE_SIGN_DATA_WITH_MMR_DATA: PartialSignDataInitData = { + flags: new BN('0', 10), + address: IdentityID.fromAddress('iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq'), + prefixString: Buffer.from('example prefix', 'utf8'), + vdxfKeys: [IdentityID.fromAddress('i81XL8ZpuCo9jmWLv5L5ikdxrGuHrrpQLz')], + vdxfKeyNames: [Buffer.from('VDXFNAME', 'utf8')], + boundHashes: [Buffer.from('0873c6ba879ce87f5c207a4382b273cac164361af0b9fe63d6d7b0d7af401fec', 'hex'), Buffer.from('0873c6ba879ce87f5c207a4382b273cac164361af0b9fe63d6d7b0d7af401fec', 'hex')], + hashType: new BN('1', 10), + encryptToAddress: SaplingPaymentAddress.fromAddressString( + 'zs1wczplx4kegw32h8g0f7xwl57p5tvnprwdmnzmdnsw50chcl26f7tws92wk2ap03ykaq6jyyztfa' + ), + createMMR: true, + signature: Buffer.from('AeNjMwABQSAPBEuajDkRyy+OBJsWmDP3EUoqN9UjCJK9nmoSQiNoZWBK19OgGCYdEqr1CiFfBf8SFHVoUv4r2tb5Q3qsMTrp', 'base64'), + dataType: DATA_TYPE_MMRDATA, + data: TEST_MMR_DATA, // This is the PartialMMRData object +} + +export const TEST_SIGNDATA_MAP = new Map(); +TEST_SIGNDATA_MAP.set("iBvyi1nuCrTA4g44xN9N7EU1t6a7gwb4h8", new PartialSignData(TEST_BASE_SIGN_DATA_WITH_MMR_DATA)) + +// Test constants with valid addresses from the codebase +export const TEST_CHALLENGE_ID = "iMdf3BJ1mEtKMAJqNg8hj5fMnCUCc3bpFN"; +export const TEST_IDENTITY_ID_1 = "i7LaXD2cdy1zeh33eHzZaEPyueT4yQmBfW"; +export const TEST_IDENTITY_ID_2 = "i84T3MWcb6zWcwgNZoU3TXtrUn9EqM84A4"; +export const TEST_IDENTITY_ID_3 = "iJ5LnijKvp1wkL4hB3EsJ5kjcE4T8VL4hD"; + +export const SERIALIZED_AUTHENTICATION_REQUEST_DETAILS = Buffer.from("070102c72c5b342995a2186f96271e91686c5e942d13e1030101022a5fc0e9dedf4f1e8351fe652a140e9dd38fa5a9020102324afad29f51859c54050db854d2c9bb52acd9bd030102a0276f355ad37d8e5d2d10f16c1d051b6f6ead62ff9982d02aac020000", 'hex'); diff --git a/src/__tests__/pbaas/partialsigndata.test.ts b/src/__tests__/pbaas/partialsigndata.test.ts index b15d7ef7..c47d21ab 100644 --- a/src/__tests__/pbaas/partialsigndata.test.ts +++ b/src/__tests__/pbaas/partialsigndata.test.ts @@ -38,24 +38,24 @@ describe('PartialSignData serialization/deserialization', () => { const baseDataWithMMR: PartialSignDataInitData = { flags: new BN('0', 10), address: IdentityID.fromAddress('iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq'), - prefixstring: Buffer.from('example prefix', 'utf8'), - vdxfkeys: [IdentityID.fromAddress('i81XL8ZpuCo9jmWLv5L5ikdxrGuHrrpQLz')], - vdxfkeynames: [Buffer.from('VDXFNAME', 'utf8')], - boundhashes: [Buffer.from('0873c6ba879ce87f5c207a4382b273cac164361af0b9fe63d6d7b0d7af401fec', 'hex'), Buffer.from('0873c6ba879ce87f5c207a4382b273cac164361af0b9fe63d6d7b0d7af401fec', 'hex')], - hashtype: new BN('1', 10), - encrypttoaddress: SaplingPaymentAddress.fromAddressString( + prefixString: Buffer.from('example prefix', 'utf8'), + vdxfKeys: [IdentityID.fromAddress('i81XL8ZpuCo9jmWLv5L5ikdxrGuHrrpQLz')], + vdxfKeyNames: [Buffer.from('VDXFNAME', 'utf8')], + boundHashes: [Buffer.from('0873c6ba879ce87f5c207a4382b273cac164361af0b9fe63d6d7b0d7af401fec', 'hex'), Buffer.from('0873c6ba879ce87f5c207a4382b273cac164361af0b9fe63d6d7b0d7af401fec', 'hex')], + hashType: new BN('1', 10), + encryptToAddress: SaplingPaymentAddress.fromAddressString( 'zs1wczplx4kegw32h8g0f7xwl57p5tvnprwdmnzmdnsw50chcl26f7tws92wk2ap03ykaq6jyyztfa' ), - createmmr: true, + createMMR: true, signature: Buffer.from('AeNjMwABQSAPBEuajDkRyy+OBJsWmDP3EUoqN9UjCJK9nmoSQiNoZWBK19OgGCYdEqr1CiFfBf8SFHVoUv4r2tb5Q3qsMTrp', 'base64'), - datatype: DATA_TYPE_MMRDATA, + dataType: DATA_TYPE_MMRDATA, data: mmrData, // This is the PartialMMRData object } // Define a base set of parameters for PartialSignData — with simple buffer data const baseDataWithBuffer = { ...baseDataWithMMR, - datatype: DATA_TYPE_MESSAGE, + dataType: DATA_TYPE_MESSAGE, data: Buffer.from('regular buffer data', 'utf8'), } @@ -63,11 +63,11 @@ describe('PartialSignData serialization/deserialization', () => { const baseConfigs = [baseDataWithMMR, baseDataWithBuffer]; const removableKeys = [ 'address', - 'prefixstring', - 'vdxfkeys', - 'vdxfkeynames', - 'boundhashes', - 'encrypttoaddress', + 'prefixString', + 'vdxfKeys', + 'vdxfKeyNames', + 'boundHashes', + 'encryptToAddress', 'signature', 'data' ] as const; @@ -85,7 +85,7 @@ describe('PartialSignData serialization/deserialization', () => { // If removing data, also remove datatype if (key === 'data') { - delete newConfig.datatype; + delete newConfig.dataType; } finalTestData.push(newConfig); diff --git a/src/__tests__/pbaas/saplingextendedspendingkey.test.ts b/src/__tests__/pbaas/saplingextendedspendingkey.test.ts new file mode 100644 index 00000000..59336ddf --- /dev/null +++ b/src/__tests__/pbaas/saplingextendedspendingkey.test.ts @@ -0,0 +1,43 @@ +import { SaplingExtendedSpendingKey } from '../../pbaas/SaplingExtendedSpendingKey'; + +describe('SaplingExtendedSpendingKey', () => { + const mainnetKey = 'secret-extended-key-main1q0njl87fqqqqpq8vghkp6nz9wx48mwelukvhx3yfwg7msatglv4xy8rrh87k9z472el95h53ym2tku2dazny0j2vfukgmp6fu3k7edzcx9n8egesc32sdy3xr4s2ep4skgc7t5j5zds4ws7hf2nuszf7ltfn2nc5rk3k77gyeqdz905x6xt6kqdx5wn7jvas0733hends8q6s8k87emn6m060xdnhgmvn4zmx0ssrwve84lzxkqu2dnfq5qsjwrtlject0an0k282rs0gws78'; + + it('should decode and encode a mainnet extended spending key', () => { + const key = SaplingExtendedSpendingKey.fromKeyString(mainnetKey); + + expect(key.depth).toBeGreaterThanOrEqual(0); + expect(key.parentFVKTag.length).toBe(4); + expect(key.childIndex.length).toBe(4); + expect(key.chainCode.length).toBe(32); + expect(key.ask.length).toBe(32); + expect(key.nsk.length).toBe(32); + expect(key.ovk.length).toBe(32); + expect(key.dk.length).toBe(32); + + const encoded = key.toKeyString(false); + expect(encoded).toBe(mainnetKey); + }); + + it('should round-trip through buffer serialization', () => { + const key = SaplingExtendedSpendingKey.fromKeyString(mainnetKey); + + const buffer = key.toBuffer(); + expect(buffer.length).toBe(169); + + const key2 = new SaplingExtendedSpendingKey(); + key2.fromBuffer(buffer); + + expect(key2.depth).toBe(key.depth); + expect(key2.parentFVKTag.equals(key.parentFVKTag)).toBe(true); + expect(key2.childIndex.equals(key.childIndex)).toBe(true); + expect(key2.chainCode.equals(key.chainCode)).toBe(true); + expect(key2.ask.equals(key.ask)).toBe(true); + expect(key2.nsk.equals(key.nsk)).toBe(true); + expect(key2.ovk.equals(key.ovk)).toBe(true); + expect(key2.dk.equals(key.dk)).toBe(true); + + const encoded = key2.toKeyString(false); + expect(encoded).toBe(mainnetKey); + }); +}); diff --git a/src/__tests__/pbaas/saplingextendedviewingkey.test.ts b/src/__tests__/pbaas/saplingextendedviewingkey.test.ts new file mode 100644 index 00000000..668a6d07 --- /dev/null +++ b/src/__tests__/pbaas/saplingextendedviewingkey.test.ts @@ -0,0 +1,43 @@ +import { SaplingExtendedViewingKey } from '../../pbaas/SaplingExtendedViewingKey'; + +describe('SaplingExtendedViewingKey', () => { + const mainnetKey = 'zxviews1q0njl87fqqqqpq8vghkp6nz9wx48mwelukvhx3yfwg7msatglv4xy8rrh87k9z472edvlrt950qyy6r766dxnpqktxug7t2wy80s4ug325dwp9hf4vw9a6ethf2mwc9wan28p88dq8q2e8sdlw2mhffg6hy92tjyuquz7a8reqdz905x6xt6kqdx5wn7jvas0733hends8q6s8k87emn6m060xdnhgmvn4zmx0ssrwve84lzxkqu2dnfq5qsjwrtlject0an0k282rsnx0kq4'; + + it('should decode and encode a mainnet extended viewing key', () => { + const key = SaplingExtendedViewingKey.fromKeyString(mainnetKey); + + expect(key.depth).toBeGreaterThanOrEqual(0); + expect(key.parentFVKTag.length).toBe(4); + expect(key.childIndex.length).toBe(4); + expect(key.chainCode.length).toBe(32); + expect(key.ak.length).toBe(32); + expect(key.nk.length).toBe(32); + expect(key.ovk.length).toBe(32); + expect(key.dk.length).toBe(32); + + const encoded = key.toKeyString(false); + expect(encoded).toBe(mainnetKey); + }); + + it('should round-trip through buffer serialization', () => { + const key = SaplingExtendedViewingKey.fromKeyString(mainnetKey); + + const buffer = key.toBuffer(); + expect(buffer.length).toBe(169); + + const key2 = new SaplingExtendedViewingKey(); + key2.fromBuffer(buffer); + + expect(key2.depth).toBe(key.depth); + expect(key2.parentFVKTag.equals(key.parentFVKTag)).toBe(true); + expect(key2.childIndex.equals(key.childIndex)).toBe(true); + expect(key2.chainCode.equals(key.chainCode)).toBe(true); + expect(key2.ak.equals(key.ak)).toBe(true); + expect(key2.nk.equals(key.nk)).toBe(true); + expect(key2.ovk.equals(key.ovk)).toBe(true); + expect(key2.dk.equals(key.dk)).toBe(true); + + const encoded = key2.toKeyString(false); + expect(encoded).toBe(mainnetKey); + }); +}); diff --git a/src/__tests__/utils/address.test.ts b/src/__tests__/utils/address.test.ts index 99f99f63..2c2beb98 100644 --- a/src/__tests__/utils/address.test.ts +++ b/src/__tests__/utils/address.test.ts @@ -1,3 +1,4 @@ +import { I_ADDR_VERSION, X_ADDR_VERSION } from "../../constants/vdxf"; import { getDataKey, nameAndParentAddrToIAddr, toIAddress } from "../../utils/address"; import { DATA_TYPE_DEFINEDKEY, IDENTITY_UPDATE_REQUEST_VDXF_KEY, VERUSPAY_INVOICE_VDXF_KEY, WALLET_VDXF_KEY } from "../../vdxf"; @@ -34,10 +35,13 @@ describe('Address tests', () => { ] for (const key of keys) { - const dataKey = getDataKey(key.qualifiedname.name); + const dataKeyI = getDataKey(key.qualifiedname.name, undefined, undefined, I_ADDR_VERSION); + const dataKeyX = getDataKey(key.qualifiedname.name, undefined, undefined, X_ADDR_VERSION); - expect(dataKey.id).toBe(key.vdxfid); - expect(dataKey.namespace).toBe(key.qualifiedname.namespace); + expect(dataKeyI.id).toBe(key.vdxfid); + expect(dataKeyI.namespace).toBe(key.qualifiedname.namespace); + expect(dataKeyX.id).toBe(key.indexid!); + expect(dataKeyX.namespace).toBe(key.qualifiedname.namespace); } }); }); diff --git a/src/__tests__/utils/attestationDetails.test.ts b/src/__tests__/utils/attestationDetails.test.ts deleted file mode 100644 index 05d294e1..00000000 --- a/src/__tests__/utils/attestationDetails.test.ts +++ /dev/null @@ -1,206 +0,0 @@ -import { AttestationDetails } from "../../vdxf/classes/attestation/AttestationDetails"; - -describe('AttestationDetails tests', () => { - test('toBuffer and fromBuffer test with real data', () => { - const testData = { - "mmrdescriptor": { - "version": 1, - "objecthashtype": 5, - "mmrhashtype": 1, - "mmrroot": { - "version": 1, - "flags": 0, - "objectdata": "da513b88a56ef93a55cfd7e8f49e1143fd26a2e6095a67fc0d368327d8e3d3df" - }, - "mmrhashes": { - "version": 1, - "flags": 0, - "objectdata": "41d826d3c6cbbc3a96992670d2f604e959fd1a8c014102c78ee8fa7c01db81cbf60181fc9baa101aa8c07d40c324d771145699168d3b18867a587f139173cf8b961d581fe15bbf15f5d02813a615e54c050d2b6b1cd4ee" - }, - "datadescriptors": [ - { - "version": 1, - "flags": 2, - "objectdata": { - "i4GC1YGEVD21afWudGoFJVdnfjJ5XWnCQv": { - "version": 1, - "flags": 96, - "mimetype": "text/plain", - "objectdata": { - "message": "John" - }, - "label": "i4GqsotHGa4czCdtg2d8FVHKfJFzVyBPrM" - } - }, - "salt": "06e9b0454f1fddf23353a8c411bdbbb266738dca1d647e03040bffe1bddacf74" - }, - { - "version": 1, - "flags": 2, - "objectdata": { - "i4GC1YGEVD21afWudGoFJVdnfjJ5XWnCQv": { - "version": 1, - "flags": 96, - "mimetype": "text/plain", - "objectdata": { - "message": "Doe" - }, - "label": "iHybTrNB1kXRrjsCtJXd6fvBKxepqMpS5Z" - } - }, - "salt": "d32fac398866a7331acd678fd48412f173f71e381f1c1d6efff253a6b29b4d5b" - } - ] - }, - "signaturedata": { - "version": 1, - "systemid": "iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq", - "hashtype": 1, - "signaturehash": "dfd3e3d82783360dfc675a09e6a226fd43119ef4e8d7cf553af96ea5883b51da", - "identityid": "iKjrTCwoPFRk44fAi2nYNbPG16ZUQjv1NB", - "signaturetype": 1, - "signature": "AgXOCgAAAUEfCiSukK9tg46cYOpHmxzKjNquWDyNc8H58+uLSOYmqlUcNUxWB8j3nzT1RHKeJGygdAwrUj5iZ/A9H3+qYV9H9g==" - } - }; - - // Create AttestationDetails from the node response - const attestationDetails = AttestationDetails.fromNodeResponse(testData); - - // Convert to buffer - const buffer = attestationDetails.toBuffer(); - - // Convert buffer to hex string for comparison - const bufferHex = buffer.toString('hex'); - - // Test that we can deserialize back to the same object - const deserializedAttestation = new AttestationDetails(); - deserializedAttestation.fromBuffer(buffer); - - // Verify the deserialized object matches the original - expect(deserializedAttestation.version.toNumber()).toBe(attestationDetails.version.toNumber()); - expect(deserializedAttestation.flags.toNumber()).toBe(attestationDetails.flags.toNumber()); - expect(deserializedAttestation.attestations.length).toBe(1); - - // Verify MMR descriptor data - const originalMmr = attestationDetails.attestations[0].mmrDescriptor; - const deserializedMmr = deserializedAttestation.attestations[0].mmrDescriptor; - - expect(deserializedMmr.version.toNumber()).toBe(originalMmr.version.toNumber()); - expect(deserializedMmr.objectHashType).toBe(originalMmr.objectHashType); - expect(deserializedMmr.mmrHashType).toBe(originalMmr.mmrHashType); - - // Verify signature data - const originalSig = attestationDetails.attestations[0].signatureData; - const deserializedSig = deserializedAttestation.attestations[0].signatureData; - - expect(deserializedSig.version.toNumber()).toBe(originalSig.version.toNumber()); - expect(deserializedSig.system_ID).toBe(originalSig.system_ID); - expect(deserializedSig.hash_type.toNumber()).toBe(originalSig.hash_type.toNumber()); - expect(deserializedSig.identity_ID).toBe(originalSig.identity_ID); - expect(deserializedSig.sig_type.toNumber()).toBe(originalSig.sig_type.toNumber()); - - // Test JSON round-trip - const json = attestationDetails.toJson(); - const fromJson = AttestationDetails.fromJson(json); - const fromJsonBuffer = fromJson.toBuffer(); - - expect(fromJsonBuffer.toString('hex')).toBe(bufferHex); - }); - - test('fromBuffer with known hex data', () => { - // This is the actual hex string generated from the test data above - const expectedHex = "010001010501010020da513b88a56ef93a55cfd7e8f49e1143fd26a2e6095a67fc0d368327d8e3d3df01005741d826d3c6cbbc3a96992670d2f604e959fd1a8c014102c78ee8fa7c01db81cbf60181fc9baa101aa8c07d40c324d771145699168d3b18867a587f139173cf8b961d581fe15bbf15f5d02813a615e54c050d2b6b1cd4ee0201024b08a2ebb2c55f83a8e2a426a53320ed4d42124f4d01350160044a6f686e2269344771736f7448476134637a436474673264384656484b664a467a56794250724d0a746578742f706c61696e2006e9b0454f1fddf23353a8c411bdbbb266738dca1d647e03040bffe1bddacf7401024a08a2ebb2c55f83a8e2a426a53320ed4d42124f4d0134016003446f65226948796254724e42316b5852726a7343744a5864366676424b786570714d7053355a0a746578742f706c61696e20d32fac398866a7331acd678fd48412f173f71e381f1c1d6efff253a6b29b4d5b01a6ef9ea235635e328124ff3429db9f9e91b64e2d0120da513b88a56ef93a55cfd7e8f49e1143fd26a2e6095a67fc0d368327d8e3d3dfb26820ee0c9b1276aac834cf457026a575dfce8401000000490205ce0a000001411f0a24ae90af6d838e9c60ea479b1cca8cdaae583c8d73c1f9f3eb8b48e626aa551c354c5607c8f79f34f544729e246ca0740c2b523e6267f03d1f7faa615f47f6"; - - // Create AttestationDetails from the hex buffer - const buffer = Buffer.from(expectedHex, 'hex'); - const attestationDetails = new AttestationDetails(); - attestationDetails.fromBuffer(buffer); - - // Verify basic structure - expect(attestationDetails.version.toNumber()).toBe(1); - expect(attestationDetails.flags.toNumber()).toBe(0); - expect(attestationDetails.attestations.length).toBe(1); - - // Convert back to JSON and verify data - const json = attestationDetails.toJson(); - expect(json.version).toBe(1); - expect(json.attestations.length).toBe(1); - - const mmrJson = json.attestations[0].mmrdescriptor; - expect(mmrJson.version).toBe(1); - expect(mmrJson.objecthashtype).toBe(5); - expect(mmrJson.mmrhashtype).toBe(1); - - const sigJson = json.attestations[0].signaturedata; - expect(sigJson.version).toBe(1); - expect(sigJson.systemid).toBe("iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq"); - expect(sigJson.hashtype).toBe(1); - expect(sigJson.identityid).toBe("iKjrTCwoPFRk44fAi2nYNbPG16ZUQjv1NB"); - expect(sigJson.signaturetype).toBe(1); - - // Test round-trip: buffer -> object -> buffer should match - const newBuffer = attestationDetails.toBuffer(); - expect(newBuffer.toString('hex')).toBe(expectedHex); - }); - - test('addAttestation functionality', () => { - const testData = { - "mmrdescriptor": { - "version": 1, - "objecthashtype": 5, - "mmrhashtype": 1, - "mmrroot": { - "version": 1, - "flags": 0, - "objectdata": "da513b88a56ef93a55cfd7e8f49e1143fd26a2e6095a67fc0d368327d8e3d3df" - }, - "mmrhashes": { - "version": 1, - "flags": 0, - "objectdata": "41d826d3c6cbbc3a96992670d2f604e959fd1a8c014102c78ee8fa7c01db81cbf60181fc9baa101aa8c07d40c324d771145699168d3b18867a587f139173cf8b961d581fe15bbf15f5d02813a615e54c050d2b6b1cd4ee" - }, - "datadescriptors": [] - }, - "signaturedata": { - "version": 1, - "systemid": "iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq", - "hashtype": 1, - "signaturehash": "dfd3e3d82783360dfc675a09e6a226fd43119ef4e8d7cf553af96ea5883b51da", - "identityid": "iKjrTCwoPFRk44fAi2nYNbPG16ZUQjv1NB", - "signaturetype": 1, - "signature": "AgXOCgAAAUEfCiSukK9tg46cYOpHmxzKjNquWDyNc8H58+uLSOYmqlUcNUxWB8j3nzT1RHKeJGygdAwrUj5iZ/A9H3+qYV9H9g==" - } - }; - - // Create initial AttestationDetails - const attestationDetails = AttestationDetails.fromNodeResponse(testData, { - label: "Test Attestation", - id: "test-001", - timestamp: 1640995200000 // Jan 1, 2022 - }); - - // Verify initial state - expect(attestationDetails.hasLabel()).toBe(true); - expect(attestationDetails.hasId()).toBe(true); - expect(attestationDetails.hasTimestamp()).toBe(true); - expect(attestationDetails.label).toBe("Test Attestation"); - expect(attestationDetails.id).toBe("test-001"); - expect(attestationDetails.getAttestationCount()).toBe(1); - - // Add another attestation - attestationDetails.addAttestation(testData); - expect(attestationDetails.getAttestationCount()).toBe(2); - - // Test buffer serialization with metadata - const buffer = attestationDetails.toBuffer(); - const deserializedAttestation = new AttestationDetails(); - deserializedAttestation.fromBuffer(buffer); - - expect(deserializedAttestation.hasLabel()).toBe(true); - expect(deserializedAttestation.hasId()).toBe(true); - expect(deserializedAttestation.hasTimestamp()).toBe(true); - expect(deserializedAttestation.label).toBe("Test Attestation"); - expect(deserializedAttestation.id).toBe("test-001"); - expect(deserializedAttestation.getAttestationCount()).toBe(2); - }); -}); diff --git a/src/__tests__/vdxf/appencryptionrequestdetails.test.ts b/src/__tests__/vdxf/appencryptionrequestdetails.test.ts new file mode 100644 index 00000000..52ab85c0 --- /dev/null +++ b/src/__tests__/vdxf/appencryptionrequestdetails.test.ts @@ -0,0 +1,112 @@ +import { BN } from "bn.js"; +import { AppEncryptionRequestDetails, CompactIAddressObject, CompactAddressObject } from "../../vdxf/classes"; +import { BigNumber } from "../../utils/types/BigNumber"; + +// Helper function to create TransferDestination from address string +function createCompactAddressObject(type: BigNumber, address: string): CompactIAddressObject { + const obj = new CompactIAddressObject({ + address, + type + }); + + return obj; +} + +describe("AppEncryptionRequestDetails serialization tests", () => { + test("creates valid AppEncryptionRequestDetails with zaddress", () => { + const details = new AppEncryptionRequestDetails({ + version: AppEncryptionRequestDetails.DEFAULT_VERSION, + flags: AppEncryptionRequestDetails.HAS_DERIVATION_ID + .or(AppEncryptionRequestDetails.HAS_REQUEST_ID), + encryptToZAddress: "zs1sthrnsx5vmpmdl3pcd0paltcq9jf56hjjzu87shf90mt54y3szde6zaauvxw5sfuqh565arhmh4", + derivationNumber: new BN(42), + derivationID: createCompactAddressObject(CompactAddressObject.TYPE_I_ADDRESS, "i9nwxtKuVYX4MSbeULLiK2ttVi6rUEhh4X"), + requestID: "iD4CrjbJBZmwEZQ4bCWgbHx9tBHGP9mdSQ" + }); + + const newDetails = new AppEncryptionRequestDetails(); + const buffer = details.toBuffer(); + newDetails.fromBuffer(buffer); + const originalBuffer = details.toBuffer(); + const deserializedBuffer = newDetails.toBuffer(); + expect(originalBuffer.toString('hex')).toBe(deserializedBuffer.toString('hex')); + + + expect(details.isValid()).toBe(true); + expect(details.encryptToZAddress).toBe("zs1sthrnsx5vmpmdl3pcd0paltcq9jf56hjjzu87shf90mt54y3szde6zaauvxw5sfuqh565arhmh4"); + expect(details.flags.toNumber()).toBe(1+2); // HAS_DERIVATION_ID + HAS_REQUEST_ID + expect(details.derivationNumber.toNumber()).toBe(42); + expect(details.derivationID?.address).toBe("i9nwxtKuVYX4MSbeULLiK2ttVi6rUEhh4X"); + expect(details.requestID).toBe("iD4CrjbJBZmwEZQ4bCWgbHx9tBHGP9mdSQ"); + }); + + test("serializes and deserializes AppEncryptionRequestDetails correctly", () => { + // Create the first AppEncryptionRequestDetails + const originalDetails = new AppEncryptionRequestDetails({ + version: AppEncryptionRequestDetails.DEFAULT_VERSION, + flags: AppEncryptionRequestDetails.HAS_DERIVATION_ID + .or(AppEncryptionRequestDetails.HAS_REQUEST_ID), + encryptToZAddress: "zs1sthrnsx5vmpmdl3pcd0paltcq9jf56hjjzu87shf90mt54y3szde6zaauvxw5sfuqh565arhmh4", + derivationNumber: new BN(42), + derivationID: createCompactAddressObject(CompactAddressObject.TYPE_I_ADDRESS, "i9nwxtKuVYX4MSbeULLiK2ttVi6rUEhh4X"), + requestID: "iD4CrjbJBZmwEZQ4bCWgbHx9tBHGP9mdSQ" + }); + + // Serialize to buffer + const buffer = originalDetails.toBuffer(); + + // Create a new instance and deserialize from buffer + const deserializedDetails = new AppEncryptionRequestDetails(); + deserializedDetails.fromBuffer(buffer); + + // Verify both instances are valid + expect(originalDetails.isValid()).toBe(true); + expect(deserializedDetails.isValid()).toBe(true); + + // Verify all properties match + expect(deserializedDetails.version.toNumber()).toBe(originalDetails.version.toNumber()); + expect(deserializedDetails.flags.toNumber()).toBe(originalDetails.flags.toNumber()); + expect(deserializedDetails.encryptToZAddress).toBe(originalDetails.encryptToZAddress); + expect(deserializedDetails.derivationNumber.toNumber()).toBe(originalDetails.derivationNumber.toNumber()); + expect(deserializedDetails.derivationID?.BNType.toNumber()).toBe(originalDetails.derivationID?.BNType.toNumber()); + expect(deserializedDetails.derivationID?.address).toBe(originalDetails.derivationID?.address); + expect(deserializedDetails.requestID).toBe(originalDetails.requestID); + + // Verify that serializing both instances produces the same buffer + const originalBuffer = originalDetails.toBuffer(); + const deserializedBuffer = deserializedDetails.toBuffer(); + expect(originalBuffer.toString('hex')).toBe(deserializedBuffer.toString('hex')); + }); + + test("fromIAddress creates valid CompactAddressObject", () => { + const iaddr = "iDZvpsGCfX6vMJxi3F7m26qCX2Ns6QtQYk"; + const compactObj = CompactAddressObject.fromIAddress(iaddr); + + expect(compactObj).toBeInstanceOf(CompactAddressObject); + expect(compactObj.address).toBe(iaddr); + expect(compactObj.BNType.toString()).toBe(CompactAddressObject.TYPE_I_ADDRESS.toString()); + + const item = new CompactAddressObject(); + item.fromBuffer(compactObj.toBuffer()); + + expect(compactObj.toBuffer().toString('hex')).toBe(item.toBuffer().toString('hex')); + + }); + + test("toIAddress converts FQN to IAddress correctly", () => { + const fqn = "myidentity.VRSC@"; + const compactObj = new CompactAddressObject({ + type: CompactAddressObject.TYPE_FQN, + address: fqn, + rootSystemName: "VRSC" + }); + const iaddr = compactObj.toIAddress(); + + expect(iaddr).toBe("iDZvpsGCfX6vMJxi3F7m26qCX2Ns6QtQYk"); + const item = new CompactAddressObject(); + item.fromBuffer(compactObj.toBuffer()); + + expect(compactObj.toBuffer().toString('hex')).toBe(item.toBuffer().toString('hex')); + + }); +}); diff --git a/src/__tests__/vdxf/appencryptionresponsedetails.test.ts b/src/__tests__/vdxf/appencryptionresponsedetails.test.ts new file mode 100644 index 00000000..96af4c92 --- /dev/null +++ b/src/__tests__/vdxf/appencryptionresponsedetails.test.ts @@ -0,0 +1,163 @@ +import { SaplingExtendedViewingKey } from '../../pbaas/SaplingExtendedViewingKey'; +import { SaplingExtendedSpendingKey } from '../../pbaas/SaplingExtendedSpendingKey'; +import { SaplingPaymentAddress } from '../../pbaas/SaplingPaymentAddress'; +import { BN } from 'bn.js'; +import { AppEncryptionResponseDetails } from '../../vdxf/classes'; + +describe('AppEncryptionResponseDetails', () => { + const testViewingKey = 'zxviews1q0njl87fqqqqpq8vghkp6nz9wx48mwelukvhx3yfwg7msatglv4xy8rrh87k9z472edvlrt950qyy6r766dxnpqktxug7t2wy80s4ug325dwp9hf4vw9a6ethf2mwc9wan28p88dq8q2e8sdlw2mhffg6hy92tjyuquz7a8reqdz905x6xt6kqdx5wn7jvas0733hends8q6s8k87emn6m060xdnhgmvn4zmx0ssrwve84lzxkqu2dnfq5qsjwrtlject0an0k282rsnx0kq4'; + const testSpendingKey = 'secret-extended-key-main1q0njl87fqqqqpq8vghkp6nz9wx48mwelukvhx3yfwg7msatglv4xy8rrh87k9z472el95h53ym2tku2dazny0j2vfukgmp6fu3k7edzcx9n8egesc32sdy3xr4s2ep4skgc7t5j5zds4ws7hf2nuszf7ltfn2nc5rk3k77gyeqdz905x6xt6kqdx5wn7jvas0733hends8q6s8k87emn6m060xdnhgmvn4zmx0ssrwve84lzxkqu2dnfq5qsjwrtlject0an0k282rs0gws78'; + const testAddress = 'zs1anxaua04mnl7dz2mjpflhw0mt73uxy9rjac53lgduk02kh3lnf0hxufk9d76j5uep5j55f5h5rk'; + const testRequestID = 'iD4CrjbJBZmwEZQ4bCWgbHx9tBHGP9mdSQ'; + + it('should create with minimal data', () => { + const testIncomingViewingKey = Buffer.from('be9af283ecfe0552480dd7e1ce9af61a12e64da4927e8011a795cb223f4afc00"', 'hex'); + const response = new AppEncryptionResponseDetails({ + version: new BN(1), + incomingViewingKey: testIncomingViewingKey, + extendedViewingKey: SaplingExtendedViewingKey.fromKeyString(testViewingKey), + address: SaplingPaymentAddress.fromAddressString(testAddress) + }); + + expect(response.incomingViewingKey).toEqual(testIncomingViewingKey); + expect(response.extendedViewingKey).toBeInstanceOf(SaplingExtendedViewingKey); + expect(response.address).toBeInstanceOf(SaplingPaymentAddress); + expect(response.containsRequestID()).toBe(false); + expect(response.containsExtendedSpendingKey()).toBe(false); + }); + + it('should create with requestID', () => { + const testIncomingViewingKey = Buffer.from('1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef', 'hex'); + const response = new AppEncryptionResponseDetails({ + version: new BN(1), + requestID: testRequestID, + incomingViewingKey: testIncomingViewingKey, + extendedViewingKey: SaplingExtendedViewingKey.fromKeyString(testViewingKey), + address: SaplingPaymentAddress.fromAddressString(testAddress) + }); + + expect(response.incomingViewingKey).toEqual(testIncomingViewingKey); + expect(response.requestID).toBe(testRequestID); + expect(response.containsRequestID()).toBe(true); + expect(response.containsExtendedSpendingKey()).toBe(false); + }); + + it('should create with extended spending key', () => { + const testIncomingViewingKey = Buffer.from('fedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321', 'hex'); + const response = new AppEncryptionResponseDetails({ + version: new BN(1), + incomingViewingKey: testIncomingViewingKey, + extendedViewingKey: SaplingExtendedViewingKey.fromKeyString(testViewingKey), + address: SaplingPaymentAddress.fromAddressString(testAddress), + extendedSpendingKey: SaplingExtendedSpendingKey.fromKeyString(testSpendingKey) + }); + + expect(response.incomingViewingKey).toEqual(testIncomingViewingKey); + expect(response.extendedSpendingKey).toBeInstanceOf(SaplingExtendedSpendingKey); + expect(response.containsRequestID()).toBe(false); + expect(response.containsExtendedSpendingKey()).toBe(true); + }); + + it('should create with all optional fields', () => { + const testIncomingViewingKey = Buffer.from('0f1e2d3c4b5a69788796a5b4c3d2e1f00f1e2d3c4b5a69788796a5b4c3d2e1f0', 'hex'); + const response = new AppEncryptionResponseDetails({ + version: new BN(1), + requestID: testRequestID, + incomingViewingKey: testIncomingViewingKey, + extendedViewingKey: SaplingExtendedViewingKey.fromKeyString(testViewingKey), + address: SaplingPaymentAddress.fromAddressString(testAddress), + extendedSpendingKey: SaplingExtendedSpendingKey.fromKeyString(testSpendingKey) + }); + + expect(response.incomingViewingKey).toEqual(testIncomingViewingKey); + expect(response.requestID).toBe(testRequestID); + expect(response.containsRequestID()).toBe(true); + expect(response.extendedSpendingKey).toBeInstanceOf(SaplingExtendedSpendingKey); + expect(response.containsExtendedSpendingKey()).toBe(true); + }); + + it('should serialize and deserialize via buffer (minimal)', () => { + const testIncomingViewingKey = Buffer.from('9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba', 'hex'); + const response = new AppEncryptionResponseDetails({ + version: new BN(1), + incomingViewingKey: testIncomingViewingKey, + extendedViewingKey: SaplingExtendedViewingKey.fromKeyString(testViewingKey), + address: SaplingPaymentAddress.fromAddressString(testAddress) + }); + + const buffer = response.toBuffer(); + const response2 = new AppEncryptionResponseDetails(); + response2.fromBuffer(buffer); + + expect(response2.incomingViewingKey.toString('hex')).toBe(testIncomingViewingKey.toString('hex')); + expect(response2.containsRequestID()).toBe(false); + expect(response2.containsExtendedSpendingKey()).toBe(false); + expect(response2.extendedViewingKey.toKeyString()).toBe(testViewingKey); + expect(response2.address.toAddressString()).toBe(testAddress); + }); + + it('should serialize and deserialize via buffer (with requestID)', () => { + const testIncomingViewingKey = Buffer.from('abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789', 'hex'); + const response = new AppEncryptionResponseDetails({ + version: new BN(1), + requestID: testRequestID, + incomingViewingKey: testIncomingViewingKey, + extendedViewingKey: SaplingExtendedViewingKey.fromKeyString(testViewingKey), + address: SaplingPaymentAddress.fromAddressString(testAddress) + }); + + const buffer = response.toBuffer(); + const response2 = new AppEncryptionResponseDetails(); + response2.fromBuffer(buffer); + + expect(response2.incomingViewingKey.toString('hex')).toBe(testIncomingViewingKey.toString('hex')); + expect(response2.requestID).toBe(testRequestID); + expect(response2.containsRequestID()).toBe(true); + expect(response2.extendedViewingKey.toKeyString()).toBe(testViewingKey); + expect(response2.address.toAddressString()).toBe(testAddress); + }); + + it('should serialize and deserialize via buffer (with spending key)', () => { + const testIncomingViewingKey = Buffer.from('5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a', 'hex'); + const response = new AppEncryptionResponseDetails({ + version: new BN(1), + incomingViewingKey: testIncomingViewingKey, + extendedViewingKey: SaplingExtendedViewingKey.fromKeyString(testViewingKey), + address: SaplingPaymentAddress.fromAddressString(testAddress), + extendedSpendingKey: SaplingExtendedSpendingKey.fromKeyString(testSpendingKey) + }); + + const buffer = response.toBuffer(); + const response2 = new AppEncryptionResponseDetails(); + response2.fromBuffer(buffer); + + expect(response2.incomingViewingKey.toString('hex')).toBe(testIncomingViewingKey.toString('hex')); + expect(response2.containsExtendedSpendingKey()).toBe(true); + expect(response2.extendedSpendingKey).toBeDefined(); + expect(response2.extendedSpendingKey!.toKeyString()).toBe(testSpendingKey); + }); + + it('should serialize and deserialize via JSON', () => { + const testIncomingViewingKey = Buffer.from('b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0', 'hex'); + const response = new AppEncryptionResponseDetails({ + version: new BN(1), + requestID: testRequestID, + incomingViewingKey: testIncomingViewingKey, + extendedViewingKey: SaplingExtendedViewingKey.fromKeyString(testViewingKey), + address: SaplingPaymentAddress.fromAddressString(testAddress), + extendedSpendingKey: SaplingExtendedSpendingKey.fromKeyString(testSpendingKey) + }); + + const json = response.toJson(); + const response2 = AppEncryptionResponseDetails.fromJson(json); + + expect(response2.incomingViewingKey.toString('hex')).toBe(testIncomingViewingKey.toString('hex')); + expect(response2.requestID).toBe(testRequestID); + expect(response2.containsRequestID()).toBe(true); + expect(response2.extendedViewingKey.toKeyString()).toBe(testViewingKey); + expect(response2.address.toAddressString()).toBe(testAddress); + expect(response2.extendedSpendingKey).toBeDefined(); + expect(response2.extendedSpendingKey!.toKeyString()).toBe(testSpendingKey); + expect(response2.containsExtendedSpendingKey()).toBe(true); + }); +}); diff --git a/src/__tests__/vdxf/authenticationrequestdetails.test.ts b/src/__tests__/vdxf/authenticationrequestdetails.test.ts new file mode 100644 index 00000000..2797a3a0 --- /dev/null +++ b/src/__tests__/vdxf/authenticationrequestdetails.test.ts @@ -0,0 +1,58 @@ +import { BN } from "bn.js"; +import { + AuthenticationRequestDetails, + CompactAddressObject, + CompactIAddressObject +} from "../../vdxf/classes"; +import { SERIALIZED_AUTHENTICATION_REQUEST_DETAILS, TEST_CHALLENGE_ID, TEST_IDENTITY_ID_1, TEST_IDENTITY_ID_2, TEST_IDENTITY_ID_3, TEST_SYSTEMID } from "../constants/fixtures"; + +describe("AuthenticationRequestDetails", () => { + describe("constructor and basic properties", () => { + test("creates instance with minimal required data", () => { + const details = new AuthenticationRequestDetails(); + + const detailsBuffer = details.toBuffer(); + + const newDetails = new AuthenticationRequestDetails(); + newDetails.fromBuffer(detailsBuffer); + + expect(details.flags?.toString()).toBe("0"); + expect(details.recipientConstraints).toBeNull(); + expect(detailsBuffer.toString('hex')).toBe(newDetails.toBuffer().toString('hex')); + }); + + test("creates instance with all optional data", () => { + const details = new AuthenticationRequestDetails({ + requestID: CompactIAddressObject.fromAddress(TEST_CHALLENGE_ID, TEST_SYSTEMID.toAddress()!), + recipientConstraints: [ + { type: AuthenticationRequestDetails.REQUIRED_ID, identity: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_I_ADDRESS, address: TEST_IDENTITY_ID_1, rootSystemName: "VRSC" }) }, + { type: AuthenticationRequestDetails.REQUIRED_SYSTEM, identity: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_I_ADDRESS, address: TEST_IDENTITY_ID_2, rootSystemName: "VRSC" }) }, + { type: AuthenticationRequestDetails.REQUIRED_PARENT, identity: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_I_ADDRESS, address: TEST_IDENTITY_ID_3, rootSystemName: "VRSC" }) } + ], + expiryTime: new BN(2938475938457) // 1 hour from now + }); + + const detailsBuffer = details.toBuffer(); + + const newDetails = new AuthenticationRequestDetails(); + newDetails.fromBuffer(detailsBuffer); + + expect(newDetails.requestID!.toAddress()).toBe(TEST_CHALLENGE_ID); + expect(newDetails.recipientConstraints?.length).toBe(3); + expect(newDetails.expiryTime?.toString()).toBe("2938475938457"); + + expect(detailsBuffer.toString('hex')).toBe(newDetails.toBuffer().toString('hex')); + + expect(details.toBuffer().toString('hex')).toBe(SERIALIZED_AUTHENTICATION_REQUEST_DETAILS.toString('hex')); + + }); + + test("creates instance with default constructor", () => { + const details = new AuthenticationRequestDetails(); + + expect(details.hasRequestID()).toBe(false); + expect(details.flags?.toString()).toBe("0"); + expect(details.recipientConstraints).toBeNull(); + }); + }); +}); diff --git a/src/__tests__/vdxf/authenticationresponsedetails.test.ts b/src/__tests__/vdxf/authenticationresponsedetails.test.ts new file mode 100644 index 00000000..497b3081 --- /dev/null +++ b/src/__tests__/vdxf/authenticationresponsedetails.test.ts @@ -0,0 +1,24 @@ +import { + AuthenticationResponseDetails, + CompactIAddressObject +} from "../../vdxf/classes"; +import { TEST_CHALLENGE_ID, TEST_SYSTEMID } from "../constants/fixtures"; + +describe("AuthenticationRequestDetails", () => { + describe("constructor and basic properties", () => { + test("creates instance with all optional data", () => { + const details = new AuthenticationResponseDetails({ + requestID: CompactIAddressObject.fromAddress(TEST_CHALLENGE_ID, TEST_SYSTEMID.toAddress()!) + }); + + const detailsBuffer = details.toBuffer(); + + const newDetails = new AuthenticationResponseDetails(); + newDetails.fromBuffer(detailsBuffer); + + expect(newDetails.requestID!.toAddress()).toBe(TEST_CHALLENGE_ID); + + expect(detailsBuffer.toString('hex')).toBe(newDetails.toBuffer().toString('hex')); + }); + }); +}); diff --git a/src/__tests__/vdxf/compactaddressidobject.test.ts b/src/__tests__/vdxf/compactaddressidobject.test.ts new file mode 100644 index 00000000..6c8fc3be --- /dev/null +++ b/src/__tests__/vdxf/compactaddressidobject.test.ts @@ -0,0 +1,122 @@ +import { CompactAddressObject, CompactAddressXVariant, CompactXAddressObject } from '../../vdxf/classes/CompactAddressObject'; +import { BN } from "bn.js"; + + + +describe("CompactAddressObject", () => { + describe("constructor and basic properties", () => { + + test("creates instance with iaddress", () => { + const item = new CompactAddressObject({ + version: new BN(CompactAddressObject.DEFAULT_VERSION), + type: CompactAddressObject.TYPE_I_ADDRESS, + address: "iB5PRXMHLYcNtM8dfLB6KwfJrHU2mKDYuU", + rootSystemName: "VRSC" + }); + + const detailsBuffer = item.toBuffer(); + + const newDetails = new CompactAddressObject(); + newDetails.fromBuffer(detailsBuffer); + expect(newDetails.version.toString()).toBe("1"); + expect(newDetails.BNType.toNumber()).toBe(CompactAddressObject.TYPE_I_ADDRESS.toNumber()); + expect(newDetails.address).toBe("iB5PRXMHLYcNtM8dfLB6KwfJrHU2mKDYuU"); + expect(newDetails.rootSystemName).toBe("VRSC"); + expect(detailsBuffer.toString('hex')).toBe(newDetails.toBuffer().toString('hex')); + expect(item.toIAddress()).toBe("iB5PRXMHLYcNtM8dfLB6KwfJrHU2mKDYuU"); + }); + + test("creates instance with xaddress", () => { + const item = new CompactAddressObject({ + version: new BN(CompactAddressObject.DEFAULT_VERSION), + type: CompactAddressObject.TYPE_X_ADDRESS, + address: "xA91QPpBrHZto92NCU5KEjCqRveS4dAPrf", + rootSystemName: "VRSC" + }); + + const detailsBuffer = item.toBuffer(); + + const newDetails = new CompactAddressObject(); + newDetails.fromBuffer(detailsBuffer); + expect(newDetails.version.toString()).toBe("1"); + expect(newDetails.BNType.toNumber()).toBe(CompactAddressObject.TYPE_X_ADDRESS.toNumber()); + expect(newDetails.address).toBe("xA91QPpBrHZto92NCU5KEjCqRveS4dAPrf"); + expect(newDetails.rootSystemName).toBe("VRSC"); + expect(detailsBuffer.toString('hex')).toBe(newDetails.toBuffer().toString('hex')); + }); + + test("creates instance with data key", () => { + const item = new CompactAddressObject({ + version: new BN(CompactAddressObject.DEFAULT_VERSION), + type: CompactAddressObject.TYPE_FQN, + address: "vrsc::applications.wallet" + }); + + const detailsBuffer = item.toBuffer(); + + const newDetails = new CompactAddressObject(); + newDetails.fromBuffer(detailsBuffer); + expect(newDetails.version.toString()).toBe("1"); + expect(newDetails.BNType.toNumber()).toBe(CompactAddressObject.TYPE_FQN.toNumber()); + expect(newDetails.address).toBe("vrsc::applications.wallet"); + expect(newDetails.rootSystemName).toBe("VRSC"); + expect(detailsBuffer.toString('hex')).toBe(newDetails.toBuffer().toString('hex')); + expect(item.toXAddress()).toBe("xA91QPpBrHZto92NCU5KEjCqRveS4dAPrf"); + }); + + test("creates instance of CompactXAddress with data key", () => { + const item = new CompactXAddressObject({ + version: new BN(CompactAddressObject.DEFAULT_VERSION), + type: CompactAddressObject.TYPE_FQN, + address: "vrsc::applications.wallet" + }); + + const detailsBuffer = item.toBuffer(); + + const newDetails = new CompactAddressObject(); + newDetails.fromBuffer(detailsBuffer); + expect(newDetails.version.toString()).toBe("1"); + expect(newDetails.BNType.toNumber()).toBe(CompactAddressObject.TYPE_FQN.toNumber()); + expect(newDetails.address).toBe("vrsc::applications.wallet"); + expect(newDetails.rootSystemName).toBe("VRSC"); + expect(detailsBuffer.toString('hex')).toBe(newDetails.toBuffer().toString('hex')); + expect(item.toAddress()).toBe("xA91QPpBrHZto92NCU5KEjCqRveS4dAPrf"); + }); + + test("creates instance with fqn", () => { + const item = new CompactAddressObject({ + version: new BN(CompactAddressObject.DEFAULT_VERSION), + type: CompactAddressObject.TYPE_FQN, + address: "bob.chips@", + rootSystemName: "VRSC" + }); + + const detailsBuffer = item.toBuffer(); + + const newDetails = new CompactAddressObject(); + newDetails.fromBuffer(detailsBuffer); + expect(newDetails.version.toString()).toBe("1"); + expect(newDetails.BNType.toNumber()).toBe(CompactAddressObject.TYPE_FQN.toNumber()); + expect(newDetails.address).toBe("bob.chips@"); + expect(newDetails.rootSystemName).toBe("VRSC"); + expect(detailsBuffer.toString('hex')).toBe(newDetails.toBuffer().toString('hex')); + }); + + test("creates instance with fqn that reduces to iaddress for space saving", () => { + const item = new CompactAddressObject({ + version: new BN(CompactAddressObject.DEFAULT_VERSION), + type: CompactAddressObject.TYPE_FQN, + address: "bob91283472394872349824728934789234.token823984279847293847239487239847324.chips@", + rootSystemName: "VRSC" + }); + + const detailsBuffer = item.toBuffer(); // this mutates the item to use iaddress internally + + const newDetails = new CompactAddressObject(); + newDetails.fromBuffer(detailsBuffer); + expect(newDetails.version.toString()).toBe("1"); + expect(newDetails.rootSystemName).toBe("VRSC"); + expect(detailsBuffer.toString('hex')).toBe(newDetails.toBuffer().toString('hex')); + }); + }); +}); diff --git a/src/__tests__/vdxf/genericrequest.test.ts b/src/__tests__/vdxf/genericrequest.test.ts new file mode 100644 index 00000000..ea2c12ea --- /dev/null +++ b/src/__tests__/vdxf/genericrequest.test.ts @@ -0,0 +1,367 @@ +import { BN } from 'bn.js'; +import base64url from 'base64url'; +import { DATA_TYPE_MMRDATA, DEFAULT_VERUS_CHAINID, HASH_TYPE_SHA256, NULL_I_ADDR } from '../../constants/pbaas'; +import { ContentMultiMap, DEST_PKH, fromBase58Check, GenericRequest, IDENTITY_VERSION_PBAAS, IdentityID, IdentityUpdateRequestDetails, KeyID, PartialIdentity, PartialMMRData, PartialSignData, PartialSignDataInitData, ResponseURI, SaplingPaymentAddress, TransferDestination, VerusPayInvoiceDetails } from '../../'; +import { VerifiableSignatureData, VerifiableSignatureDataInterface } from '../../vdxf/classes/VerifiableSignatureData'; +import { CompactIAddressObject } from '../../vdxf/classes/CompactAddressObject'; +import { GeneralTypeOrdinalVDXFObject, IdentityUpdateRequestOrdinalVDXFObject, VerusPayInvoiceOrdinalVDXFObject } from '../../vdxf/classes/ordinals'; +import { DEEPLINK_PROTOCOL_URL_CURRENT_VERSION, DEEPLINK_PROTOCOL_URL_STRING } from '../../constants/deeplink'; + +describe('GenericRequest — buffer / URI / QR operations', () => { + function roundTripBuffer(req: GenericRequest): GenericRequest { + const buf = req.toBuffer(); + const clone = new GenericRequest(); + clone.fromBuffer(buf, 0); + + return GenericRequest.fromQrString((GenericRequest.fromWalletDeeplinkUri(clone.toWalletDeeplinkUri())).toQrString()); + } + + it('round trips with a single detail (no signature / createdAt)', () => { + const detail = new GeneralTypeOrdinalVDXFObject({ + data: Buffer.from('cafebabe', 'hex'), + key: DEFAULT_VERUS_CHAINID + }); + const req = new GenericRequest({ details: [detail] }); + + expect(req.hasMultiDetails()).toBe(false); + expect(req.hasCreatedAt()).toBe(false); + expect(req.isSigned()).toBe(false); + + const round = roundTripBuffer(req); + expect(round.version.toString()).toEqual(req.version.toString()); + expect(round.flags.toString()).toEqual(req.flags.toString()); + expect(round.details.length).toBe(1); + const d2 = round.getDetails(0); + expect(d2).toBeInstanceOf(GeneralTypeOrdinalVDXFObject); + expect((d2 as GeneralTypeOrdinalVDXFObject).data).toEqual(detail.data); + expect((d2 as GeneralTypeOrdinalVDXFObject).key).toEqual(detail.key); + expect(round.toBuffer().toString('hex')).toEqual(req.toBuffer().toString('hex')); + }); + + it('round trips with multiple details', () => { + const d1 = new GeneralTypeOrdinalVDXFObject({ + data: Buffer.from('aa', 'hex'), + key: DEFAULT_VERUS_CHAINID + }); + const d2 = new GeneralTypeOrdinalVDXFObject({ + data: Buffer.from('bb', 'hex'), + key: DEFAULT_VERUS_CHAINID + }); + const req = new GenericRequest({ details: [d1, d2] }); + expect(req.hasMultiDetails()).toBe(true); + + const round = roundTripBuffer(req); + expect(round.details.length).toBe(2); + expect((round.getDetails(0) as GeneralTypeOrdinalVDXFObject).data).toEqual(d1.data); + expect((round.getDetails(1) as GeneralTypeOrdinalVDXFObject).data).toEqual(d2.data); + expect(round.toBuffer().toString('hex')).toEqual(req.toBuffer().toString('hex')); + }); + + it('round trips with createdAt, signature, responseURI, requestID, encryptResponseToAddress, and appOrDelegatedID', () => { + const sig = new VerifiableSignatureData({ + flags: new BN(0), + version: new BN(1), + systemID: CompactIAddressObject.fromAddress(DEFAULT_VERUS_CHAINID), + hashType: HASH_TYPE_SHA256, + identityID: CompactIAddressObject.fromAddress(DEFAULT_VERUS_CHAINID), + signatureAsVch: Buffer.from('AgX3RgAAAUEgHAVIHuui1Sc9oLxLbglKvmrv47JJLiM0/RBQwzYL1dlamI/2o9qBc93d79laLXWMhQomqZ4U3Mlr3ueuwl4JFA==', 'base64'), + vdxfKeys: [DEFAULT_VERUS_CHAINID, DEFAULT_VERUS_CHAINID], + vdxfKeyNames: ["VRSC", "VRSC"], + boundHashes: [Buffer.from('abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd', 'hex')], + statements: [Buffer.from('1234123412341234123412341234123412341234123412341234123412341234', 'hex')] + }); + + const detail = new GeneralTypeOrdinalVDXFObject({ + data: Buffer.from('abcd', 'hex'), + key: DEFAULT_VERUS_CHAINID + }); + + const createdAt = new BN(9999); + const saplingAddr = "zs1wczplx4kegw32h8g0f7xwl57p5tvnprwdmnzmdnsw50chcl26f7tws92wk2ap03ykaq6jyyztfa" + + const req = new GenericRequest({ + details: [detail], + signature: sig, + requestID: CompactIAddressObject.fromAddress(NULL_I_ADDR), + createdAt, + encryptResponseToAddress: SaplingPaymentAddress.fromAddressString(saplingAddr), + appOrDelegatedID: CompactIAddressObject.fromAddress(DEFAULT_VERUS_CHAINID), + responseURIs: [ResponseURI.fromUriString("https://verus.io/callback", ResponseURI.TYPE_POST), ResponseURI.fromUriString("https://example.com/callback", ResponseURI.TYPE_REDIRECT)] + }); + + expect(req.isSigned()).toBe(true); + expect(req.hasCreatedAt()).toBe(true); + + const round = roundTripBuffer(req); + expect(round.signature).toBeDefined(); + expect(round.signature?.signatureAsVch.toString('base64')).toBe(sig.signatureAsVch.toString('base64')) + expect(round.createdAt?.toString()).toEqual(createdAt.toString()); + expect(round.hasResponseURIs()).toBe(true) + expect(round.responseURIs![0].getUriString()).toBe("https://verus.io/callback") + expect(round.responseURIs![0].type.toString()).toBe(ResponseURI.TYPE_POST.toString()) + expect(round.responseURIs![1].getUriString()).toBe("https://example.com/callback") + expect(round.responseURIs![1].type.toString()).toBe(ResponseURI.TYPE_REDIRECT.toString()) + expect(round.requestID?.toAddress()).toBe(NULL_I_ADDR) + expect(round.appOrDelegatedID?.toIAddress()).toBe(DEFAULT_VERUS_CHAINID) + expect(round.hasEncryptResponseToAddress()).toBe(true) + expect(round.encryptResponseToAddress?.toAddressString()).toBe(saplingAddr) + const d2 = round.getDetails(0); + expect((d2 as GeneralTypeOrdinalVDXFObject).data).toEqual(detail.data); + expect(round.toBuffer().toString('hex')).toEqual(req.toBuffer().toString('hex')); + }); + + it('round trips with createdAt, and valid signature that can be hashed', () => { + const sig = new VerifiableSignatureData({ + systemID: CompactIAddressObject.fromAddress(DEFAULT_VERUS_CHAINID), + identityID: CompactIAddressObject.fromAddress(DEFAULT_VERUS_CHAINID), + signatureAsVch: Buffer.from('AgX3RgAAAUEgHAVIHuui1Sc9oLxLbglKvmrv47JJLiM0/RBQwzYL1dlamI/2o9qBc93d79laLXWMhQomqZ4U3Mlr3ueuwl4JFA==', 'base64'), + }); + + const detail = new GeneralTypeOrdinalVDXFObject({ + data: Buffer.from('abcd', 'hex'), + key: DEFAULT_VERUS_CHAINID + }); + + const createdAt = new BN(9999); + const saplingAddr = "zs1wczplx4kegw32h8g0f7xwl57p5tvnprwdmnzmdnsw50chcl26f7tws92wk2ap03ykaq6jyyztfa" + + const req = new GenericRequest({ + details: [detail], + signature: sig, + createdAt, + encryptResponseToAddress: SaplingPaymentAddress.fromAddressString(saplingAddr) + }); + + expect(req.isSigned()).toBe(true); + expect(req.hasCreatedAt()).toBe(true); + expect(req.getDetailsIdentitySignatureHash(1000)).toBeDefined(); + expect(req.signature?.signatureVersion.toString()).toBe("2"); + + const round = roundTripBuffer(req); + expect(round.signature).toBeDefined(); + expect(round.signature?.signatureAsVch.toString('base64')).toBe(sig.signatureAsVch.toString('base64')) + expect(round.createdAt?.toString()).toEqual(createdAt.toString()); + expect(round.hasEncryptResponseToAddress()).toBe(true) + expect(round.encryptResponseToAddress?.toAddressString()).toBe(saplingAddr) + const d2 = round.getDetails(0); + expect((d2 as GeneralTypeOrdinalVDXFObject).data).toEqual(detail.data); + expect(round.toBuffer().toString('hex')).toEqual(req.toBuffer().toString('hex')); + }); + + it('round trips with createdAt, signature that can be hashed, and invoice', () => { + const sig = new VerifiableSignatureData({ + systemID: CompactIAddressObject.fromAddress(DEFAULT_VERUS_CHAINID), + identityID: CompactIAddressObject.fromAddress(DEFAULT_VERUS_CHAINID), + signatureAsVch: Buffer.from('AgX3RgAAAUEgHAVIHuui1Sc9oLxLbglKvmrv47JJLiM0/RBQwzYL1dlamI/2o9qBc93d79laLXWMhQomqZ4U3Mlr3ueuwl4JFA==', 'base64'), + }); + + const details = new VerusPayInvoiceDetails({ + amount: new BN(10000000000, 10), + destination: new TransferDestination({ + type: DEST_PKH, + destination_bytes: fromBase58Check("R9J8E2no2HVjQmzX6Ntes2ShSGcn7WiRcx").hash + }), + requestedcurrencyid: "iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq", + maxestimatedslippage: new BN(40000000, 10), + expiryheight: new BN(2000000, 10), + acceptedsystems: ["iNC9NG5Jqk2tqVtqfjfiSpaqxrXaFU6RDu", "iBDkVJqik6BrtcDBQfFygffiYzTMy6EuhU"] + }) + + details.setFlags({ + acceptsConversion: true, + expires: true, + acceptsNonVerusSystems: true + }) + + const createdAt = new BN(9999); + const saplingAddr = "zs1wczplx4kegw32h8g0f7xwl57p5tvnprwdmnzmdnsw50chcl26f7tws92wk2ap03ykaq6jyyztfa" + + const req = new GenericRequest({ + details: [new VerusPayInvoiceOrdinalVDXFObject({ + data: details, + })], + signature: sig, + createdAt, + encryptResponseToAddress: SaplingPaymentAddress.fromAddressString(saplingAddr) + }); + + expect(req.isSigned()).toBe(true); + expect(req.hasCreatedAt()).toBe(true); + expect(req.getDetailsIdentitySignatureHash(1000)).toBeDefined(); + expect(req.signature?.signatureVersion.toString()).toBe("2"); + + const round = roundTripBuffer(req); + expect(round.signature).toBeDefined(); + expect(round.signature?.signatureAsVch.toString('base64')).toBe(sig.signatureAsVch.toString('base64')) + expect(round.createdAt?.toString()).toEqual(createdAt.toString()); + expect(round.hasEncryptResponseToAddress()).toBe(true) + expect(round.encryptResponseToAddress?.toAddressString()).toBe(saplingAddr) + const d2 = round.getDetails(0); + expect((d2 as VerusPayInvoiceOrdinalVDXFObject).data).toEqual(details); + expect(round.toBuffer().toString('hex')).toEqual(req.toBuffer().toString('hex')); + }); + + it('same hash before/after signature', () => { + const contentmap = new Map(); + contentmap.set("iPsFBfFoCcxtuZNzE8yxPQhXVn4dmytf8j", Buffer.alloc(32)); + contentmap.set("iK7a5JNJnbeuYWVHCDRpJosj3irGJ5Qa8c", Buffer.alloc(32)); + + const systemID = IdentityID.fromAddress("iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq"); + const requestID = "iPsFBfFoCcxtuZNzE8yxPQhXVn4dmytf8j" + const createdAt = new BN("1700000000", 10); + const expiryHeight = new BN("123456"); + const salt = Buffer.from('=H319X:)@H2Z'); + + const partialIdentity = new PartialIdentity({ + flags: new BN("0"), + version: IDENTITY_VERSION_PBAAS, + min_sigs: new BN(1), + primary_addresses: [ + KeyID.fromAddress("RQVsJRf98iq8YmRQdehzRcbLGHEx6YfjdH"), + KeyID.fromAddress("RP4Qct9197i5vrS11qHVtdyRRoAHVNJS47") + ], + parent: IdentityID.fromAddress("iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq"), + system_id: IdentityID.fromAddress("iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq"), + name: "TestID", + content_map: contentmap, + content_multimap: ContentMultiMap.fromJson({ + iPsFBfFoCcxtuZNzE8yxPQhXVn4dmytf8j: [ + { iK7a5JNJnbeuYWVHCDRpJosj3irGJ5Qa8c: 'Test String 123454321' }, + { iK7a5JNJnbeuYWVHCDRpJosj3irGJ5Qa8c: 'Test String 123454321' }, + { iK7a5JNJnbeuYWVHCDRpJosj3irGJ5Qa8c: 'Test String 123454321' }, + { iK7a5JNJnbeuYWVHCDRpJosj3irGJ5Qa8c: 'Test String 123454321' } + ], + iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq: '6868686868686868686868686868686868686868', + i5v3h9FWVdRFbNHU7DfcpGykQjRaHtMqu7: [ + '6868686868686868686868686868686868686868', + '6868686868686868686868686868686868686868', + '6868686868686868686868686868686868686868' + ], + i81XL8ZpuCo9jmWLv5L5ikdxrGuHrrpQLz: { iK7a5JNJnbeuYWVHCDRpJosj3irGJ5Qa8c: 'Test String 123454321' } + }), + recovery_authority: IdentityID.fromAddress("i81XL8ZpuCo9jmWLv5L5ikdxrGuHrrpQLz"), + revocation_authority: IdentityID.fromAddress("i5v3h9FWVdRFbNHU7DfcpGykQjRaHtMqu7"), + unlock_after: new BN("123456", 10), + private_addresses: [SaplingPaymentAddress.fromAddressString("zs1wczplx4kegw32h8g0f7xwl57p5tvnprwdmnzmdnsw50chcl26f7tws92wk2ap03ykaq6jyyztfa")] + }); + + const mmrData = new PartialMMRData({ + flags: new BN('0', 10), + data: [ + { type: new BN('2', 10), data: Buffer.from('src/__tests__/pbaas/partialmmrdata.test.ts', 'utf-8') }, + { type: new BN('3', 10), data: Buffer.from('Hello test message 12345', 'utf-8') }, + ], + salt: [Buffer.from('=H319X:)@H2Z'), Buffer.from('s*1UHmVr?feI')], + mmrhashtype: new BN('1', 10), // e.g. PartialMMRData.HASH_TYPE_SHA256 + priormmr: [ + Buffer.from('80a28cdff6bd91a2e96a473c234371fd8b67705a8c4956255ce7b8c7bf20470f02381c9a935f06cdf986a7c5facd77625befa11cf9fd4b59857b457394a8af979ab2830087a3b27041b37bc318484175'), + Buffer.from('d97fd4bbd9e88ca0c5822c12d5c9b272b2044722aa48b1c8fde178be6b59ccea509f403d3acd226c16ba3c32f0cb92e2fcaaa02b40d0bc5257e0fbf2e6c3d3d7f1a1df066967b193d131158ba5bef732') + ], + }) + + const baseSignDataWithMMR: PartialSignDataInitData = { + flags: new BN('0', 10), + address: IdentityID.fromAddress('iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq'), + prefixString: Buffer.from('example prefix', 'utf8'), + vdxfKeys: [IdentityID.fromAddress('i81XL8ZpuCo9jmWLv5L5ikdxrGuHrrpQLz')], + vdxfKeyNames: [Buffer.from('VDXFNAME', 'utf8')], + boundHashes: [Buffer.from('0873c6ba879ce87f5c207a4382b273cac164361af0b9fe63d6d7b0d7af401fec', 'hex'), Buffer.from('0873c6ba879ce87f5c207a4382b273cac164361af0b9fe63d6d7b0d7af401fec', 'hex')], + hashType: new BN('1', 10), + encryptToAddress: SaplingPaymentAddress.fromAddressString( + 'zs1wczplx4kegw32h8g0f7xwl57p5tvnprwdmnzmdnsw50chcl26f7tws92wk2ap03ykaq6jyyztfa' + ), + createMMR: true, + signature: Buffer.from('AeNjMwABQSAPBEuajDkRyy+OBJsWmDP3EUoqN9UjCJK9nmoSQiNoZWBK19OgGCYdEqr1CiFfBf8SFHVoUv4r2tb5Q3qsMTrp', 'base64'), + dataType: DATA_TYPE_MMRDATA, + data: mmrData, // This is the PartialMMRData object + } + + const signdatamap = new Map(); + signdatamap.set("iBvyi1nuCrTA4g44xN9N7EU1t6a7gwb4h8", new PartialSignData(baseSignDataWithMMR)) + + const requestDetails = new IdentityUpdateRequestDetails({ + requestID: requestID, + systemID: systemID, + identity: partialIdentity, + expiryHeight: expiryHeight, + signDataMap: signdatamap + }); + + const unsignedSigData: VerifiableSignatureDataInterface = { + systemID: CompactIAddressObject.fromAddress(systemID.toAddress()!), + identityID: CompactIAddressObject.fromAddress(systemID.toAddress()!) + } + + const req = new GenericRequest({ + createdAt: createdAt, + salt, + encryptResponseToAddress: SaplingPaymentAddress.fromAddressString("zs1wczplx4kegw32h8g0f7xwl57p5tvnprwdmnzmdnsw50chcl26f7tws92wk2ap03ykaq6jyyztfa"), + details: [ + new IdentityUpdateRequestOrdinalVDXFObject({ data: requestDetails }) + ], + signature: new VerifiableSignatureData(unsignedSigData) + }); + + const height = 18167; + + req.setSigned(); + + const preSigHash = req.getDetailsIdentitySignatureHash(height); + + req.signature!.signatureAsVch = Buffer.from("AgX3RgAAAUEgrnmmyGip2lFhWM0pA2zDifZnAX+ZhPhFEzhhQuPOzr8vLYDpa1PzJNMmMm4dKOfwTdohSFeIPE3SCPR99cZ1vg==", 'base64'); + + const postSigHash = req.getDetailsIdentitySignatureHash(height); + + expect(preSigHash.toString('hex')).toBe(postSigHash.toString('hex')); + }); + + it('toString / fromQrString consistency', () => { + const detail = new GeneralTypeOrdinalVDXFObject({ + data: Buffer.from('feed', 'hex'), + key: DEFAULT_VERUS_CHAINID + }); + const req = new GenericRequest({ details: [detail] }); + + const str = req.toString(); + const buf = base64url.toBuffer(str); + const parsed = new GenericRequest(); + parsed.fromBuffer(buf, 0); + expect(parsed.details[0].toJson()).toEqual(detail.toJson()); + }); + + it('deeplink URI round trip', () => { + const detail = new GeneralTypeOrdinalVDXFObject({ + data: Buffer.from('face', 'hex'), + key: DEFAULT_VERUS_CHAINID + }); + const req = new GenericRequest({ details: [detail] }); + const uri = req.toWalletDeeplinkUri(); + + expect(uri).toContain(`${DEEPLINK_PROTOCOL_URL_STRING}://${DEEPLINK_PROTOCOL_URL_CURRENT_VERSION}/`); + + const parsed = GenericRequest.fromWalletDeeplinkUri(uri); + expect(parsed.version.toString()).toEqual(req.version.toString()); + expect(parsed.details[0].toJson()).toEqual(detail.toJson()); + expect(parsed.toBuffer().toString('hex')).toEqual(req.toBuffer().toString('hex')); + }); + + it('fromQrString should parse correctly', () => { + const detail = new GeneralTypeOrdinalVDXFObject({ + data: Buffer.from('bead', 'hex'), + key: DEFAULT_VERUS_CHAINID + }); + const req = new GenericRequest({ details: [detail] }); + const qr = req.toQrString(); + const parsed = GenericRequest.fromQrString(qr); + expect(parsed.details[0].toJson()).toEqual(detail.toJson()); + expect(parsed.toBuffer().toString('hex')).toEqual(req.toBuffer().toString('hex')); + }); + + it('fromBuffer with empty buffer should throw', () => { + const empty = Buffer.alloc(0); + const req = new GenericRequest(); + expect(() => { + req.fromBuffer(empty, 0); + }).toThrow("Cannot create request from empty buffer"); + }); +}); \ No newline at end of file diff --git a/src/__tests__/vdxf/genericresponse.test.ts b/src/__tests__/vdxf/genericresponse.test.ts new file mode 100644 index 00000000..fad9e21f --- /dev/null +++ b/src/__tests__/vdxf/genericresponse.test.ts @@ -0,0 +1,217 @@ +import { BN } from 'bn.js'; +import base64url from 'base64url'; +import { DEFAULT_VERUS_CHAINID, HASH_TYPE_SHA256, NULL_I_ADDR } from '../../constants/pbaas'; +import { GenericResponse, IdentityID, IdentityUpdateResponseDetails } from '../../'; +import { createHash } from 'crypto'; +import { VerifiableSignatureData, VerifiableSignatureDataInterface } from '../../vdxf/classes/VerifiableSignatureData'; +import { CompactIAddressObject } from '../../vdxf/classes/CompactAddressObject'; +import { GeneralTypeOrdinalVDXFObject, IdentityUpdateResponseOrdinalVDXFObject } from '../../vdxf/classes/ordinals'; +import { TEST_TXID } from '../constants/fixtures'; + +describe('GenericResponse — buffer / URI / QR operations', () => { + function roundTripBuffer(req: GenericResponse): GenericResponse { + const buf = req.toBuffer(); + const clone = new GenericResponse(); + clone.fromBuffer(buf, 0); + + return clone; + } + + function rawDetailsSha256(req: GenericResponse): Buffer { + // replicate the same behavior as getRawDetailsSha256() + const buf = req['toBufferOptionalSig'](false); // call internal method + return createHash("sha256").update(buf).digest(); + } + + it('round trips with a single detail (no signature / createdAt)', () => { + const detail = new GeneralTypeOrdinalVDXFObject({ + data: Buffer.from('cafebabe', 'hex'), + key: DEFAULT_VERUS_CHAINID + }); + const req = new GenericResponse({ details: [detail] }); + + expect(req.hasMultiDetails()).toBe(false); + expect(req.hasCreatedAt()).toBe(false); + expect(req.isSigned()).toBe(false); + + const round = roundTripBuffer(req); + expect(round.version.toString()).toEqual(req.version.toString()); + expect(round.flags.toString()).toEqual(req.flags.toString()); + expect(round.details.length).toBe(1); + const d2 = round.getDetails(0); + expect(d2).toBeInstanceOf(GeneralTypeOrdinalVDXFObject); + expect((d2 as GeneralTypeOrdinalVDXFObject).data).toEqual(detail.data); + expect((d2 as GeneralTypeOrdinalVDXFObject).key).toEqual(detail.key); + expect(round.toBuffer().toString('hex')).toEqual(req.toBuffer().toString('hex')); + }); + + it('round trips with multiple details', () => { + const d1 = new GeneralTypeOrdinalVDXFObject({ + data: Buffer.from('aa', 'hex'), + key: DEFAULT_VERUS_CHAINID + }); + const d2 = new GeneralTypeOrdinalVDXFObject({ + data: Buffer.from('bb', 'hex'), + key: DEFAULT_VERUS_CHAINID + }); + const req = new GenericResponse({ details: [d1, d2] }); + expect(req.hasMultiDetails()).toBe(true); + + const round = roundTripBuffer(req); + expect(round.details.length).toBe(2); + expect((round.getDetails(0) as GeneralTypeOrdinalVDXFObject).data).toEqual(d1.data); + expect((round.getDetails(1) as GeneralTypeOrdinalVDXFObject).data).toEqual(d2.data); + expect(round.toBuffer().toString('hex')).toEqual(req.toBuffer().toString('hex')); + }); + + it('round trips with createdAt, signature, requestID, and requestHash/requestHashType', () => { + const sig = new VerifiableSignatureData({ + flags: new BN(0), + version: new BN(1), + systemID: CompactIAddressObject.fromAddress(DEFAULT_VERUS_CHAINID), + hashType: HASH_TYPE_SHA256, + identityID: CompactIAddressObject.fromAddress(DEFAULT_VERUS_CHAINID), + signatureAsVch: Buffer.from('abcd', 'hex'), + vdxfKeys: [DEFAULT_VERUS_CHAINID, DEFAULT_VERUS_CHAINID], + vdxfKeyNames: ["VRSC", "VRSC"], + boundHashes: [Buffer.from('abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd', 'hex')], + statements: [Buffer.from('1234123412341234123412341234123412341234123412341234123412341234', 'hex')] + }); + + const detail = new GeneralTypeOrdinalVDXFObject({ + data: Buffer.from('abcd', 'hex'), + key: DEFAULT_VERUS_CHAINID + }); + + const createdAt = new BN(9999); + const requestHash = Buffer.from('abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd', 'hex'); + const requestHashType = HASH_TYPE_SHA256; + + const req = new GenericResponse({ + details: [detail], + requestID: CompactIAddressObject.fromAddress(NULL_I_ADDR), + signature: sig, + createdAt, + requestHash: requestHash, + requestHashType: requestHashType + }); + + expect(req.isSigned()).toBe(true); + expect(req.hasCreatedAt()).toBe(true); + + const round = roundTripBuffer(req); + expect(round.signature).toBeDefined(); + expect(round.createdAt?.toString()).toEqual(createdAt.toString()); + expect(round.hasRequestHash()).toBe(true) + expect(round.requestHash?.toString('hex')).toBe(requestHash.toString('hex')) + expect(round.requestHashType?.toNumber()).toBe(requestHashType.toNumber()) + expect(round.requestID?.toAddress()).toBe(NULL_I_ADDR) + const d2 = round.getDetails(0); + expect((d2 as GeneralTypeOrdinalVDXFObject).data).toEqual(detail.data); + expect(round.toBuffer().toString('hex')).toEqual(req.toBuffer().toString('hex')); + }); + + it('round trips with createdAt, and valid signature that can be hashed', () => { + const sig = new VerifiableSignatureData({ + systemID: CompactIAddressObject.fromAddress(DEFAULT_VERUS_CHAINID), + identityID: CompactIAddressObject.fromAddress(DEFAULT_VERUS_CHAINID), + signatureAsVch: Buffer.from('AgX3RgAAAUEgHAVIHuui1Sc9oLxLbglKvmrv47JJLiM0/RBQwzYL1dlamI/2o9qBc93d79laLXWMhQomqZ4U3Mlr3ueuwl4JFA==', 'base64'), + }); + + const detail = new GeneralTypeOrdinalVDXFObject({ + data: Buffer.from('abcd', 'hex'), + key: DEFAULT_VERUS_CHAINID + }); + + const createdAt = new BN(9999); + const requestHash = Buffer.from('abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd', 'hex'); + const requestHashType = HASH_TYPE_SHA256; + + const req = new GenericResponse({ + details: [detail], + signature: sig, + createdAt, + requestHash: requestHash, + requestHashType: requestHashType + }); + + expect(req.isSigned()).toBe(true); + expect(req.hasCreatedAt()).toBe(true); + expect(req.getDetailsIdentitySignatureHash(1000)).toBeDefined(); + expect(req.signature?.signatureVersion.toString()).toBe("2"); + + const round = roundTripBuffer(req); + expect(round.signature).toBeDefined(); + expect(round.createdAt?.toString()).toEqual(createdAt.toString()); + expect(round.hasRequestHash()).toBe(true) + expect(round.requestHash?.toString('hex')).toBe(requestHash.toString('hex')) + expect(round.requestHashType?.toNumber()).toBe(requestHashType.toNumber()) + const d2 = round.getDetails(0); + expect((d2 as GeneralTypeOrdinalVDXFObject).data).toEqual(detail.data); + expect(round.toBuffer().toString('hex')).toEqual(req.toBuffer().toString('hex')); + }); + + it('same hash before/after signature', () => { + const contentmap = new Map(); + contentmap.set("iPsFBfFoCcxtuZNzE8yxPQhXVn4dmytf8j", Buffer.alloc(32)); + contentmap.set("iK7a5JNJnbeuYWVHCDRpJosj3irGJ5Qa8c", Buffer.alloc(32)); + + const systemID = IdentityID.fromAddress("iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq"); + const requestID = "iPsFBfFoCcxtuZNzE8yxPQhXVn4dmytf8j" + const createdAt = new BN("1700000000", 10); + const salt = Buffer.from('=H319X:)@H2Z'); + + const responseDetails = new IdentityUpdateResponseDetails({ + requestID: requestID, + txid: Buffer.from(TEST_TXID, 'hex') + }); + + const unsignedSigData: VerifiableSignatureDataInterface = { + systemID: CompactIAddressObject.fromAddress(systemID.toAddress()!), + identityID: CompactIAddressObject.fromAddress(systemID.toAddress()!) + } + + const req = new GenericResponse({ + createdAt: createdAt, + salt, + details: [ + new IdentityUpdateResponseOrdinalVDXFObject({ data: responseDetails }) + ], + signature: new VerifiableSignatureData(unsignedSigData) + }); + + const height = 18167; + + req.setSigned(); + + const preSigHash = req.getDetailsIdentitySignatureHash(height); + + req.signature!.signatureAsVch = Buffer.from("AgX3RgAAAUEgrnmmyGip2lFhWM0pA2zDifZnAX+ZhPhFEzhhQuPOzr8vLYDpa1PzJNMmMm4dKOfwTdohSFeIPE3SCPR99cZ1vg==", 'base64'); + + const postSigHash = req.getDetailsIdentitySignatureHash(height); + + expect(preSigHash.toString('hex')).toBe(postSigHash.toString('hex')); + }); + + it('toString / fromQrString consistency', () => { + const detail = new GeneralTypeOrdinalVDXFObject({ + data: Buffer.from('feed', 'hex'), + key: DEFAULT_VERUS_CHAINID + }); + const req = new GenericResponse({ details: [detail] }); + + const str = req.toString(); + const buf = base64url.toBuffer(str); + const parsed = new GenericResponse(); + parsed.fromBuffer(buf, 0); + expect(parsed.details[0].toJson()).toEqual(detail.toJson()); + }); + + it('fromBuffer with empty buffer should throw', () => { + const empty = Buffer.alloc(0); + const req = new GenericResponse(); + expect(() => { + req.fromBuffer(empty, 0); + }).toThrow("Cannot create response from empty buffer"); + }); +}); \ No newline at end of file diff --git a/src/__tests__/vdxf/identityupdateenvelope.test.ts b/src/__tests__/vdxf/identityupdateenvelope.test.ts index 6bfdab3c..9980e97a 100644 --- a/src/__tests__/vdxf/identityupdateenvelope.test.ts +++ b/src/__tests__/vdxf/identityupdateenvelope.test.ts @@ -1,139 +1,28 @@ -import { BN } from "bn.js"; -import { IdentityUpdateRequest, IdentityUpdateResponse, IdentityUpdateEnvelope } from "../../vdxf/classes/identity/IdentityUpdateEnvelope"; import { IdentityUpdateRequestDetails } from "../../vdxf/classes/identity/IdentityUpdateRequestDetails"; import { IdentityUpdateResponseDetails } from "../../vdxf/classes/identity/IdentityUpdateResponseDetails"; -import { ContentMultiMap, IDENTITY_VERSION_PBAAS, IdentityID, KeyID, SaplingPaymentAddress } from "../../pbaas"; -import { PartialIdentity } from "../../pbaas/PartialIdentity"; -import { ResponseUri } from "../../vdxf/classes/ResponseUri"; -import { PartialMMRData } from "../../pbaas/PartialMMRData"; -import { PartialSignData, PartialSignDataInitData } from "../../pbaas/PartialSignData"; -import { DATA_TYPE_MMRDATA } from "../../constants/pbaas"; - -describe("IdentityUpdateEnvelope Serialization", () => { - const systemID = IdentityID.fromAddress("iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq"); - const signingID = IdentityID.fromAddress("iPsFBfFoCcxtuZNzE8yxPQhXVn4dmytf8j"); - const requestID = new BN("123456", 10); - const createdAt = new BN("1700000000", 10); - const expiryHeight = new BN("123456"); - const salt = Buffer.from('=H319X:)@H2Z'); - const txid = "2474d2c7b3586cedd8bf7f4a9af7c26e794ea2fc44853f17a30148e2ed857a95"; - - const contentmap = new Map(); - contentmap.set("iPsFBfFoCcxtuZNzE8yxPQhXVn4dmytf8j", Buffer.alloc(32)); - contentmap.set("iK7a5JNJnbeuYWVHCDRpJosj3irGJ5Qa8c", Buffer.alloc(32)); - - const cliIdUpdateRequestJson = { - "name": "data", - "contentmultimap": { - "i5CXAPoCLothTntExgvc5kK38u2wyHtFCg": { - "data": {"createmmr":true, "mmrdata":[{"message": "{\"rail_transport\": 43326.71, \"public_bus_transport\": 83452.4, \"air_transport\": 1306.83, \"urban_public_transport\": -1, \"time\": 993945600}", "mimetype": "application/json", "label": "quarter_3_2001_transport_passenger_data_cz"}]} - } - } - } - - const cliIdUpdateRequestJsonHex = { - "name":"[32][32]", - "parent":"iF6hHpRXpmhLq77eksQzqQrWuminKtzmxT", - "contentmultimap": { - "i4d7U1aZhmoxZbWx8AVezh6z1YewAnuw3V": [ - { - "i4GC1YGEVD21afWudGoFJVdnfjJ5XWnCQv": { - "version": 1, - "flags": 32, - "label": "i3bgiLuaxTr6smF8q6xLG4jvvhF1mmrkM2", - "objectdata": { - "serializedhex": "08a2ebb2c55f83a8e2a426a53320ed4d42124f4d010c012001010776657273696f6e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d011d01600a656d706c6f796d656e7404747970650a746578742f706c61696e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d011d016009446576656c6f706572057469746c650a746578742f706c61696e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d0157016044426f6479206f6620636c61696d20676f657320686572652c207768617420796f75206861766520646f6e652c207768617420796f7520686176652061636869657665642e04626f64790a746578742f706c61696e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d011d016009323031392d323032300564617465730a746578742f706c61696e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d011f01600a323032352d30312d3330066973737565640a746578742f706c61696e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d012f012020cc2b8109fb5566cf98297aaf5c80e2fb0a5051c3252a7957b13ba5433767e23a0b7265666572656e63654944" - } - } - }, - { - "i4GC1YGEVD21afWudGoFJVdnfjJ5XWnCQv": { - "version": 1, - "flags": 32, - "label": "i3bgiLuaxTr6smF8q6xLG4jvvhF1mmrkM2", - "objectdata": { - "serializedhex": "08a2ebb2c55f83a8e2a426a53320ed4d42124f4d010c012001010776657273696f6e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d011d01600a656d706c6f796d656e7404747970650a746578742f706c61696e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d012301600f436869656620446576656c6f706572057469746c650a746578742f706c61696e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d0157016044426f6479206f6620636c61696d20676f657320686572652c207768617420796f75206861766520646f6e652c207768617420796f7520686176652061636869657665642e04626f64790a746578742f706c61696e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d011d016009323032312d323032340564617465730a746578742f706c61696e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d011f01600a323032352d30312d3239066973737565640a746578742f706c61696e08a2ebb2c55f83a8e2a426a53320ed4d42124f4d015a016040373962343830376333303465383035333831666438653165376234383865353062363032613033333366663266663633636264313564363362366163383835650b7265666572656e636549440a746578742f706c61696e" - } - } - } - ] - } - } - - const partialIdentity = new PartialIdentity({ - flags: new BN("0"), - version: IDENTITY_VERSION_PBAAS, - min_sigs: new BN(1), - primary_addresses: [ - KeyID.fromAddress("RQVsJRf98iq8YmRQdehzRcbLGHEx6YfjdH"), - KeyID.fromAddress("RP4Qct9197i5vrS11qHVtdyRRoAHVNJS47") - ], - parent: IdentityID.fromAddress("iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq"), - system_id: IdentityID.fromAddress("iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq"), - name: "TestID", - content_map: contentmap, - content_multimap: ContentMultiMap.fromJson({ - iPsFBfFoCcxtuZNzE8yxPQhXVn4dmytf8j: [ - { iK7a5JNJnbeuYWVHCDRpJosj3irGJ5Qa8c: 'Test String 123454321' }, - { iK7a5JNJnbeuYWVHCDRpJosj3irGJ5Qa8c: 'Test String 123454321' }, - { iK7a5JNJnbeuYWVHCDRpJosj3irGJ5Qa8c: 'Test String 123454321' }, - { iK7a5JNJnbeuYWVHCDRpJosj3irGJ5Qa8c: 'Test String 123454321' } - ], - iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq: '6868686868686868686868686868686868686868', - i5v3h9FWVdRFbNHU7DfcpGykQjRaHtMqu7: [ - '6868686868686868686868686868686868686868', - '6868686868686868686868686868686868686868', - '6868686868686868686868686868686868686868' - ], - i81XL8ZpuCo9jmWLv5L5ikdxrGuHrrpQLz: { iK7a5JNJnbeuYWVHCDRpJosj3irGJ5Qa8c: 'Test String 123454321' } - }), - recovery_authority: IdentityID.fromAddress("i81XL8ZpuCo9jmWLv5L5ikdxrGuHrrpQLz"), - revocation_authority: IdentityID.fromAddress("i5v3h9FWVdRFbNHU7DfcpGykQjRaHtMqu7"), - unlock_after: new BN("123456", 10), - private_addresses: [SaplingPaymentAddress.fromAddressString("zs1wczplx4kegw32h8g0f7xwl57p5tvnprwdmnzmdnsw50chcl26f7tws92wk2ap03ykaq6jyyztfa")] - }); - - const mmrData = new PartialMMRData({ - flags: new BN('0', 10), - data: [ - { type: new BN('2', 10), data: Buffer.from('src/__tests__/pbaas/partialmmrdata.test.ts', 'utf-8') }, - { type: new BN('3', 10), data: Buffer.from('Hello test message 12345', 'utf-8') }, - ], - salt: [Buffer.from('=H319X:)@H2Z'), Buffer.from('s*1UHmVr?feI')], - mmrhashtype: new BN('1', 10), // e.g. PartialMMRData.HASH_TYPE_SHA256 - priormmr: [ - Buffer.from('80a28cdff6bd91a2e96a473c234371fd8b67705a8c4956255ce7b8c7bf20470f02381c9a935f06cdf986a7c5facd77625befa11cf9fd4b59857b457394a8af979ab2830087a3b27041b37bc318484175'), - Buffer.from('d97fd4bbd9e88ca0c5822c12d5c9b272b2044722aa48b1c8fde178be6b59ccea509f403d3acd226c16ba3c32f0cb92e2fcaaa02b40d0bc5257e0fbf2e6c3d3d7f1a1df066967b193d131158ba5bef732') - ], - }) - - const baseSignDataWithMMR: PartialSignDataInitData = { - flags: new BN('0', 10), - address: IdentityID.fromAddress('iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq'), - prefixstring: Buffer.from('example prefix', 'utf8'), - vdxfkeys: [IdentityID.fromAddress('i81XL8ZpuCo9jmWLv5L5ikdxrGuHrrpQLz')], - vdxfkeynames: [Buffer.from('VDXFNAME', 'utf8')], - boundhashes: [Buffer.from('0873c6ba879ce87f5c207a4382b273cac164361af0b9fe63d6d7b0d7af401fec', 'hex'), Buffer.from('0873c6ba879ce87f5c207a4382b273cac164361af0b9fe63d6d7b0d7af401fec', 'hex')], - hashtype: new BN('1', 10), - encrypttoaddress: SaplingPaymentAddress.fromAddressString( - 'zs1wczplx4kegw32h8g0f7xwl57p5tvnprwdmnzmdnsw50chcl26f7tws92wk2ap03ykaq6jyyztfa' - ), - createmmr: true, - signature: Buffer.from('AeNjMwABQSAPBEuajDkRyy+OBJsWmDP3EUoqN9UjCJK9nmoSQiNoZWBK19OgGCYdEqr1CiFfBf8SFHVoUv4r2tb5Q3qsMTrp', 'base64'), - datatype: DATA_TYPE_MMRDATA, - data: mmrData, // This is the PartialMMRData object - } - - const signdatamap = new Map(); - signdatamap.set("iBvyi1nuCrTA4g44xN9N7EU1t6a7gwb4h8", new PartialSignData(baseSignDataWithMMR)) - - function testSerialization(instance) { +import { ContentMultiMap } from "../../pbaas"; +import { PartialSignData } from "../../pbaas/PartialSignData"; +import { + TEST_BASE_SIGN_DATA_WITH_MMR_DATA, + TEST_CLI_ID_UPDATE_REQUEST_JSON, + TEST_CLI_ID_UPDATE_REQUEST_JSON_HEX, + TEST_EXPIRYHEIGHT, + TEST_MMR_DATA, + TEST_PARTIAL_IDENTITY, + TEST_REQUESTID, + TEST_SIGNDATA_MAP, + TEST_SYSTEMID, + TEST_TXID +} from "../constants/fixtures"; + +describe("IdentityUpdate request/response details Serialization", () => { + function testSerialization(instance: any) { const fromBufferInstance = new instance.constructor(); fromBufferInstance.fromBuffer(instance.toBuffer()); expect(fromBufferInstance.toBuffer().toString("hex")).toBe(instance.toBuffer().toString("hex")); } - function testJsonSerialization(instance) { + function testJsonSerialization(instance: any) { const json = instance.toJson(); const fromJsonInstance = instance.constructor.fromJson(json); const newJson = fromJsonInstance.toJson(); @@ -149,79 +38,41 @@ describe("IdentityUpdateEnvelope Serialization", () => { expect(fromCLIJsonInstance.toCLIJson()).toEqual(cliJson); } - test("Serialize/Deserialize unsigned IdentityUpdateRequest", () => { + test("Serialize/Deserialize basic IdentityUpdateRequestDetails", () => { const requestDetails = new IdentityUpdateRequestDetails({ - requestid: requestID, - createdat: createdAt, - systemid: systemID, - identity: partialIdentity, - expiryheight: expiryHeight, - salt: salt, - signdatamap + requestID: TEST_REQUESTID, + systemID: TEST_SYSTEMID, + identity: TEST_PARTIAL_IDENTITY, + expiryHeight: TEST_EXPIRYHEIGHT, + signDataMap: TEST_SIGNDATA_MAP }); - const request = new IdentityUpdateRequest({ details: requestDetails }); - testSerialization(request); - testCLIJsonSerialization(request.details as IdentityUpdateRequestDetails); - }); - test("Serialize/Deserialize signed IdentityUpdateRequest", () => { - const requestDetails = new IdentityUpdateRequestDetails({ - requestid: requestID, - createdat: createdAt, - systemid: systemID, - identity: partialIdentity, - expiryheight: expiryHeight, - salt: salt, - signdatamap - }); - const request = new IdentityUpdateRequest({ - details: requestDetails, - systemid: systemID, - signingid: signingID, - signature: "AeNjMwABQSAPBEuajDkRyy+OBJsWmDP3EUoqN9UjCJK9nmoSQiNoZWBK19OgGCYdEqr1CiFfBf8SFHVoUv4r2tb5Q3qsMTrp" - }); - - testSerialization(request); - testCLIJsonSerialization(request.details as IdentityUpdateRequestDetails); + testSerialization(requestDetails); + testCLIJsonSerialization(requestDetails); }); - test("Serialize/Deserialize unsigned IdentityUpdateResponse", () => { - const responseDetails = new IdentityUpdateResponseDetails({ requestid: requestID, createdat: createdAt }); - const response = new IdentityUpdateResponse({ details: responseDetails }); - testSerialization(response); - }); + test("Serialize/Deserialize basic IdentityUpdateResponseDetails", () => { + const responseDetails = new IdentityUpdateResponseDetails({ requestID: TEST_REQUESTID }); - test("Serialize/Deserialize signed IdentityUpdateResponse", () => { - const responseDetails = new IdentityUpdateResponseDetails({ requestid: requestID, createdat: createdAt }); - const response = new IdentityUpdateResponse({ - details: responseDetails, - systemid: systemID, - signingid: signingID, - signature: "AeNjMwABQSAPBEuajDkRyy+OBJsWmDP3EUoqN9UjCJK9nmoSQiNoZWBK19OgGCYdEqr1CiFfBf8SFHVoUv4r2tb5Q3qsMTrp" - }); - testSerialization(response); + testSerialization(responseDetails); }); - test("Remove optional fields from unsigned IdentityUpdateRequest", () => { + test("Remove optional fields from IdentityUpdateRequestDetails", () => { let baseRequestDetailsConfig = { - requestid: requestID, - createdat: createdAt, - systemid: systemID, - identity: partialIdentity, - expiryheight: expiryHeight, - responseuris: [ResponseUri.fromUriString("http:/127.0.0.1:8000", ResponseUri.TYPE_REDIRECT), ResponseUri.fromUriString("http:/127.0.0.1:8000", ResponseUri.TYPE_POST)], - signdatamap: signdatamap, - salt + requestID: TEST_REQUESTID, + systemID: TEST_SYSTEMID, + identity: TEST_PARTIAL_IDENTITY, + expiryHeight: TEST_EXPIRYHEIGHT, + signDataMap: TEST_SIGNDATA_MAP }; - const toRemove = ["expiryheight", "responseuris", "signdatamap", "salt", "systemid"]; + const toRemove = ["expiryHeight", "signDataMap", "systemID"]; for (let i = 0; i < toRemove.length + 1; i++) { const newRequestDetails = new IdentityUpdateRequestDetails({ ...baseRequestDetailsConfig }); - const request = new IdentityUpdateRequest({ details: newRequestDetails }); - testSerialization(request); - testCLIJsonSerialization(request.details as IdentityUpdateRequestDetails); + testSerialization(newRequestDetails); + testCLIJsonSerialization(newRequestDetails as IdentityUpdateRequestDetails); if (i < toRemove.length) { delete baseRequestDetailsConfig[toRemove[i]] @@ -229,17 +80,16 @@ describe("IdentityUpdateEnvelope Serialization", () => { } }); - test("Remove optional fields from IdentityUpdateResponse", () => { - const txidbuf = Buffer.from(txid, 'hex').reverse(); - let baseResponseDetailsConfig = { requestid: requestID, createdat: createdAt, txid: txidbuf, salt }; + test("Remove optional fields from IdentityUpdateResponseDetails", () => { + const txidbuf = Buffer.from(TEST_TXID, 'hex').reverse(); + let baseResponseDetailsConfig = { requestID: TEST_REQUESTID, txid: txidbuf }; - const toRemove = ["txid", "salt"]; + const toRemove = ["txid"]; for (let i = 0; i < toRemove.length + 1; i++) { const newResponseDetails = new IdentityUpdateResponseDetails({ ...baseResponseDetailsConfig }); - const response = new IdentityUpdateResponse({ details: newResponseDetails }); - testSerialization(response); + testSerialization(newResponseDetails); if (i < toRemove.length) { delete baseResponseDetailsConfig[toRemove[i]] @@ -247,78 +97,36 @@ describe("IdentityUpdateEnvelope Serialization", () => { } }); - test("Serialize/Deserialize IdentityUpdateRequest to/from JSON", () => { - const requestDetails = new IdentityUpdateRequestDetails({ - requestid: requestID, - createdat: createdAt, - systemid: systemID, - identity: partialIdentity, - expiryheight: expiryHeight, - salt: salt, - signdatamap - }); - - const request = new IdentityUpdateRequest({ details: requestDetails }); - testJsonSerialization(request); - testCLIJsonSerialization(request.details as IdentityUpdateRequestDetails); - }); - - test("Serialize/Deserialize signed IdentityUpdateRequest to/from JSON", () => { + test("Serialize/Deserialize IdentityUpdateRequestDetails to/from JSON", () => { const requestDetails = new IdentityUpdateRequestDetails({ - requestid: requestID, - createdat: createdAt, - systemid: systemID, - identity: partialIdentity, - expiryheight: expiryHeight, - salt: salt, - signdatamap + requestID: TEST_REQUESTID, + systemID: TEST_SYSTEMID, + identity: TEST_PARTIAL_IDENTITY, + expiryHeight: TEST_EXPIRYHEIGHT, + signDataMap: TEST_SIGNDATA_MAP }); - const request = new IdentityUpdateRequest({ - details: requestDetails, - systemid: systemID, - signingid: signingID, - signature: "AeNjMwABQSAPBEuajDkRyy+OBJsWmDP3EUoqN9UjCJK9nmoSQiNoZWBK19OgGCYdEqr1CiFfBf8SFHVoUv4r2tb5Q3qsMTrp" - }); - - testJsonSerialization(request); - testCLIJsonSerialization(request.details as IdentityUpdateRequestDetails); + testJsonSerialization(requestDetails); + testCLIJsonSerialization(requestDetails); }); - test("Serialize/Deserialize IdentityUpdateResponse to/from JSON", () => { - const txidbuf = Buffer.from(txid, 'hex').reverse(); - let baseResponseDetailsConfig = { requestid: requestID, createdat: createdAt, txid: txidbuf, salt }; - - const responseDetails = new IdentityUpdateResponseDetails(baseResponseDetailsConfig); - const response = new IdentityUpdateResponse({ details: responseDetails }); - testJsonSerialization(response); - }); + test("Serialize/Deserialize IdentityUpdateResponseDetails to/from JSON", () => { + const txidbuf = Buffer.from(TEST_TXID, 'hex').reverse(); - test("Serialize/Deserialize signed IdentityUpdateResponse to/from JSON", () => { - const txidbuf = Buffer.from(txid, 'hex').reverse(); - let baseResponseDetailsConfig = { requestid: requestID, createdat: createdAt, txid: txidbuf, salt }; + let baseResponseDetailsConfig = { requestID: TEST_REQUESTID, txid: txidbuf }; const responseDetails = new IdentityUpdateResponseDetails(baseResponseDetailsConfig); - const response = new IdentityUpdateResponse({ - details: responseDetails, - systemid: systemID, - signingid: signingID, - signature: "AeNjMwABQSAPBEuajDkRyy+OBJsWmDP3EUoqN9UjCJK9nmoSQiNoZWBK19OgGCYdEqr1CiFfBf8SFHVoUv4r2tb5Q3qsMTrp" - }); - - testJsonSerialization(response); + testJsonSerialization(responseDetails); }); test("Serialize/Deserialize IdentityUpdateRequestDetails to/from JSON", () => { const requestDetails = new IdentityUpdateRequestDetails({ - requestid: requestID, - createdat: createdAt, - systemid: systemID, - identity: partialIdentity, - expiryheight: expiryHeight, - salt: salt, - signdatamap + requestID: TEST_REQUESTID, + systemID: TEST_SYSTEMID, + identity: TEST_PARTIAL_IDENTITY, + expiryHeight: TEST_EXPIRYHEIGHT, + signDataMap: TEST_SIGNDATA_MAP }); testJsonSerialization(requestDetails); @@ -327,31 +135,24 @@ describe("IdentityUpdateEnvelope Serialization", () => { test("Serialize/Deserialize IdentityUpdateResponseDetails to/from JSON", () => { const responseDetails = new IdentityUpdateResponseDetails({ - requestid: requestID, - createdat: createdAt, - txid: Buffer.from(txid, 'hex').reverse(), - salt + requestID: TEST_REQUESTID, + txid: Buffer.from(TEST_TXID, 'hex').reverse() }); testJsonSerialization(responseDetails); }); test("Serialize/Deserialize PartialIdentity to/from JSON", () => { - testJsonSerialization(partialIdentity); + testJsonSerialization(TEST_PARTIAL_IDENTITY); }); test("Serialize/Deserialize PartialSignData to/from JSON", () => { - const partialSignData = new PartialSignData(baseSignDataWithMMR); + const partialSignData = new PartialSignData(TEST_BASE_SIGN_DATA_WITH_MMR_DATA); testJsonSerialization(partialSignData); }); test("Serialize/Deserialize PartialMMRData to/from JSON", () => { - testJsonSerialization(mmrData); - }); - - test("Serialize/Deserialize ResponseUri to/from JSON", () => { - const responseUri = ResponseUri.fromUriString("http:/127.0.0.1:8000", ResponseUri.TYPE_REDIRECT); - testJsonSerialization(responseUri); + testJsonSerialization(TEST_MMR_DATA); }); test("Serialize/Deserialize ContentMultiMap to/from JSON", () => { @@ -365,57 +166,32 @@ describe("IdentityUpdateEnvelope Serialization", () => { }); test("Deserialize cli identity update details", () => { - const req = IdentityUpdateRequestDetails.fromCLIJson(cliIdUpdateRequestJson); + const req = IdentityUpdateRequestDetails.fromCLIJson(TEST_CLI_ID_UPDATE_REQUEST_JSON); testCLIJsonSerialization(req); }) test("Deserialize cli identity update details", () => { const req = IdentityUpdateRequestDetails.fromCLIJson( - cliIdUpdateRequestJsonHex, + TEST_CLI_ID_UPDATE_REQUEST_JSON_HEX, { - systemid: systemID.toAddress() as string, - requestid: requestID.toString(), - createdat: createdAt.toString(), - expiryheight: expiryHeight.toString(), - responseuris: [ - ResponseUri.fromUriString("http:/127.0.0.1:8000", ResponseUri.TYPE_REDIRECT).toJson(), - ResponseUri.fromUriString("http:/127.0.0.1:8000", ResponseUri.TYPE_POST).toJson() - ], - salt: salt.toString('hex'), - txid + systemid: TEST_SYSTEMID.toAddress() as string, + requestid: TEST_REQUESTID.toString(), + expiryheight: TEST_EXPIRYHEIGHT.toString(), + txid: TEST_TXID } ); - const env = new IdentityUpdateRequest({ - details: req, - signingid: signingID, - systemid: systemID, - signature: "AeNjMwABQSAPBEuajDkRyy+OBJsWmDP3EUoqN9UjCJK9nmoSQiNoZWBK19OgGCYdEqr1CiFfBf8SFHVoUv4r2tb5Q3qsMTrp" - }); - - const envBuf = env.toBuffer(); - - const envFromBuf = new IdentityUpdateRequest(); - envFromBuf.fromBuffer(envBuf); - - expect(JSON.stringify(env.toJson())).toEqual(JSON.stringify(IdentityUpdateRequest.fromWalletDeeplinkUri(env.toWalletDeeplinkUri()).toJson())); testCLIJsonSerialization(req); - testJsonSerialization(env); - testSerialization(env); + testJsonSerialization(req); + testSerialization(req); }) test("Deserialize cli identity update details", () => { const detailsProps = { - requestid: requestID.toString(), - createdat: createdAt.toString(), - expiryheight: expiryHeight.toString(), - responseuris: [ - ResponseUri.fromUriString("http:/127.0.0.1:8000", ResponseUri.TYPE_REDIRECT).toJson(), - ResponseUri.fromUriString("http:/127.0.0.1:8000", ResponseUri.TYPE_POST).toJson() - ], - salt: salt.toString('hex'), - txid + requestID: TEST_REQUESTID.toString(), + expiryHeight: TEST_EXPIRYHEIGHT.toString(), + txid: TEST_TXID }; expect(IdentityUpdateRequestDetails.fromCLIJson( diff --git a/src/__tests__/vdxf/ordinalvdxfobject.test.ts b/src/__tests__/vdxf/ordinalvdxfobject.test.ts new file mode 100644 index 00000000..5da6851b --- /dev/null +++ b/src/__tests__/vdxf/ordinalvdxfobject.test.ts @@ -0,0 +1,612 @@ +import { BN } from 'bn.js'; +import { + AppEncryptionRequestOrdinalVDXFObject, + GeneralTypeOrdinalVDXFObject, + getOrdinalVDXFObjectClassForType, + IdentityUpdateRequestOrdinalVDXFObject, + IdentityUpdateResponseOrdinalVDXFObject, + AuthenticationRequestOrdinalVDXFObject, + AuthenticationResponseOrdinalVDXFObject, + OrdinalVDXFObject, + UserDataRequestOrdinalVDXFObject, + UserSpecificDataPacketDetailsOrdinalVDXFObject, + DataPacketResponseOrdinalVDXFObject +} from '../../vdxf/classes/ordinals'; +import { + DataDescriptorOrdinalVDXFObject +} from '../../vdxf/classes/ordinals/DataDescriptorOrdinalVDXFObject'; +import { DataDescriptor, DEST_PKH, SaplingPaymentAddress, TransferDestination } from '../../pbaas'; +import { + AppEncryptionRequestDetails, + CompactAddressObject, + IdentityUpdateRequestDetails, + IdentityUpdateResponseDetails, + AuthenticationRequestDetails, + AuthenticationResponseDetails, + ProvisionIdentityDetails, + VerusPayInvoiceDetails, + UserDataRequestDetails, + UserSpecificDataPacketDetails, + AppEncryptionResponseOrdinalVDXFObject, + AppEncryptionResponseDetails, + CompactIAddressObject +} from '../../vdxf/classes'; +import { DEFAULT_VERUS_CHAINID } from '../../constants/pbaas'; +import { fromBase58Check } from '../../utils/address'; +import { VDXF_OBJECT_RESERVED_BYTE_I_ADDR, VDXF_ORDINAL_APP_ENCRYPTION_REQUEST, VDXF_ORDINAL_APP_ENCRYPTION_RESPONSE, VDXF_ORDINAL_DATA_DESCRIPTOR, VDXF_ORDINAL_IDENTITY_UPDATE_REQUEST, VDXF_ORDINAL_IDENTITY_UPDATE_RESPONSE, VDXF_ORDINAL_AUTHENTICATION_REQUEST, VDXF_ORDINAL_PROVISION_IDENTITY_DETAILS, VDXF_ORDINAL_VERUSPAY_INVOICE, VDXF_OBJECT_RESERVED_BYTE_VDXF_ID_STRING, VDXF_OBJECT_RESERVED_BYTE_ID_OR_CURRENCY } from '../../constants/ordinals/ordinals'; +import { VerusPayInvoiceOrdinalVDXFObject } from '../../vdxf/classes/ordinals/VerusPayInvoiceOrdinalVDXFObject'; +import { TEST_CHALLENGE_ID, TEST_CLI_ID_UPDATE_REQUEST_JSON_HEX, TEST_EXPIRYHEIGHT, TEST_IDENTITY_ID_1, TEST_IDENTITY_ID_2, TEST_IDENTITY_ID_3, TEST_REQUESTID, TEST_SYSTEMID, TEST_TXID } from '../constants/fixtures'; +import { ProvisionIdentityDetailsOrdinalVDXFObject } from '../../vdxf/classes/ordinals/ProvisionIdentityDetailsOrdinalVDXFObject'; +import { BigNumber } from '../../utils/types/BigNumber'; +import { DataPacketResponse } from '../../vdxf/classes/datapacket/DataPacketResponse'; +import { VerifiableSignatureData } from '../../vdxf/classes/VerifiableSignatureData'; +import { SaplingExtendedSpendingKey } from '../../pbaas/SaplingExtendedSpendingKey'; +import { SaplingExtendedViewingKey } from '../../pbaas/SaplingExtendedViewingKey'; +import { VERUSPAY_INVOICE_DETAILS_VDXF_KEY } from '../../vdxf'; + +// Helper function to create TransferDestination from address string +function createCompactAddressObject(type: BigNumber, address: string): CompactIAddressObject { + const obj = new CompactIAddressObject({ + type, + address + }); + + return obj; +} + +describe('OrdinalVDXFObject and subclasses round-trip serialization', () => { + function roundTripBuffer(obj: T): T { + const buf = obj.toBuffer(); + // Use the factory createFromBuffer so the correct subclass is used + const { obj: parsed } = OrdinalVDXFObject.createFromBuffer(buf); + + // Type assertion + const parsedTyped = parsed as T; + + expect(parsedTyped.toBuffer().toString('hex')).toBe(buf.toString('hex')); + + return parsedTyped; + } + + function roundTripJson(obj: T): T { + const json = obj.toJson(); + // Depending on subclass, call static fromJson + let newObj: OrdinalVDXFObject; + if (obj instanceof DataDescriptorOrdinalVDXFObject) { + newObj = DataDescriptorOrdinalVDXFObject.fromJson(json as any); + } else if (obj instanceof VerusPayInvoiceOrdinalVDXFObject) { + newObj = VerusPayInvoiceOrdinalVDXFObject.fromJson(json as any); + } else if (obj instanceof GeneralTypeOrdinalVDXFObject) { + newObj = GeneralTypeOrdinalVDXFObject.fromJson(json); + } else if (obj instanceof IdentityUpdateRequestOrdinalVDXFObject) { + newObj = IdentityUpdateRequestOrdinalVDXFObject.fromJson(json as any); + } else if (obj instanceof IdentityUpdateResponseOrdinalVDXFObject) { + newObj = IdentityUpdateResponseOrdinalVDXFObject.fromJson(json as any); + } else if (obj instanceof AuthenticationRequestOrdinalVDXFObject) { + newObj = AuthenticationRequestOrdinalVDXFObject.fromJson(json as any); + } else if (obj instanceof AuthenticationResponseOrdinalVDXFObject) { + newObj = AuthenticationResponseOrdinalVDXFObject.fromJson(json as any); + } else if (obj instanceof ProvisionIdentityDetailsOrdinalVDXFObject) { + newObj = ProvisionIdentityDetailsOrdinalVDXFObject.fromJson(json as any); + } else if (obj instanceof AppEncryptionRequestOrdinalVDXFObject) { + newObj = AppEncryptionRequestOrdinalVDXFObject.fromJson(json as any); + } else if (obj instanceof DataPacketResponseOrdinalVDXFObject) { + newObj = DataPacketResponseOrdinalVDXFObject.fromJson(json as any); + } else if (obj instanceof UserDataRequestOrdinalVDXFObject) { + newObj = UserDataRequestOrdinalVDXFObject.fromJson(json as any); + } else if (obj instanceof UserSpecificDataPacketDetailsOrdinalVDXFObject) { + newObj = UserSpecificDataPacketDetailsOrdinalVDXFObject.fromJson(json as any); + } else if (obj instanceof AppEncryptionResponseOrdinalVDXFObject) { + newObj = AppEncryptionResponseOrdinalVDXFObject.fromJson(json as any); + } else { + throw new Error("Unrecognized type"); + } + + return newObj as T; + } + + it('should serialize / deserialize a GeneralTypeOrdinalVDXFObject (opaque buffer) via buffer with I address key', () => { + const sample = Buffer.from('deadbeef', 'hex'); + const obj = new GeneralTypeOrdinalVDXFObject({ data: sample, key: VERUSPAY_INVOICE_DETAILS_VDXF_KEY.vdxfid }); + + // check some properties + expect(obj.isDefinedByVdxfKey()).toBe(true); + expect(obj.getIAddressKey()).toBe(VERUSPAY_INVOICE_DETAILS_VDXF_KEY.vdxfid); + expect(obj.data).toEqual(sample); + expect(obj.key).toEqual(VERUSPAY_INVOICE_DETAILS_VDXF_KEY.vdxfid); + + const round = roundTripBuffer(obj); + expect(round).toBeInstanceOf(GeneralTypeOrdinalVDXFObject); + expect((round as GeneralTypeOrdinalVDXFObject).data).toEqual(sample); + expect((round as GeneralTypeOrdinalVDXFObject).getIAddressKey()).toEqual(VERUSPAY_INVOICE_DETAILS_VDXF_KEY.vdxfid); + expect(((round as GeneralTypeOrdinalVDXFObject).key)).toEqual(VERUSPAY_INVOICE_DETAILS_VDXF_KEY.vdxfid); + + // Their JSON should match hex + const j = obj.toJson(); + expect(j.data).toEqual(sample.toString('hex')); + const roundJ = roundTripJson(obj); + expect(roundJ).toBeInstanceOf(GeneralTypeOrdinalVDXFObject); + expect((roundJ as GeneralTypeOrdinalVDXFObject).data).toEqual(sample); + expect((roundJ as GeneralTypeOrdinalVDXFObject).getIAddressKey()).toEqual(VERUSPAY_INVOICE_DETAILS_VDXF_KEY.vdxfid); + expect(((roundJ as GeneralTypeOrdinalVDXFObject).key)).toEqual(VERUSPAY_INVOICE_DETAILS_VDXF_KEY.vdxfid); + }); + + it('should serialize / deserialize a GeneralTypeOrdinalVDXFObject (opaque buffer) via buffer with vdxfkey text key', () => { + const sample = Buffer.from('deadbeef', 'hex'); + const obj = new GeneralTypeOrdinalVDXFObject({ + data: sample, + key: VERUSPAY_INVOICE_DETAILS_VDXF_KEY.qualifiedname.name, + type: VDXF_OBJECT_RESERVED_BYTE_VDXF_ID_STRING + }); + + // check some properties + expect(obj.isDefinedByTextVdxfKey()).toBe(true); + expect(obj.getIAddressKey()).toBe(VERUSPAY_INVOICE_DETAILS_VDXF_KEY.vdxfid); + expect(obj.data).toEqual(sample); + expect(obj.key).toEqual(VERUSPAY_INVOICE_DETAILS_VDXF_KEY.qualifiedname.name); + + const round = roundTripBuffer(obj); + expect(round).toBeInstanceOf(GeneralTypeOrdinalVDXFObject); + expect((round as GeneralTypeOrdinalVDXFObject).data).toEqual(sample); + expect((round as GeneralTypeOrdinalVDXFObject).getIAddressKey()).toEqual(VERUSPAY_INVOICE_DETAILS_VDXF_KEY.vdxfid); + expect(((round as GeneralTypeOrdinalVDXFObject).key)).toEqual(VERUSPAY_INVOICE_DETAILS_VDXF_KEY.qualifiedname.name); + + // Their JSON should match hex + const j = obj.toJson(); + expect(j.data).toEqual(sample.toString('hex')); + const roundJ = roundTripJson(obj); + expect(roundJ).toBeInstanceOf(GeneralTypeOrdinalVDXFObject); + expect((roundJ as GeneralTypeOrdinalVDXFObject).data).toEqual(sample); + expect((roundJ as GeneralTypeOrdinalVDXFObject).getIAddressKey()).toEqual(VERUSPAY_INVOICE_DETAILS_VDXF_KEY.vdxfid); + expect(((roundJ as GeneralTypeOrdinalVDXFObject).key)).toEqual(VERUSPAY_INVOICE_DETAILS_VDXF_KEY.qualifiedname.name); + }); + + it('should serialize / deserialize a GeneralTypeOrdinalVDXFObject (opaque buffer) via buffer with FQN key', () => { + const sample = Buffer.from('deadbeef', 'hex'); + const obj = new GeneralTypeOrdinalVDXFObject({ + data: sample, + key: "service.VRSCTEST", + type: VDXF_OBJECT_RESERVED_BYTE_ID_OR_CURRENCY + }); + + // check some properties + expect(obj.isDefinedByIDOrCurrencyFQN()).toBe(true); + expect(obj.getIAddressKey()).toBe("iFZC7A1HnnJGwBmoPjX3mG37RKbjZZLPhm"); + expect(obj.data).toEqual(sample); + expect(obj.key).toEqual("service.VRSCTEST"); + + const round = roundTripBuffer(obj); + expect(round).toBeInstanceOf(GeneralTypeOrdinalVDXFObject); + expect((round as GeneralTypeOrdinalVDXFObject).data).toEqual(sample); + expect((round as GeneralTypeOrdinalVDXFObject).getIAddressKey()).toEqual("iFZC7A1HnnJGwBmoPjX3mG37RKbjZZLPhm"); + expect(((round as GeneralTypeOrdinalVDXFObject).key)).toEqual("service.VRSCTEST"); + + // Their JSON should match hex + const j = obj.toJson(); + expect(j.data).toEqual(sample.toString('hex')); + const roundJ = roundTripJson(obj); + expect(roundJ).toBeInstanceOf(GeneralTypeOrdinalVDXFObject); + expect((roundJ as GeneralTypeOrdinalVDXFObject).data).toEqual(sample); + expect((roundJ as GeneralTypeOrdinalVDXFObject).getIAddressKey()).toEqual("iFZC7A1HnnJGwBmoPjX3mG37RKbjZZLPhm"); + expect(((roundJ as GeneralTypeOrdinalVDXFObject).key)).toEqual("service.VRSCTEST"); + }); + + it('should serialize / deserialize a DataDescriptorOrdinalVDXFObject via buffer', () => { + // Create a DataDescriptor with some fields + const dd = DataDescriptor.fromJson({ + version: 1, + "flags": 2, + "objectdata": { + "i4GC1YGEVD21afWudGoFJVdnfjJ5XWnCQv": { + "version": 1, + "flags": 96, + "mimetype": "text/plain", + "objectdata": { + "message": "Something 1" + }, + "label": "label 1" + } + }, + "salt": "4f66603f256d3f757b6dc3ea44802d4041d2a1901e06005028fd60b85a5878a2" + }); + + // Force flags, etc. + dd.SetFlags(); + + const obj = new DataDescriptorOrdinalVDXFObject({ data: dd }); + + const round = roundTripBuffer(obj); + expect(round).toBeInstanceOf(DataDescriptorOrdinalVDXFObject); + const dd2 = (round as DataDescriptorOrdinalVDXFObject).data; + expect(dd2.version.toString()).toEqual(dd.version.toString()); + expect(dd2.flags.toString()).toEqual(dd.flags.toString()); + expect(dd2.objectdata).toEqual(dd.objectdata); + expect(dd2.label).toEqual(dd.label); + expect(dd2.mimeType).toEqual(dd.mimeType); + + // Now JSON round trip + const json = obj.toJson(); + + // The JSON data field should be the DataDescriptor JSON + expect(json.data).toBeDefined(); + const roundJ = roundTripJson(obj); + expect(roundJ).toBeInstanceOf(DataDescriptorOrdinalVDXFObject); + const dd3 = (roundJ as DataDescriptorOrdinalVDXFObject).data; + expect(dd3.version.toString()).toBe(dd.version.toString()); + expect(dd3.flags.toString()).toBe(dd.flags.toString()); + expect(dd3.objectdata).toEqual(dd.objectdata); + expect(dd3.label).toBe(dd.label); + expect(dd3.mimeType).toBe(dd.mimeType); + }); + + it('should serialize / deserialize a VerusPayInvoiceOrdinalVDXFObject via buffer', () => { + // Create a VerusPayInvoiceDetails with some fields + const details = new VerusPayInvoiceDetails({ + amount: new BN(10000000000, 10), + destination: new TransferDestination({ + type: DEST_PKH, + destination_bytes: fromBase58Check("R9J8E2no2HVjQmzX6Ntes2ShSGcn7WiRcx").hash + }), + requestedcurrencyid: "iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq" + }); + + details.amount = new BN(12345); + details.requestedcurrencyid = DEFAULT_VERUS_CHAINID; + + const obj = new VerusPayInvoiceOrdinalVDXFObject({ data: details }); + + const round = roundTripBuffer(obj); + expect(round).toBeInstanceOf(VerusPayInvoiceOrdinalVDXFObject); + const d2 = (round as VerusPayInvoiceOrdinalVDXFObject).data; + expect(d2.requestedcurrencyid).toEqual(details.requestedcurrencyid); + expect(d2.amount.toString()).toEqual(details.amount.toString()); + + const json = obj.toJson(); + expect(json.data).toBeDefined(); + const roundJ = roundTripJson(obj); + expect(roundJ).toBeInstanceOf(VerusPayInvoiceOrdinalVDXFObject); + const d3 = (roundJ as VerusPayInvoiceOrdinalVDXFObject).data; + expect(d3.requestedcurrencyid).toEqual(details.requestedcurrencyid); + expect(d3.amount.toString()).toEqual(details.amount.toString()); + }); + + it('should serialize / deserialize a IdentityUpdateRequestOrdinalVDXFObject via buffer', () => { + const details = IdentityUpdateRequestDetails.fromCLIJson( + TEST_CLI_ID_UPDATE_REQUEST_JSON_HEX, + { + systemid: TEST_SYSTEMID.toAddress() as string, + requestid: TEST_REQUESTID.toString(), + expiryheight: TEST_EXPIRYHEIGHT.toString(), + txid: TEST_TXID + } + ); + + const obj = new IdentityUpdateRequestOrdinalVDXFObject({ data: details }); + + const round = roundTripBuffer(obj); + expect(round).toBeInstanceOf(IdentityUpdateRequestOrdinalVDXFObject); + + const d2 = (round as IdentityUpdateRequestOrdinalVDXFObject).data; + expect(d2.systemID!.toAddress()).toEqual(details.systemID!.toAddress()); + expect(d2.requestID!.toString()).toEqual(details.requestID!.toString()); + expect(d2.expiryHeight!.toString()).toEqual(details.expiryHeight!.toString()); + expect(d2.txid!.toString('hex')).toEqual(details.txid!.toString('hex')); + + const json = obj.toJson(); + expect(json.data).toBeDefined(); + const roundJ = roundTripJson(obj); + expect(roundJ).toBeInstanceOf(IdentityUpdateRequestOrdinalVDXFObject); + + const d3 = (roundJ as IdentityUpdateRequestOrdinalVDXFObject).data; + expect(d3.systemID!.toAddress()).toEqual(details.systemID!.toAddress()); + expect(d3.requestID!.toString()).toEqual(details.requestID!.toString()); + expect(d3.expiryHeight!.toString()).toEqual(details.expiryHeight!.toString()); + expect(d3.txid!.toString('hex')).toEqual(details.txid!.toString('hex')); + }); + + it('should serialize / deserialize a IdentityUpdateResponseOrdinalVDXFObject via buffer', () => { + const details = new IdentityUpdateResponseDetails({ + requestID: TEST_REQUESTID, + txid: Buffer.from(TEST_TXID, 'hex').reverse() + }); + + const obj = new IdentityUpdateResponseOrdinalVDXFObject({ data: details }); + + const round = roundTripBuffer(obj); + expect(round).toBeInstanceOf(IdentityUpdateResponseOrdinalVDXFObject); + + const d2 = (round as IdentityUpdateResponseOrdinalVDXFObject).data; + expect(d2.requestID!.toString()).toEqual(details.requestID!.toString()); + expect(d2.txid!.toString('hex')).toEqual(details.txid!.toString('hex')); + + const json = obj.toJson(); + expect(json.data).toBeDefined(); + const roundJ = roundTripJson(obj); + expect(roundJ).toBeInstanceOf(IdentityUpdateResponseOrdinalVDXFObject); + + const d3 = (roundJ as IdentityUpdateResponseOrdinalVDXFObject).data; + expect(d3.requestID!.toString()).toEqual(details.requestID!.toString()); + expect(d3.txid!.toString('hex')).toEqual(details.txid!.toString('hex')); + }); + + it('should serialize / deserialize a AuthenticationRequestOrdinalVDXFObject via buffer', () => { + const details = new AuthenticationRequestDetails({ + requestID: CompactIAddressObject.fromAddress(TEST_CHALLENGE_ID, TEST_SYSTEMID.toAddress()!), + recipientConstraints: [ + { type: AuthenticationRequestDetails.REQUIRED_ID, identity: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_I_ADDRESS, address: TEST_IDENTITY_ID_1, rootSystemName: "VRSC" }) }, + { type: AuthenticationRequestDetails.REQUIRED_SYSTEM, identity: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_I_ADDRESS, address: TEST_IDENTITY_ID_2, rootSystemName: "VRSC" }) }, + { type: AuthenticationRequestDetails.REQUIRED_PARENT, identity: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_I_ADDRESS, address: TEST_IDENTITY_ID_3, rootSystemName: "VRSC" }) } + ], + expiryTime: new BN(2938475938457) + }); + + const obj = new AuthenticationRequestOrdinalVDXFObject({ data: details }); + + const round = roundTripBuffer(obj); + expect(round).toBeInstanceOf(AuthenticationRequestOrdinalVDXFObject); + + const d2 = (round as AuthenticationRequestOrdinalVDXFObject).data; + expect(d2.requestID!.toString()).toEqual(details.requestID!.toString()); + expect(d2.expiryTime!.toNumber()).toEqual(details.expiryTime!.toNumber()); + + const json = obj.toJson(); + expect(json.data).toBeDefined(); + const roundJ = roundTripJson(obj); + expect(roundJ).toBeInstanceOf(AuthenticationRequestOrdinalVDXFObject); + + const d3 = (roundJ as AuthenticationRequestOrdinalVDXFObject).data; + expect(d3.requestID!.toString()).toEqual(details.requestID!.toString()); + expect(d3.expiryTime!.toNumber()).toEqual(details.expiryTime!.toNumber()); + }); + + it('should serialize / deserialize a AuthenticationResponseOrdinalVDXFObject via buffer', () => { + const details = new AuthenticationResponseDetails({ + requestID: CompactIAddressObject.fromAddress(TEST_CHALLENGE_ID, TEST_SYSTEMID.toAddress()!) + }); + + const obj = new AuthenticationResponseOrdinalVDXFObject({ data: details }); + + const round = roundTripBuffer(obj); + expect(round).toBeInstanceOf(AuthenticationResponseOrdinalVDXFObject); + + const d2 = (round as AuthenticationResponseOrdinalVDXFObject).data; + expect(d2.requestID!.toString()).toEqual(details.requestID!.toString()); + + const json = obj.toJson(); + expect(json.data).toBeDefined(); + const roundJ = roundTripJson(obj); + expect(roundJ).toBeInstanceOf(AuthenticationResponseOrdinalVDXFObject); + + const d3 = (roundJ as AuthenticationResponseOrdinalVDXFObject).data; + expect(d3.requestID!.toString()).toEqual(details.requestID!.toString()); + }); + + it('should serialize / deserialize a ProvisionIdentityDetailsOrdinalVDXFObject', () => { + const details = new ProvisionIdentityDetails({ + version: new BN(1, 10), + flags: ProvisionIdentityDetails.FLAG_HAS_SYSTEMID.or(ProvisionIdentityDetails.FLAG_HAS_PARENTID), + systemID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_I_ADDRESS, address: TEST_IDENTITY_ID_1, rootSystemName: "VRSC" }), + parentID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_I_ADDRESS, address: TEST_IDENTITY_ID_2, rootSystemName: "VRSC" }) + }); + + const obj = new ProvisionIdentityDetailsOrdinalVDXFObject({ data: details }); + + const round = roundTripBuffer(obj); + expect(round).toBeInstanceOf(ProvisionIdentityDetailsOrdinalVDXFObject); + + const d2 = (round as ProvisionIdentityDetailsOrdinalVDXFObject).data; + expect(d2.systemID!.toIAddress()).toEqual(details.systemID!.toIAddress()); + expect(d2.parentID!.toIAddress()).toEqual(details.parentID!.toIAddress()); + + const json = obj.toJson(); + expect(json.data).toBeDefined(); + const roundJ = roundTripJson(obj); + expect(roundJ).toBeInstanceOf(ProvisionIdentityDetailsOrdinalVDXFObject); + + const d3 = (roundJ as ProvisionIdentityDetailsOrdinalVDXFObject).data; + expect(d3.systemID!.toIAddress()).toEqual(details.systemID!.toIAddress()); + expect(d3.parentID!.toIAddress()).toEqual(details.parentID!.toIAddress()); + }); + + it('should serialize / deserialize an AppEncryptionRequestOrdinalVDXFObject', () => { + const details = new AppEncryptionRequestDetails({ + version: AppEncryptionRequestDetails.DEFAULT_VERSION, + flags: AppEncryptionRequestDetails.HAS_DERIVATION_ID + .or(AppEncryptionRequestDetails.HAS_REQUEST_ID), + encryptToZAddress: "zs1sthrnsx5vmpmdl3pcd0paltcq9jf56hjjzu87shf90mt54y3szde6zaauvxw5sfuqh565arhmh4", + derivationNumber: new BN(42), + derivationID: createCompactAddressObject(CompactAddressObject.TYPE_I_ADDRESS, "i9nwxtKuVYX4MSbeULLiK2ttVi6rUEhh4X"), + requestID: "iD4CrjbJBZmwEZQ4bCWgbHx9tBHGP9mdSQ" + }); + + const obj = new AppEncryptionRequestOrdinalVDXFObject({ data: details }); + + const round = roundTripBuffer(obj); + expect(round).toBeInstanceOf(AppEncryptionRequestOrdinalVDXFObject); + + const d2 = (round as AppEncryptionRequestOrdinalVDXFObject).data; + expect(d2.encryptToZAddress!).toEqual(details.encryptToZAddress); + expect(d2.derivationNumber!.toString()).toEqual(details.derivationNumber!.toString()); + expect(d2.derivationID!.toIAddress()).toEqual(details.derivationID!.toIAddress()); + expect(d2.requestID).toEqual(details.requestID); + + const json = obj.toJson(); + expect(json.data).toBeDefined(); + const roundJ = roundTripJson(obj); + expect(roundJ).toBeInstanceOf(AppEncryptionRequestOrdinalVDXFObject); + + const d3 = (roundJ as AppEncryptionRequestOrdinalVDXFObject).data; + expect(d3.encryptToZAddress!).toEqual(details.encryptToZAddress); + expect(d3.derivationNumber!.toString()).toEqual(details.derivationNumber!.toString()); + expect(d3.derivationID!.toIAddress()).toEqual(details.derivationID!.toIAddress()); + expect(d3.requestID).toEqual(details.requestID); + }); + + it('getOrdinalVDXFObjectClassForType should map to correct classes', () => { + expect(getOrdinalVDXFObjectClassForType(VDXF_ORDINAL_DATA_DESCRIPTOR)) + .toBe(DataDescriptorOrdinalVDXFObject); + expect(getOrdinalVDXFObjectClassForType(VDXF_ORDINAL_VERUSPAY_INVOICE)) + .toBe(VerusPayInvoiceOrdinalVDXFObject); + expect(getOrdinalVDXFObjectClassForType(VDXF_ORDINAL_IDENTITY_UPDATE_REQUEST)) + .toBe(IdentityUpdateRequestOrdinalVDXFObject); + expect(getOrdinalVDXFObjectClassForType(VDXF_ORDINAL_IDENTITY_UPDATE_RESPONSE)) + .toBe(IdentityUpdateResponseOrdinalVDXFObject); + expect(getOrdinalVDXFObjectClassForType(VDXF_OBJECT_RESERVED_BYTE_I_ADDR)) + .toBe(GeneralTypeOrdinalVDXFObject); + expect(getOrdinalVDXFObjectClassForType(VDXF_ORDINAL_AUTHENTICATION_REQUEST)) + .toBe(AuthenticationRequestOrdinalVDXFObject); + expect(getOrdinalVDXFObjectClassForType(VDXF_ORDINAL_PROVISION_IDENTITY_DETAILS)) + .toBe(ProvisionIdentityDetailsOrdinalVDXFObject); + expect(getOrdinalVDXFObjectClassForType(VDXF_ORDINAL_APP_ENCRYPTION_REQUEST)) + .toBe(AppEncryptionRequestOrdinalVDXFObject); + expect(getOrdinalVDXFObjectClassForType(VDXF_ORDINAL_APP_ENCRYPTION_RESPONSE)) + .toBe(AppEncryptionResponseOrdinalVDXFObject); + + // unrecognized + expect(() => getOrdinalVDXFObjectClassForType(new BN(999))).toThrow(); + }); + + it('base OrdinalVDXFObject buffer round trip (no key path)', () => { + // This tests the fallback when no key is provided + const base = new OrdinalVDXFObject({ type: VDXF_ORDINAL_DATA_DESCRIPTOR }); + const buf = base.toBuffer(); + const parsed = new OrdinalVDXFObject(); + parsed.fromBuffer(buf); + + expect(parsed.type.toString()).toBe(base.type.toString()); + expect(parsed.version.toString()).toBe(base.version.toString()); + + // data is undefined or empty + expect(parsed.data).toBeUndefined(); + }); + + it('should serialize / deserialize a DataPacketResponse via buffer', () => { + const details = new DataPacketResponse({ + flags: new BN(0), + requestID: TEST_CHALLENGE_ID, + data: new DataDescriptor({ + version: new BN(1, 10), + "flags": new BN(2, 10), + "objectdata": Buffer.from("deadbeef", "hex"), + "salt": Buffer.from("4f66603f256d3f757b6dc3ea44802d4041d2a1901e06005028fd60b85a5878a2", "hex") + }) + }); + + const obj = new DataPacketResponseOrdinalVDXFObject({ data: details }); + + const round = roundTripBuffer(obj); + expect(round).toBeInstanceOf(DataPacketResponseOrdinalVDXFObject); + + const d2 = (round as DataPacketResponseOrdinalVDXFObject).data; + expect(d2.requestID!.toString()).toEqual(details.requestID!.toString()); + + const json = obj.toJson(); + expect(json.data).toBeDefined(); + const roundJ = roundTripJson(obj); + expect(roundJ).toBeInstanceOf(DataPacketResponseOrdinalVDXFObject); + + const d3 = (roundJ as DataPacketResponseOrdinalVDXFObject).data; + expect(d3.requestID!.toString()).toEqual(details.requestID!.toString()); + }); + + it('should serialize / deserialize a UserDataRequestOrdinalVDXFObject via buffer', () => { + const details = new UserDataRequestDetails({ + version: new BN(1), + flags: UserDataRequestDetails.FULL_DATA.or(UserDataRequestDetails.ATTESTATION).or(UserDataRequestDetails.HAS_SIGNER), + searchDataKey: [{ "iEEjVkvM9Niz4u2WCr6QQzx1zpVSvDFub1": "Attestation Name" }], + signer: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_I_ADDRESS, address: "iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq", rootSystemName: "VRSC" }), + requestID: "iD4CrjbJBZmwEZQ4bCWgbHx9tBHGP9mdSQ" + }); + + const obj = new UserDataRequestOrdinalVDXFObject({ data: details }); + + const round = roundTripBuffer(obj); + expect(round).toBeInstanceOf(UserDataRequestOrdinalVDXFObject); + + const d2 = (round as UserDataRequestOrdinalVDXFObject).data; + expect(d2.requestID!.toString()).toEqual(details.requestID!.toString()); + expect(d2.searchDataKey).toEqual(details.searchDataKey); + expect(d2.signer!.toIAddress()).toEqual(details.signer!.toIAddress()); + + const json = obj.toJson(); + expect(json.data).toBeDefined(); + const roundJ = roundTripJson(obj); + expect(roundJ).toBeInstanceOf(UserDataRequestOrdinalVDXFObject); + + const d3 = (roundJ as UserDataRequestOrdinalVDXFObject).data; + expect(d3.requestID!.toString()).toEqual(details.requestID!.toString()); + expect(d3.searchDataKey).toEqual(details.searchDataKey); + expect(d3.signer!.toIAddress()).toEqual(details.signer!.toIAddress()); + }); + + it('should serialize / deserialize a UserSpecificDataPacketDetailsOrdinalVDXFObject via buffer', () => { + const details = new UserSpecificDataPacketDetails({ + version: new BN(1), + flags: UserSpecificDataPacketDetails.HAS_STATEMENTS.or(UserSpecificDataPacketDetails.HAS_SIGNATURE), + signableObjects: [DataDescriptor.fromJson({ version: new BN(1), label: "123", objectdata: "0011223344aabbcc", flags: DataDescriptor.FLAG_LABEL_PRESENT })], + statements: ["Statement 1", "Statement 2"], + signature: new VerifiableSignatureData({ + version: new BN(1), + signatureAsVch: Buffer.from("efc8d6b60c5b6efaeb3fce4b2c0749c317f2167549ec22b1bee411b8802d5aaf", 'hex'), + hashType: new BN(1), + flags: new BN(0), + identityID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_I_ADDRESS, address: "i7LaXD2cdy1zeh33eHzZaEPyueT4yQmBfW", rootSystemName: "VRSC" }), + systemID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_FQN, address: "VRSC", rootSystemName: "VRSC" }), + }), + detailsID: "iD4CrjbJBZmwEZQ4bCWgbHx9tBHGP9mdSQ" + }); + + const obj = new UserSpecificDataPacketDetailsOrdinalVDXFObject({ data: details }); + + const round = roundTripBuffer(obj); + expect(round).toBeInstanceOf(UserSpecificDataPacketDetailsOrdinalVDXFObject); + + const d2 = (round as UserSpecificDataPacketDetailsOrdinalVDXFObject).data; + expect(d2.detailsID!.toString()).toEqual(details.detailsID!.toString()); + expect(d2.signableObjects.length).toBe(1); + expect(d2.statements?.length).toBe(2); + expect(d2.signature?.signatureAsVch.toString('hex')).toBe("efc8d6b60c5b6efaeb3fce4b2c0749c317f2167549ec22b1bee411b8802d5aaf"); + + const json = obj.toJson(); + expect(json.data).toBeDefined(); + const roundJ = roundTripJson(obj); + expect(roundJ).toBeInstanceOf(UserSpecificDataPacketDetailsOrdinalVDXFObject); + + const d3 = (roundJ as UserSpecificDataPacketDetailsOrdinalVDXFObject).data; + expect(d3.detailsID!.toString()).toEqual(details.detailsID!.toString()); + expect(d3.signableObjects.length).toBe(1); + expect(d3.statements?.length).toBe(2); + expect(d3.signature?.signatureAsVch.toString('hex')).toBe("efc8d6b60c5b6efaeb3fce4b2c0749c317f2167549ec22b1bee411b8802d5aaf"); + }); + + it('should serialize / deserialize an AppEncryptionResponseOrdinalVDXFObject', () => { + + const testViewingKey = 'zxviews1q0njl87fqqqqpq8vghkp6nz9wx48mwelukvhx3yfwg7msatglv4xy8rrh87k9z472edvlrt950qyy6r766dxnpqktxug7t2wy80s4ug325dwp9hf4vw9a6ethf2mwc9wan28p88dq8q2e8sdlw2mhffg6hy92tjyuquz7a8reqdz905x6xt6kqdx5wn7jvas0733hends8q6s8k87emn6m060xdnhgmvn4zmx0ssrwve84lzxkqu2dnfq5qsjwrtlject0an0k282rsnx0kq4'; + const testSpendingKey = 'secret-extended-key-main1q0njl87fqqqqpq8vghkp6nz9wx48mwelukvhx3yfwg7msatglv4xy8rrh87k9z472el95h53ym2tku2dazny0j2vfukgmp6fu3k7edzcx9n8egesc32sdy3xr4s2ep4skgc7t5j5zds4ws7hf2nuszf7ltfn2nc5rk3k77gyeqdz905x6xt6kqdx5wn7jvas0733hends8q6s8k87emn6m060xdnhgmvn4zmx0ssrwve84lzxkqu2dnfq5qsjwrtlject0an0k282rs0gws78'; + const testAddress = 'zs1anxaua04mnl7dz2mjpflhw0mt73uxy9rjac53lgduk02kh3lnf0hxufk9d76j5uep5j55f5h5rk'; + const testIncomingViewingKey = Buffer.from('ba9af283ecfe0552480dd7e1ce9af68a12e64da4927e8011a795cb223f4afc00"', 'hex'); + + const details = new AppEncryptionResponseDetails({ + version: new BN(1), + flags: AppEncryptionResponseDetails.RESPONSE_CONTAINS_REQUEST_ID.or(AppEncryptionResponseDetails.RESPONSE_CONTAINS_EXTENDED_SPENDING_KEY), + requestID: "iD4CrjbJBZmwEZQ4bCWgbHx9tBHGP9mdSQ", + incomingViewingKey: testIncomingViewingKey, + extendedViewingKey: SaplingExtendedViewingKey.fromKeyString(testViewingKey), + extendedSpendingKey: SaplingExtendedSpendingKey.fromKeyString(testSpendingKey), + address: SaplingPaymentAddress.fromAddressString(testAddress) + }); + + const obj = new AppEncryptionResponseOrdinalVDXFObject({ data: details }); + + const round = roundTripBuffer(obj); + expect(round).toBeInstanceOf(AppEncryptionResponseOrdinalVDXFObject); + + const d2 = (round as AppEncryptionResponseOrdinalVDXFObject).data; + expect(d2.incomingViewingKey.toString('hex')).toEqual(testIncomingViewingKey.toString('hex')); + expect(d2.requestID!.toString()).toEqual(details.requestID!.toString()); + expect(d2.extendedViewingKey!.toKeyString()).toEqual(details.extendedViewingKey!.toKeyString()); + expect(d2.extendedSpendingKey!.toKeyString()).toEqual(details.extendedSpendingKey!.toKeyString()); + expect(d2.address!.toAddressString()).toEqual(details.address!.toAddressString()); + + }); +}); diff --git a/src/__tests__/vdxf/provisioningidentitydetails.test.ts b/src/__tests__/vdxf/provisioningidentitydetails.test.ts new file mode 100644 index 00000000..5b8d8cc6 --- /dev/null +++ b/src/__tests__/vdxf/provisioningidentitydetails.test.ts @@ -0,0 +1,36 @@ + +import { ProvisionIdentityDetails } from "../../vdxf/classes/requestobjects/ProvisionIdentityDetails"; +import { CompactIAddressObject, CompactAddressObject } from "../../vdxf/classes"; +import { BN } from "bn.js"; +import { TEST_IDENTITY_ID_1, TEST_IDENTITY_ID_2 } from "../constants/fixtures"; + +describe('Serializes and deserializes ProvisionIdentityDetails', () => { + test('(de)serialize ProvisionIdentityDetails', () => { + const e = new ProvisionIdentityDetails({ + version: new BN(1, 10), + flags: ProvisionIdentityDetails.FLAG_HAS_SYSTEMID.or(ProvisionIdentityDetails.FLAG_HAS_PARENTID), + systemID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_I_ADDRESS, address: TEST_IDENTITY_ID_1, rootSystemName: "VRSC" }), + parentID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_I_ADDRESS, address: TEST_IDENTITY_ID_2, rootSystemName: "VRSC" }) + }); + + const r = e.toBuffer(); + const rFromBuf = new ProvisionIdentityDetails(); + rFromBuf.fromBuffer(r); + + expect(rFromBuf.toBuffer().toString('hex')).toBe(r.toString('hex')) + }); + + test('(de)serialize ProvisionIdentity with fqn', async () => { + const e = new ProvisionIdentityDetails({ + version: new BN(1, 10), + flags: ProvisionIdentityDetails.FLAG_IS_A_DEFINED_NAME_TO_PROVISION, + identityID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_I_ADDRESS, address: TEST_IDENTITY_ID_1, rootSystemName: "VRSC" }) + }) + + const r = e.toBuffer(); + const rFromBuf = new ProvisionIdentityDetails(); + rFromBuf.fromBuffer(r); + + expect(rFromBuf.toBuffer().toString('hex')).toBe(r.toString('hex')) + }); +}); \ No newline at end of file diff --git a/src/__tests__/vdxf/userdatarequest.test.ts b/src/__tests__/vdxf/userdatarequest.test.ts new file mode 100644 index 00000000..39f8d359 --- /dev/null +++ b/src/__tests__/vdxf/userdatarequest.test.ts @@ -0,0 +1,40 @@ + +import { CompactAddressObject, UserDataRequestDetails, UserDataRequestJson } from "../../vdxf/classes"; + +describe('Serializes and deserializes UserDataRequestDetails', () => { + test('(de)serialize UserDataRequestDetails', () => { + + const provisionJson: UserDataRequestJson = { + version: 1, + flags: UserDataRequestDetails.FULL_DATA.or(UserDataRequestDetails.ATTESTATION).or(UserDataRequestDetails.HAS_SIGNER).toNumber(), + searchdatakey: [{ "iEEjVkvM9Niz4u2WCr6QQzx1zpVSvDFub1": "Attestation Name" }], + signer: { version: 1, type: CompactAddressObject.TYPE_I_ADDRESS.toNumber(), address: "iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq", rootsystemname: "VRSC" }, + requestid: "iD4CrjbJBZmwEZQ4bCWgbHx9tBHGP9mdSQ" + } + + const e = UserDataRequestDetails.fromJson(provisionJson); + const r = e.toBuffer(); + const rFromBuf = new UserDataRequestDetails(); + rFromBuf.fromBuffer(r); + + expect(rFromBuf.toBuffer().toString('hex')).toBe(r.toString('hex')) + }); + test('(de)serialize UserDataRequestDetails with requestedkeys', async () => { + + const provisionJson: UserDataRequestJson = { + version: 1, + flags: UserDataRequestDetails.PARTIAL_DATA.or(UserDataRequestDetails.ATTESTATION).or(UserDataRequestDetails.HAS_SIGNER).toNumber(), + searchdatakey: [{ "iEEjVkvM9Niz4u2WCr6QQzx1zpVSvDFub1": "Attestation Name" }], + signer: { version: 1, type: CompactAddressObject.TYPE_FQN.toNumber(), address: "bob@", rootsystemname: "VRSC" }, + requestedkeys: ["iLB8SG7ErJtTYcG1f4w9RLuMJPpAsjFkiL"], + requestid: "iD4CrjbJBZmwEZQ4bCWgbHx9tBHGP9mdSQ" + } + + const e = UserDataRequestDetails.fromJson(provisionJson); + const r = e.toBuffer(); + const rFromBuf = new UserDataRequestDetails(); + rFromBuf.fromBuffer(r); + + expect(rFromBuf.toBuffer().toString('hex')).toBe(r.toString('hex')) + }); +}); \ No newline at end of file diff --git a/src/__tests__/vdxf/userspecificdatapacketdetails.test.ts b/src/__tests__/vdxf/userspecificdatapacketdetails.test.ts new file mode 100644 index 00000000..fd489347 --- /dev/null +++ b/src/__tests__/vdxf/userspecificdatapacketdetails.test.ts @@ -0,0 +1,47 @@ +import { BN } from "bn.js"; +import { + CompactAddressObject, + CompactIAddressObject, + UserSpecificDataPacketDetails +} from "../../vdxf/classes"; +import { DataDescriptor } from "../../pbaas"; +import { VerifiableSignatureData } from "../../vdxf/classes/VerifiableSignatureData"; + + +describe("UserSpecificDataPacketDetails", () => { + describe("constructor and basic properties", () => { + test("creates instance with custom values", () => { + const item = new UserSpecificDataPacketDetails({ + version: new BN(UserSpecificDataPacketDetails.DEFAULT_VERSION), + flags: UserSpecificDataPacketDetails.HAS_STATEMENTS.or(UserSpecificDataPacketDetails.HAS_SIGNATURE).or(UserSpecificDataPacketDetails.HAS_DETAILS_ID), + signableObjects: [DataDescriptor.fromJson({ version: new BN(1), label: "123", objectdata: "0011223344aabbcc", flags: DataDescriptor.FLAG_LABEL_PRESENT })], + statements: ["Statement 1", "Statement 2"], + signature: new VerifiableSignatureData({ + version: new BN(1), + signatureAsVch: Buffer.from("efc8d6b60c5b6efaeb3fce4b2c0749c317f2167549ec22b1bee411b8802d5aaf", 'hex'), + hashType: new BN(1), + flags: new BN(0), + identityID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_I_ADDRESS, address: "i7LaXD2cdy1zeh33eHzZaEPyueT4yQmBfW", rootSystemName: "VRSC" }), + systemID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_FQN, address: "VRSC", rootSystemName: "VRSC" }), + }), + detailsID: "iD4CrjbJBZmwEZQ4bCWgbHx9tBHGP9mdSQ" + }); + + const detailsBuffer = item.toBuffer(); + + const newDetails = new UserSpecificDataPacketDetails(); + newDetails.fromBuffer(detailsBuffer); + + expect(newDetails.toJson()).toEqual(item.toJson()); + + expect(newDetails.version.toString()).toBe(item.version.toString()); + expect(newDetails.flags.toString()).toBe(item.flags.toString()); + expect(newDetails.signableObjects.length).toBe(1); + expect(newDetails.signableObjects[0].toJson().label).toBe("123"); + expect(newDetails.statements?.length).toBe(2); + expect(newDetails.statements?.[0]).toBe("Statement 1"); + expect(newDetails.signature?.signatureAsVch.toString('hex')).toBe("efc8d6b60c5b6efaeb3fce4b2c0749c317f2167549ec22b1bee411b8802d5aaf"); + expect(newDetails.toBuffer().toString('hex')).toBe(detailsBuffer.toString('hex')); + }); + }); +}); diff --git a/src/__tests__/vdxf/verifiablesignaturedata.test.ts b/src/__tests__/vdxf/verifiablesignaturedata.test.ts new file mode 100644 index 00000000..4af7b30a --- /dev/null +++ b/src/__tests__/vdxf/verifiablesignaturedata.test.ts @@ -0,0 +1,324 @@ +import { VerifiableSignatureData } from "../../vdxf/classes/VerifiableSignatureData"; +import { CompactAddressObject, CompactIAddressObject } from "../../vdxf/classes/CompactAddressObject"; +import { HASH_TYPE_SHA256 } from '../../constants/pbaas'; +import { BN } from "bn.js"; + +const createHash = require("create-hash"); + +describe('Serializes and deserializes SignatureData', () => { + test('(de)serialize SignatureData', () => { + + const s = new VerifiableSignatureData({ + version: new BN(1), + signatureAsVch: Buffer.from("efc8d6b60c5b6efaeb3fce4b2c0749c317f2167549ec22b1bee411b8802d5aaf", 'hex'), + hashType: HASH_TYPE_SHA256, + flags: new BN(0), + identityID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_I_ADDRESS, address: "i7LaXD2cdy1zeh33eHzZaEPyueT4yQmBfW", rootSystemName: "VRSC" }), + systemID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_FQN, address: "VRSC", rootSystemName: "VRSC" }), + }) + + const sFromBuf = new VerifiableSignatureData(); + + sFromBuf.fromBuffer(s.toBuffer()) + + expect(sFromBuf.toBuffer().toString('hex')).toBe(s.toBuffer().toString('hex')) + }); + + test('(de)serialize SignatureData with vdxfKeys', () => { + const s = new VerifiableSignatureData({ + version: new BN(1), + signatureVersion: new BN(2), + signatureAsVch: Buffer.from("efc8d6b60c5b6efaeb3fce4b2c0749c317f2167549ec22b1bee411b8802d5aaf", 'hex'), + hashType: HASH_TYPE_SHA256, + identityID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_I_ADDRESS, address: "i7LaXD2cdy1zeh33eHzZaEPyueT4yQmBfW", rootSystemName: "VRSC" }), + systemID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_FQN, address: "VRSC", rootSystemName: "VRSC" }), + vdxfKeys: ["iRrCKQqLQrWczeNotMgqJkoUW5ZzF182Ax", "iCCSCFbq9n7ftEQCQT94t8CcVV5NdxnTvL"], + }) + + const sFromBuf = new VerifiableSignatureData(); + sFromBuf.fromBuffer(s.toBuffer()) + + expect(sFromBuf.toBuffer().toString('hex')).toBe(s.toBuffer().toString('hex')) + expect(sFromBuf.vdxfKeys).toEqual(s.vdxfKeys) + expect(sFromBuf.hasVdxfKeys()).toBe(true) + }); + + test('(de)serialize SignatureData with vdxfKeyNames', () => { + const s = new VerifiableSignatureData({ + version: new BN(1), + signatureVersion: new BN(2), + signatureAsVch: Buffer.from("efc8d6b60c5b6efaeb3fce4b2c0749c317f2167549ec22b1bee411b8802d5aaf", 'hex'), + hashType: HASH_TYPE_SHA256, + identityID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_I_ADDRESS, address: "i7LaXD2cdy1zeh33eHzZaEPyueT4yQmBfW", rootSystemName: "VRSC" }), + systemID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_FQN, address: "VRSC", rootSystemName: "VRSC" }), + vdxfKeyNames: ["key.name.one", "key.name.two", "another.key"], + }) + + const sFromBuf = new VerifiableSignatureData(); + sFromBuf.fromBuffer(s.toBuffer()) + + expect(sFromBuf.toBuffer().toString('hex')).toBe(s.toBuffer().toString('hex')) + expect(sFromBuf.vdxfKeyNames).toEqual(s.vdxfKeyNames) + expect(sFromBuf.hasVdxfKeyNames()).toBe(true) + }); + + test('(de)serialize SignatureData with boundHashes', () => { + const s = new VerifiableSignatureData({ + version: new BN(1), + signatureVersion: new BN(2), + signatureAsVch: Buffer.from("efc8d6b60c5b6efaeb3fce4b2c0749c317f2167549ec22b1bee411b8802d5aaf", 'hex'), + hashType: HASH_TYPE_SHA256, + identityID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_I_ADDRESS, address: "i7LaXD2cdy1zeh33eHzZaEPyueT4yQmBfW", rootSystemName: "VRSC" }), + systemID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_FQN, address: "VRSC", rootSystemName: "VRSC" }), + boundHashes: [ + Buffer.from("a".repeat(64), 'hex'), + Buffer.from("b".repeat(64), 'hex'), + ], + }) + + const sFromBuf = new VerifiableSignatureData(); + sFromBuf.fromBuffer(s.toBuffer()) + + expect(sFromBuf.toBuffer().toString('hex')).toBe(s.toBuffer().toString('hex')) + expect(sFromBuf.boundHashes?.length).toBe(2) + expect(sFromBuf.hasBoundHashes()).toBe(true) + }); + + test('(de)serialize SignatureData with all extra data', () => { + const s = new VerifiableSignatureData({ + version: new BN(1), + signatureVersion: new BN(2), + signatureAsVch: Buffer.from("efc8d6b60c5b6efaeb3fce4b2c0749c317f2167549ec22b1bee411b8802d5aaf", 'hex'), + hashType: HASH_TYPE_SHA256, + identityID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_I_ADDRESS, address: "i7LaXD2cdy1zeh33eHzZaEPyueT4yQmBfW", rootSystemName: "VRSC" }), + systemID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_FQN, address: "VRSC", rootSystemName: "VRSC" }), + vdxfKeys: ["iRrCKQqLQrWczeNotMgqJkoUW5ZzF182Ax", "iCCSCFbq9n7ftEQCQT94t8CcVV5NdxnTvL"], + vdxfKeyNames: ["key.name.one", "key.name.two"], + boundHashes: [ + Buffer.from("a".repeat(64), 'hex'), + Buffer.from("b".repeat(64), 'hex'), + ], + }) + + const sFromBuf = new VerifiableSignatureData(); + sFromBuf.fromBuffer(s.toBuffer()) + + expect(sFromBuf.toBuffer().toString('hex')).toBe(s.toBuffer().toString('hex')) + expect(sFromBuf.vdxfKeys).toEqual(s.vdxfKeys) + expect(sFromBuf.vdxfKeyNames).toEqual(s.vdxfKeyNames) + expect(sFromBuf.boundHashes?.length).toBe(2) + expect(sFromBuf.hasVdxfKeys()).toBe(true) + expect(sFromBuf.hasVdxfKeyNames()).toBe(true) + expect(sFromBuf.hasBoundHashes()).toBe(true) + }); + + test('getIdentityHash with extra data - vdxfKeys are sorted by buffer value', () => { + // Create with keys in non-sorted order + const s = new VerifiableSignatureData({ + version: new BN(1), + signatureVersion: new BN(2), + signatureAsVch: Buffer.from("AgVfngwAAUEgywnMVejMz6iZj88qRawIivovU9L9uQtGcDbD635QbNt2G/QoZjxT6c7w099JjBd2cGa8ajI99KG0MTbHT99ZZw==", 'base64'), + hashType: HASH_TYPE_SHA256, + identityID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_I_ADDRESS, address: "i4M7ar436N7wKHgZodjGAWdsBSNjG7cz8s", rootSystemName: "VRSCTEST" }), + systemID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_FQN, address: "VRSCTEST", rootSystemName: "VRSCTEST" }), + vdxfKeys: ["iQRWB2Ay9rEbzStXDjMFpveh4oEmD6YWXa"], + }) + + const sigHash = createHash("sha256").update("hello world1").digest(); + const hash1 = s.getIdentityHash(826975, sigHash); + + // Create with same keys but different order + const s2 = new VerifiableSignatureData({ + version: new BN(1), + signatureVersion: new BN(2), + signatureAsVch: Buffer.from("AgVfngwAAUEgywnMVejMz6iZj88qRawIivovU9L9uQtGcDbD635QbNt2G/QoZjxT6c7w099JjBd2cGa8ajI99KG0MTbHT99ZZw==", 'base64'), + hashType: HASH_TYPE_SHA256, + identityID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_I_ADDRESS, address: "i4M7ar436N7wKHgZodjGAWdsBSNjG7cz8s", rootSystemName: "VRSCTEST" }), + systemID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_FQN, address: "VRSCTEST", rootSystemName: "VRSCTEST" }), + vdxfKeys: ["iQRWB2Ay9rEbzStXDjMFpveh4oEmD6YWXa"], + }) + + const hash2 = s2.getIdentityHash(826975, sigHash); + + // Hashes should be identical because keys are sorted before hashing + expect(hash1.toString('hex')).toBe(hash2.toString('hex')) + }); + + test('getIdentityHash with extra data - vdxfKeys are sorted by buffer value', () => { + // Create with keys in non-sorted order + const s = new VerifiableSignatureData({ + version: new BN(1), + signatureVersion: new BN(2), + signatureAsVch: Buffer.from("AgV1ngwAAUEfYEg7UW5l0zS88ERfSBXZJ6+RWiUwXQ8BwMkkUesmemFBF29LEVw0C60csXMbMdLYxt3qGLLhgHnev9XIwWFIvw==", 'base64'), + hashType: HASH_TYPE_SHA256, + identityID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_I_ADDRESS, address: "i4M7ar436N7wKHgZodjGAWdsBSNjG7cz8s", rootSystemName: "VRSCTEST" }), + systemID: new CompactIAddressObject({ version: CompactAddressObject.DEFAULT_VERSION, type: CompactAddressObject.TYPE_FQN, address: "VRSCTEST", rootSystemName: "VRSCTEST" }), + }) + + const sigHash = createHash("sha256").update("hello world1").digest(); + const hash1 = s.getIdentityHash(826997, sigHash); + + // Hashes should be identical because keys are sorted before hashing + expect(hash1.toString('hex')).toBe(hash1.toString('hex')) + + }); + + test('fromSignatureDataJson parses all fields correctly', () => { + const signatureDataJson = { + "signaturedata": { + "version": 1, + "systemid": "iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq", // + "hashtype": 5, + "signaturehash": "f8220bacb0bf5bd8ca33a890184b66b35fb64647274b4b9fb4ff90e68f77a5a7", + "identityid": "i4M7ar436N7wKHgZodjGAWdsBSNjG7cz8s", + "signaturetype": 1, + "signature": "AgVgngwAAUEg4QYvX2zJJUZLa4YdtwoxehCQ9T3U6xGw08SmonRSv1xofR1264j5/bdXmq6Qc2YgzlCt3DqVKM9c9DLuCU4bbQ==",// + "vdxfkeys": [ + "iQRWB2Ay9rEbzStXDjMFpveh4oEmD6YWXa", + "i5cVmwQQZfWz1AYp9AwKakPQxTjQfK2Mrk", + "iKqjqcXE15KPNuCvm2evZUnwiYEZ2CLnV2", + "iRrCKQqLQrWczeNotMgqJkoUW5ZzF182Ax" + ], + "vdxfkeynames": [ + "examplename1", + "examplename2" + ], + "boundhashes": [ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + ] + }, + "system": "VRSCTEST", + "systemid": "iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq", + "hashtype": "sha256", + "hash": "f8220bacb0bf5bd8ca33a890184b66b35fb64647274b4b9fb4ff90e68f77a5a7", + "identity": "endorsetest.VRSCTEST@", + "canonicalname": "endorsetest.vrsctest@", + "address": "i4M7ar436N7wKHgZodjGAWdsBSNjG7cz8s", + "signatureheight": 826976, + "vdxfkeys": [ + "iQRWB2Ay9rEbzStXDjMFpveh4oEmD6YWXa", + "i5cVmwQQZfWz1AYp9AwKakPQxTjQfK2Mrk", + "iKqjqcXE15KPNuCvm2evZUnwiYEZ2CLnV2", + "iRrCKQqLQrWczeNotMgqJkoUW5ZzF182Ax" + ], + "vdxfkeynames": [ + "examplename1", + "examplename2" + ], + "boundhashes": [ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + ], + "signatureversion": 2, + "signature": "AgVgngwAAUEg4QYvX2zJJUZLa4YdtwoxehCQ9T3U6xGw08SmonRSv1xofR1264j5/bdXmq6Qc2YgzlCt3DqVKM9c9DLuCU4bbQ==" + }; + + const verifiableSig = VerifiableSignatureData.fromCLIJson(signatureDataJson); + + // Verify version fields + expect(verifiableSig.version.toNumber()).toBe(1); + expect(verifiableSig.signatureVersion.toNumber()).toBe(2); // Auto-detected as v2 due to extra data + + // Verify IDs + expect(verifiableSig.systemID.toIAddress()).toBe("iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq"); + expect(verifiableSig.identityID.toIAddress()).toBe("i4M7ar436N7wKHgZodjGAWdsBSNjG7cz8s"); + + // Verify hash type + expect(verifiableSig.hashType.toNumber()).toBe(5); + + // Verify vdxfKeys (stored as strings) + expect(verifiableSig.vdxfKeys).toBeDefined(); + expect(verifiableSig.vdxfKeys?.length).toBe(4); + expect(verifiableSig.vdxfKeys?.[0]).toBe("iQRWB2Ay9rEbzStXDjMFpveh4oEmD6YWXa"); + expect(verifiableSig.vdxfKeys?.[1]).toBe("i5cVmwQQZfWz1AYp9AwKakPQxTjQfK2Mrk"); + expect(verifiableSig.vdxfKeys?.[2]).toBe("iKqjqcXE15KPNuCvm2evZUnwiYEZ2CLnV2"); + expect(verifiableSig.vdxfKeys?.[3]).toBe("iRrCKQqLQrWczeNotMgqJkoUW5ZzF182Ax"); + + // Verify vdxfKeyNames + expect(verifiableSig.vdxfKeyNames).toBeDefined(); + expect(verifiableSig.vdxfKeyNames?.length).toBe(2); + expect(verifiableSig.vdxfKeyNames?.[0]).toBe("examplename1"); + expect(verifiableSig.vdxfKeyNames?.[1]).toBe("examplename2"); + + // Verify boundHashes + expect(verifiableSig.boundHashes).toBeDefined(); + expect(verifiableSig.boundHashes?.length).toBe(2); + expect(verifiableSig.boundHashes?.[0].toString('hex')).toBe("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + expect(verifiableSig.boundHashes?.[1].toString('hex')).toBe("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); + + // Verify signature + expect(verifiableSig.signatureAsVch.toString('base64')).toBe("AgVgngwAAUEg4QYvX2zJJUZLa4YdtwoxehCQ9T3U6xGw08SmonRSv1xofR1264j5/bdXmq6Qc2YgzlCt3DqVKM9c9DLuCU4bbQ=="); + }); + + test('verify daemon signature with all extra data - from signdata', () => { + // Real signature data from daemon with vdxfkeys, vdxfkeynames, and boundhashes + const signatureDataJson = { + "signaturedata": { + "version": 1, + "systemid": "iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq", // + "hashtype": 5, + "signaturehash": "f8220bacb0bf5bd8ca33a890184b66b35fb64647274b4b9fb4ff90e68f77a5a7", + "identityid": "i4M7ar436N7wKHgZodjGAWdsBSNjG7cz8s", + "signaturetype": 1, + "signature": "AgVgngwAAUEg4QYvX2zJJUZLa4YdtwoxehCQ9T3U6xGw08SmonRSv1xofR1264j5/bdXmq6Qc2YgzlCt3DqVKM9c9DLuCU4bbQ==",// + "vdxfkeys": [ + "iQRWB2Ay9rEbzStXDjMFpveh4oEmD6YWXa", + "i5cVmwQQZfWz1AYp9AwKakPQxTjQfK2Mrk", + "iKqjqcXE15KPNuCvm2evZUnwiYEZ2CLnV2", + "iRrCKQqLQrWczeNotMgqJkoUW5ZzF182Ax" + ], + "vdxfkeynames": [ + "examplename1", + "examplename2" + ], + "boundhashes": [ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + ] + }, + "system": "VRSCTEST", + "systemid": "iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq", + "hashtype": "sha256", + "hash": "f8220bacb0bf5bd8ca33a890184b66b35fb64647274b4b9fb4ff90e68f77a5a7", + "identity": "endorsetest.VRSCTEST@", + "canonicalname": "endorsetest.vrsctest@", + "address": "i4M7ar436N7wKHgZodjGAWdsBSNjG7cz8s", + "signatureheight": 826976, + "vdxfkeys": [ + "iQRWB2Ay9rEbzStXDjMFpveh4oEmD6YWXa", + "i5cVmwQQZfWz1AYp9AwKakPQxTjQfK2Mrk", + "iKqjqcXE15KPNuCvm2evZUnwiYEZ2CLnV2", + "iRrCKQqLQrWczeNotMgqJkoUW5ZzF182Ax" + ], + "vdxfkeynames": [ + "examplename1", + "examplename2" + ], + "boundhashes": [ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + ], + "signatureversion": 2, + "signature": "AgVgngwAAUEg4QYvX2zJJUZLa4YdtwoxehCQ9T3U6xGw08SmonRSv1xofR1264j5/bdXmq6Qc2YgzlCt3DqVKM9c9DLuCU4bbQ==" + }; + + // Create VerifiableSignatureData directly from SignatureData JSON + const verifiableSig = VerifiableSignatureData.fromCLIJson(signatureDataJson); + + // Verify the parsed data + expect(verifiableSig.version.toNumber()).toBe(1); + expect(verifiableSig.signatureVersion.toNumber()).toBe(2); + expect(verifiableSig.hashType.toNumber()).toBe(5); + expect(verifiableSig.systemID.toIAddress()).toBe("iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq"); + expect(verifiableSig.identityID.toIAddress()).toBe("i4M7ar436N7wKHgZodjGAWdsBSNjG7cz8s"); + expect(verifiableSig.vdxfKeys?.length).toBe(4); + expect(verifiableSig.vdxfKeyNames?.length).toBe(2); + expect(verifiableSig.boundHashes?.length).toBe(2); + + + + }); + + +}); diff --git a/src/__tests__/vdxf/veruspayinvoice.test.ts b/src/__tests__/vdxf/veruspayinvoice.test.ts index fc292a98..1e73200f 100644 --- a/src/__tests__/vdxf/veruspayinvoice.test.ts +++ b/src/__tests__/vdxf/veruspayinvoice.test.ts @@ -1,8 +1,10 @@ import { BN } from "bn.js"; -import { VerusPayInvoice, VerusPayInvoiceDetails } from "../../vdxf/classes"; +import { CompactXAddressObject, VerusPayInvoice, VerusPayInvoiceDetails } from "../../vdxf/classes"; import { DEST_PKH, TransferDestination } from "../../pbaas/TransferDestination"; import { fromBase58Check } from "../../utils/address"; -import { VERUSPAY_VERSION_FIRSTVALID, VERUSPAY_VERSION_LASTVALID } from "../../vdxf/classes/payment/VerusPayInvoice"; +import { VERUSPAY_VERSION_3, VERUSPAY_VERSION_4, VERUSPAY_VERSION_FIRSTVALID, VERUSPAY_VERSION_LASTVALID } from "../../constants/vdxf/veruspay"; +import { BigNumber } from "../../utils/types/BigNumber"; +import { SaplingPaymentAddress } from "../../pbaas"; describe('Serializes and deserializes VerusPay invoice', () => { test('basic verus pay invoice with invalid version', async () => { @@ -13,7 +15,7 @@ describe('Serializes and deserializes VerusPay invoice', () => { destination_bytes: fromBase58Check("R9J8E2no2HVjQmzX6Ntes2ShSGcn7WiRcx").hash }), requestedcurrencyid: "iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq" - }) + }, VERUSPAY_VERSION_3) const inv = new VerusPayInvoice({ details, @@ -31,7 +33,7 @@ describe('Serializes and deserializes VerusPay invoice', () => { destination_bytes: fromBase58Check("R9J8E2no2HVjQmzX6Ntes2ShSGcn7WiRcx").hash }), requestedcurrencyid: "iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq" - }) + }); const inv2 = new VerusPayInvoice({ details: details2, @@ -43,7 +45,12 @@ describe('Serializes and deserializes VerusPay invoice', () => { expect(() => _inv2.fromBuffer(invbuf2)).toThrow("Unsupported version for vdxf object.") }); - test('basic verus pay invoice without signature', async () => { + const testEveryVersion = async (test: (version: BigNumber) => Promise) => { + await test(VERUSPAY_VERSION_3) + await test(VERUSPAY_VERSION_4) + } + + const basicTestWithoutSig = async (version: BigNumber) => { const details = new VerusPayInvoiceDetails({ amount: new BN(10000000000, 10), destination: new TransferDestination({ @@ -51,10 +58,11 @@ describe('Serializes and deserializes VerusPay invoice', () => { destination_bytes: fromBase58Check("R9J8E2no2HVjQmzX6Ntes2ShSGcn7WiRcx").hash }), requestedcurrencyid: "iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq" - }) + }, version) const inv = new VerusPayInvoice({ - details + details, + version: version }) const invbuf = inv.toBuffer() @@ -72,9 +80,9 @@ describe('Serializes and deserializes VerusPay invoice', () => { const _invfromqrstring = VerusPayInvoice.fromQrString(invqrstring) expect(_invfromqrstring.toBuffer().toString('hex')).toBe(inv.toBuffer().toString('hex')); - }); + } - test('JSON test basic verus pay invoice without signature', async () => { + const basicJSONTestWithoutSig = async (version: BigNumber) => { const details = new VerusPayInvoiceDetails({ amount: new BN(10000000000, 10), destination: new TransferDestination({ @@ -82,21 +90,22 @@ describe('Serializes and deserializes VerusPay invoice', () => { destination_bytes: fromBase58Check("R9J8E2no2HVjQmzX6Ntes2ShSGcn7WiRcx").hash }), requestedcurrencyid: "iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq" - }) + }, version) const inv = new VerusPayInvoice({ - details + details, + version: version }) const invFromJson = VerusPayInvoice.fromJson(inv.toJson()); expect(invFromJson.toBuffer().toString('hex')).toBe(inv.toBuffer().toString('hex')); - }); + } - test('basic verus pay invoice without signature that accepts any amount and destination', async () => { + const testNoSigAcceptsAnyAmountAcceptsAnyDest = async (version: BigNumber) => { const details = new VerusPayInvoiceDetails({ requestedcurrencyid: "iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq" - }) + }, version) details.setFlags({ acceptsAnyAmount: true, @@ -104,7 +113,8 @@ describe('Serializes and deserializes VerusPay invoice', () => { }) const inv = new VerusPayInvoice({ - details + details, + version: version }) const invbuf = inv.toBuffer() @@ -122,9 +132,9 @@ describe('Serializes and deserializes VerusPay invoice', () => { const _invfromqrstring = VerusPayInvoice.fromQrString(invqrstring) expect(_invfromqrstring.toBuffer().toString('hex')).toBe(inv.toBuffer().toString('hex')); - }); + } - test('verus pay invoice without signature that accepts conversion', async () => { + const testNoSigAcceptsConversion = async (version: BigNumber) => { const details = new VerusPayInvoiceDetails({ amount: new BN(10000000000, 10), destination: new TransferDestination({ @@ -133,14 +143,15 @@ describe('Serializes and deserializes VerusPay invoice', () => { }), requestedcurrencyid: "iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq", maxestimatedslippage: new BN(40000000, 10), - }) + }, version) details.setFlags({ acceptsConversion: true }) const inv = new VerusPayInvoice({ - details + details, + version: version }) const invbuf = inv.toBuffer() @@ -158,9 +169,9 @@ describe('Serializes and deserializes VerusPay invoice', () => { const _invfromqrstring = VerusPayInvoice.fromQrString(invqrstring) expect(_invfromqrstring.toBuffer().toString('hex')).toBe(inv.toBuffer().toString('hex')); - }); + } - test('verus pay invoice without signature that accepts conversion and expires', async () => { + const testNoSigAcceptsConversionExpires = async (version: BigNumber) => { const details = new VerusPayInvoiceDetails({ amount: new BN(10000000000, 10), destination: new TransferDestination({ @@ -170,7 +181,7 @@ describe('Serializes and deserializes VerusPay invoice', () => { requestedcurrencyid: "iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq", maxestimatedslippage: new BN(40000000, 10), expiryheight: new BN(2000000, 10) - }) + }, version) details.setFlags({ acceptsConversion: true, @@ -178,7 +189,8 @@ describe('Serializes and deserializes VerusPay invoice', () => { }) const inv = new VerusPayInvoice({ - details + details, + version: version }) const invbuf = inv.toBuffer() @@ -196,9 +208,9 @@ describe('Serializes and deserializes VerusPay invoice', () => { const _invfromqrstring = VerusPayInvoice.fromQrString(invqrstring) expect(_invfromqrstring.toBuffer().toString('hex')).toBe(inv.toBuffer().toString('hex')); - }); + } - test('verus pay invoice without signature that accepts conversion on 2 non-verus systems and expires', async () => { + const testNoSigAcceptsConversionHasNonVerusSystemsExpires = async (version: BigNumber) => { const details = new VerusPayInvoiceDetails({ amount: new BN(10000000000, 10), destination: new TransferDestination({ @@ -209,7 +221,7 @@ describe('Serializes and deserializes VerusPay invoice', () => { maxestimatedslippage: new BN(40000000, 10), expiryheight: new BN(2000000, 10), acceptedsystems: ["iNC9NG5Jqk2tqVtqfjfiSpaqxrXaFU6RDu", "iBDkVJqik6BrtcDBQfFygffiYzTMy6EuhU"] - }) + }, version) details.setFlags({ acceptsConversion: true, @@ -218,7 +230,8 @@ describe('Serializes and deserializes VerusPay invoice', () => { }) const inv = new VerusPayInvoice({ - details + details, + version: version }) const invbuf = inv.toBuffer() @@ -236,9 +249,9 @@ describe('Serializes and deserializes VerusPay invoice', () => { const _invfromqrstring = VerusPayInvoice.fromQrString(invqrstring) expect(_invfromqrstring.toBuffer().toString('hex')).toBe(inv.toBuffer().toString('hex')); - }); + } - test('verus pay invoice with signature that accepts conversion on 2 non-verus systems and expires', async () => { + const testSignedAcceptsConversionHasNonVerusSystemsExpires = async (version: BigNumber) => { const details = new VerusPayInvoiceDetails({ amount: new BN(10000000000, 10), destination: new TransferDestination({ @@ -249,7 +262,7 @@ describe('Serializes and deserializes VerusPay invoice', () => { maxestimatedslippage: new BN(40000000, 10), expiryheight: new BN(2000000, 10), acceptedsystems: ["iNC9NG5Jqk2tqVtqfjfiSpaqxrXaFU6RDu", "iBDkVJqik6BrtcDBQfFygffiYzTMy6EuhU"] - }) + }, version) details.setFlags({ acceptsConversion: true, @@ -265,6 +278,61 @@ describe('Serializes and deserializes VerusPay invoice', () => { signature: "AYG2IQABQSAN1fp6A9NIVbxvKuOVLLU+0I+G3oQGbRtS6u4Eampfb217Cdf5FCMScQhV9kMxtjI9GWzpchmjuiTB2tctk6qT", }, + version: version + }) + + inv.setSigned() + + const invbuf = inv.toBuffer() + const _inv = new VerusPayInvoice() + _inv.fromBuffer(invbuf) + + expect(_inv.toBuffer().toString('hex')).toBe(invbuf.toString('hex')); + + const invuri = inv.toWalletDeeplinkUri() + const _invfromuri = VerusPayInvoice.fromWalletDeeplinkUri(invuri) + + expect(_invfromuri.toBuffer().toString('hex')).toBe(inv.toBuffer().toString('hex')); + + const invqrstring = inv.toQrString() + const _invfromqrstring = VerusPayInvoice.fromQrString(invqrstring) + + expect(_invfromqrstring.toBuffer().toString('hex')).toBe(inv.toBuffer().toString('hex')); + + const invFromJson = VerusPayInvoice.fromJson(inv.toJson()); + + expect(invFromJson.toBuffer().toString('hex')).toBe(inv.toBuffer().toString('hex')); + } + + const testSignedAcceptsConversionHasNonVerusSystemsExpiresWithSaplingAddressPreconvertTag = async (version: BigNumber) => { + const addrString = "zs1wczplx4kegw32h8g0f7xwl57p5tvnprwdmnzmdnsw50chcl26f7tws92wk2ap03ykaq6jyyztfa"; + + const details = new VerusPayInvoiceDetails({ + amount: new BN(10000000000, 10), + destination: SaplingPaymentAddress.fromAddressString(addrString), + requestedcurrencyid: "iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq", + maxestimatedslippage: new BN(40000000, 10), + expiryheight: new BN(2000000, 10), + acceptedsystems: ["iNC9NG5Jqk2tqVtqfjfiSpaqxrXaFU6RDu", "iBDkVJqik6BrtcDBQfFygffiYzTMy6EuhU"], + tag: CompactXAddressObject.fromAddress("xA91QPpBrHZto92NCU5KEjCqRveS4dAPrf") + }, version) + + details.setFlags({ + acceptsConversion: true, + expires: true, + acceptsNonVerusSystems: true, + destinationIsSaplingPaymentAddress: true + }) + + const inv = new VerusPayInvoice({ + details, + system_id: "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV", + signing_id: "iB5PRXMHLYcNtM8dfLB6KwfJrHU2mKDYuU", + signature: { + signature: + "AYG2IQABQSAN1fp6A9NIVbxvKuOVLLU+0I+G3oQGbRtS6u4Eampfb217Cdf5FCMScQhV9kMxtjI9GWzpchmjuiTB2tctk6qT", + }, + version: version }) inv.setSigned() @@ -286,7 +354,76 @@ describe('Serializes and deserializes VerusPay invoice', () => { expect(_invfromqrstring.toBuffer().toString('hex')).toBe(inv.toBuffer().toString('hex')); const invFromJson = VerusPayInvoice.fromJson(inv.toJson()); - + expect(invFromJson.toBuffer().toString('hex')).toBe(inv.toBuffer().toString('hex')); + } + + const testNoSigAcceptsAnyAmountAcceptsAnyDestPreconvert = async (version: BigNumber) => { + const details = new VerusPayInvoiceDetails({ + requestedcurrencyid: "iNC9NG5Jqk2tqVtqfjfiSpaqxrXaFU6RDu" + }, version) + + details.setFlags({ + acceptsAnyAmount: true, + acceptsAnyDestination: true, + isPreconvert: true + }) + + const inv = new VerusPayInvoice({ + details, + version: version + }) + + const invbuf = inv.toBuffer() + const _inv = new VerusPayInvoice() + _inv.fromBuffer(invbuf) + + expect(_inv.toBuffer().toString('hex')).toBe(invbuf.toString('hex')); + + const invuri = inv.toWalletDeeplinkUri() + const _invfromuri = VerusPayInvoice.fromWalletDeeplinkUri(invuri) + + expect(_invfromuri.toBuffer().toString('hex')).toBe(inv.toBuffer().toString('hex')); + + const invqrstring = inv.toQrString() + const _invfromqrstring = VerusPayInvoice.fromQrString(invqrstring) + + expect(_invfromqrstring.toBuffer().toString('hex')).toBe(inv.toBuffer().toString('hex')); + } + + test('basic verus pay invoice without signature', async () => { + await testEveryVersion(basicTestWithoutSig); + }); + + test('JSON test basic verus pay invoice without signature', async () => { + await testEveryVersion(basicJSONTestWithoutSig); + }); + + test('basic verus pay invoice without signature that accepts any amount and destination', async () => { + await testEveryVersion(testNoSigAcceptsAnyAmountAcceptsAnyDest); + }); + + test('verus pay invoice without signature that accepts conversion', async () => { + await testEveryVersion(testNoSigAcceptsConversion); }); + + test('verus pay invoice without signature that accepts conversion and expires', async () => { + await testEveryVersion(testNoSigAcceptsConversionExpires); + }); + + test('verus pay invoice without signature that accepts conversion on 2 non-verus systems and expires', async () => { + await testEveryVersion(testNoSigAcceptsConversionHasNonVerusSystemsExpires); + }); + + test('verus pay invoice with signature that accepts conversion on 2 non-verus systems and expires', async () => { + await testEveryVersion(testSignedAcceptsConversionHasNonVerusSystemsExpires); + }); + + test('verus pay invoice with signature that accepts conversion on 2 non-verus systems and expires with sapling address', async () => { + await testSignedAcceptsConversionHasNonVerusSystemsExpiresWithSaplingAddressPreconvertTag(VERUSPAY_VERSION_4); + }) + + test('verus pay invoice without signature that accepts any amount and destination for preconvert', async () => { + await testNoSigAcceptsAnyAmountAcceptsAnyDestPreconvert(VERUSPAY_VERSION_4); + }) }); diff --git a/src/api/classes/SendCurrency/SendCurrencyRequest.ts b/src/api/classes/SendCurrency/SendCurrencyRequest.ts index d44f27e7..7118eec8 100644 --- a/src/api/classes/SendCurrency/SendCurrencyRequest.ts +++ b/src/api/classes/SendCurrency/SendCurrencyRequest.ts @@ -17,6 +17,7 @@ type output = { preconvert?: boolean; burn?: boolean; mintnew?: boolean; + vdxftag?: string; } export class SendCurrencyRequest extends ApiRequest { diff --git a/src/constants/deeplink.ts b/src/constants/deeplink.ts new file mode 100644 index 00000000..7ce5d20a --- /dev/null +++ b/src/constants/deeplink.ts @@ -0,0 +1,4 @@ +import { BN } from "bn.js" + +export const DEEPLINK_PROTOCOL_URL_STRING = "verus"; +export const DEEPLINK_PROTOCOL_URL_CURRENT_VERSION = new BN(1, 10); \ No newline at end of file diff --git a/src/constants/ordinals/ordinals.ts b/src/constants/ordinals/ordinals.ts new file mode 100644 index 00000000..37846a3b --- /dev/null +++ b/src/constants/ordinals/ordinals.ts @@ -0,0 +1,19 @@ +import { BN } from "bn.js"; + +export const VDXF_OBJECT_RESERVED_BYTE_I_ADDR = new BN(102, 10); +export const VDXF_OBJECT_RESERVED_BYTE_VDXF_ID_STRING = new BN(103, 10); +export const VDXF_OBJECT_RESERVED_BYTE_ID_OR_CURRENCY = new BN(104, 10); + +export const VDXF_ORDINAL_DATA_DESCRIPTOR = new BN(0, 10); +export const VDXF_ORDINAL_VERUSPAY_INVOICE = new BN(1, 10); +export const VDXF_ORDINAL_AUTHENTICATION_REQUEST = new BN(2, 10); +export const VDXF_ORDINAL_AUTHENTICATION_RESPONSE = new BN(3, 10); +export const VDXF_ORDINAL_IDENTITY_UPDATE_REQUEST = new BN(4, 10); +export const VDXF_ORDINAL_IDENTITY_UPDATE_RESPONSE = new BN(5, 10); +export const VDXF_ORDINAL_PROVISION_IDENTITY_DETAILS = new BN(6, 10); + +export const VDXF_ORDINAL_APP_ENCRYPTION_REQUEST = new BN(8, 10); +export const VDXF_ORDINAL_APP_ENCRYPTION_RESPONSE = new BN(9, 10); +export const VDXF_ORDINAL_USER_SPECIFIC_DATA_PACKET = new BN(10, 10); +export const VDXF_ORDINAL_USER_DATA_REQUEST = new BN(12, 10); +export const VDXF_ORDINAL_DATA_RESPONSE = new BN(13, 10); diff --git a/src/constants/ordinals/register.ts b/src/constants/ordinals/register.ts new file mode 100644 index 00000000..534bdf2e --- /dev/null +++ b/src/constants/ordinals/register.ts @@ -0,0 +1,34 @@ +import { APP_ENCRYPTION_REQUEST_VDXF_KEY, APP_ENCRYPTION_RESPONSE_VDXF_KEY, DATA_RESPONSE_VDXF_KEY, DATA_TYPE_OBJECT_DATADESCRIPTOR, AUTHENTICATION_REQUEST_VDXF_KEY, AUTHENTICATION_RESPONSE_VDXF_KEY, PROVISION_IDENTITY_DETAILS_VDXF_KEY, USER_DATA_REQUEST_VDXF_KEY, USER_SPECIFIC_DATA_PACKET_VDXF_KEY, VERUSPAY_INVOICE_DETAILS_VDXF_KEY, IDENTITY_UPDATE_RESPONSE_VDXF_KEY, IDENTITY_UPDATE_REQUEST_VDXF_KEY } from "../../vdxf"; +import { AppEncryptionRequestOrdinalVDXFObject } from "../../vdxf/classes/ordinals/AppEncryptionRequestOrdinalVDXFObject"; +import { DataDescriptorOrdinalVDXFObject } from "../../vdxf/classes/ordinals/DataDescriptorOrdinalVDXFObject"; +import { DataPacketResponseOrdinalVDXFObject } from "../../vdxf/classes/ordinals/DataPacketResponseOrdinalVDXFObject"; +import { UserDataRequestOrdinalVDXFObject } from "../../vdxf/classes/ordinals/UserDataRequestOrdinalVDXFObject"; +import { UserSpecificDataPacketDetailsOrdinalVDXFObject } from "../../vdxf/classes/ordinals/UserSpecificDataPacketDetailsOrdinalVDXFObject"; +import { IdentityUpdateRequestOrdinalVDXFObject } from "../../vdxf/classes/ordinals/IdentityUpdateRequestOrdinalVDXFObject"; +import { IdentityUpdateResponseOrdinalVDXFObject } from "../../vdxf/classes/ordinals/IdentityUpdateResponseOrdinalVDXFObject"; +import { AuthenticationRequestOrdinalVDXFObject } from "../../vdxf/classes/ordinals/AuthenticationRequestOrdinalVDXFObject"; +import { AuthenticationResponseOrdinalVDXFObject } from "../../vdxf/classes/ordinals/AuthenticationResponseOrdinalVDXFObject"; +import { OrdinalVDXFObjectOrdinalMap } from "../../vdxf/classes/ordinals/OrdinalVDXFObjectOrdinalMap"; +import { ProvisionIdentityDetailsOrdinalVDXFObject } from "../../vdxf/classes/ordinals/ProvisionIdentityDetailsOrdinalVDXFObject"; +import { VerusPayInvoiceOrdinalVDXFObject } from "../../vdxf/classes/ordinals/VerusPayInvoiceOrdinalVDXFObject"; +import { VDXF_ORDINAL_APP_ENCRYPTION_REQUEST, VDXF_ORDINAL_APP_ENCRYPTION_RESPONSE, VDXF_ORDINAL_DATA_DESCRIPTOR, VDXF_ORDINAL_DATA_RESPONSE, VDXF_ORDINAL_IDENTITY_UPDATE_REQUEST, VDXF_ORDINAL_IDENTITY_UPDATE_RESPONSE, VDXF_ORDINAL_AUTHENTICATION_REQUEST, VDXF_ORDINAL_AUTHENTICATION_RESPONSE, VDXF_ORDINAL_PROVISION_IDENTITY_DETAILS, VDXF_ORDINAL_USER_DATA_REQUEST, VDXF_ORDINAL_USER_SPECIFIC_DATA_PACKET, VDXF_ORDINAL_VERUSPAY_INVOICE } from "./ordinals"; +import { AppEncryptionResponseOrdinalVDXFObject } from "../../vdxf/classes/ordinals/AppEncryptionResponseOrdinalVDXFObject"; + +// This is where all ordinals are currently registered for ordinal VDXF objects. Standard naming convention for the VDXF keys is to +// include the word "response" at the end if it is a response and "request" at the end if it is a request. In case it isn't a request +// (an object expecting a response) or a response, you can use the world "details" at the end, but best not to mix request + details +// or response + details +export const registerOrdinals = () => { + OrdinalVDXFObjectOrdinalMap.registerOrdinal(VDXF_ORDINAL_DATA_DESCRIPTOR.toNumber(), DATA_TYPE_OBJECT_DATADESCRIPTOR.vdxfid, DataDescriptorOrdinalVDXFObject, false); + OrdinalVDXFObjectOrdinalMap.registerOrdinal(VDXF_ORDINAL_VERUSPAY_INVOICE.toNumber(), VERUSPAY_INVOICE_DETAILS_VDXF_KEY.vdxfid, VerusPayInvoiceOrdinalVDXFObject, false); + OrdinalVDXFObjectOrdinalMap.registerOrdinal(VDXF_ORDINAL_AUTHENTICATION_REQUEST.toNumber(), AUTHENTICATION_REQUEST_VDXF_KEY.vdxfid, AuthenticationRequestOrdinalVDXFObject, false); + OrdinalVDXFObjectOrdinalMap.registerOrdinal(VDXF_ORDINAL_AUTHENTICATION_RESPONSE.toNumber(), AUTHENTICATION_RESPONSE_VDXF_KEY.vdxfid, AuthenticationResponseOrdinalVDXFObject, false); + OrdinalVDXFObjectOrdinalMap.registerOrdinal(VDXF_ORDINAL_IDENTITY_UPDATE_REQUEST.toNumber(), IDENTITY_UPDATE_REQUEST_VDXF_KEY.vdxfid, IdentityUpdateRequestOrdinalVDXFObject, false); + OrdinalVDXFObjectOrdinalMap.registerOrdinal(VDXF_ORDINAL_IDENTITY_UPDATE_RESPONSE.toNumber(), IDENTITY_UPDATE_RESPONSE_VDXF_KEY.vdxfid, IdentityUpdateResponseOrdinalVDXFObject, false); + OrdinalVDXFObjectOrdinalMap.registerOrdinal(VDXF_ORDINAL_PROVISION_IDENTITY_DETAILS.toNumber(), PROVISION_IDENTITY_DETAILS_VDXF_KEY.vdxfid, ProvisionIdentityDetailsOrdinalVDXFObject, false); + OrdinalVDXFObjectOrdinalMap.registerOrdinal(VDXF_ORDINAL_APP_ENCRYPTION_REQUEST.toNumber(), APP_ENCRYPTION_REQUEST_VDXF_KEY.vdxfid, AppEncryptionRequestOrdinalVDXFObject, false); + OrdinalVDXFObjectOrdinalMap.registerOrdinal(VDXF_ORDINAL_DATA_RESPONSE.toNumber(), DATA_RESPONSE_VDXF_KEY.vdxfid, DataPacketResponseOrdinalVDXFObject, false); + OrdinalVDXFObjectOrdinalMap.registerOrdinal(VDXF_ORDINAL_USER_DATA_REQUEST.toNumber(), USER_DATA_REQUEST_VDXF_KEY.vdxfid, UserDataRequestOrdinalVDXFObject, false); + OrdinalVDXFObjectOrdinalMap.registerOrdinal(VDXF_ORDINAL_USER_SPECIFIC_DATA_PACKET.toNumber(), USER_SPECIFIC_DATA_PACKET_VDXF_KEY.vdxfid, UserSpecificDataPacketDetailsOrdinalVDXFObject, false); + OrdinalVDXFObjectOrdinalMap.registerOrdinal(VDXF_ORDINAL_APP_ENCRYPTION_RESPONSE.toNumber(), APP_ENCRYPTION_RESPONSE_VDXF_KEY.vdxfid, AppEncryptionResponseOrdinalVDXFObject, false); +} \ No newline at end of file diff --git a/src/constants/ordinals/types.ts b/src/constants/ordinals/types.ts new file mode 100644 index 00000000..13d6f471 --- /dev/null +++ b/src/constants/ordinals/types.ts @@ -0,0 +1,53 @@ +import { DataDescriptor, DataDescriptorJson } from "../../pbaas"; +import { + AppEncryptionRequestDetails, + AppEncryptionRequestJson, + IdentityUpdateRequestDetails, + IdentityUpdateRequestDetailsJson, + IdentityUpdateResponseDetails, + IdentityUpdateResponseDetailsJson, + AuthenticationRequestDetails, + AuthenticationRequestDetailsJson, + AuthenticationResponseDetails, + AuthenticationResponseDetailsJson, + ProvisionIdentityDetails, + ProvisionIdentityDetailsJson, + UserDataRequestDetails, + UserDataRequestJson, + UserSpecificDataPacketDetails, + UserSpecificDataPacketDetailsJson, + VerusPayInvoiceDetails, + AppEncryptionResponseDetails, + AppEncryptionResponseDetailsJson +} from "../../vdxf/classes"; +import { VerusPayInvoiceDetailsJson } from "../../vdxf/classes/payment/VerusPayInvoiceDetails"; +import { DataPacketResponse, DataResponseJson } from "../../vdxf/classes/datapacket/DataPacketResponse"; + +export type OrdinalVDXFObjectReservedData = + DataDescriptor | + VerusPayInvoiceDetails | + IdentityUpdateRequestDetails | + IdentityUpdateResponseDetails | + AuthenticationRequestDetails | + AuthenticationResponseDetails | + ProvisionIdentityDetails | + AppEncryptionRequestDetails | + DataPacketResponse | + UserDataRequestDetails | + UserSpecificDataPacketDetails | + AppEncryptionResponseDetails; + +export type OrdinalVDXFObjectReservedDataJson = + DataDescriptorJson | + VerusPayInvoiceDetailsJson | + IdentityUpdateRequestDetailsJson | + IdentityUpdateResponseDetailsJson | + AuthenticationRequestDetailsJson | + AuthenticationResponseDetailsJson | + ProvisionIdentityDetailsJson | + AppEncryptionRequestJson | + DataResponseJson | + UserDataRequestJson | + UserSpecificDataPacketDetailsJson | + AppEncryptionResponseDetailsJson; + diff --git a/src/constants/pbaas.ts b/src/constants/pbaas.ts index ab77a689..62cc052f 100644 --- a/src/constants/pbaas.ts +++ b/src/constants/pbaas.ts @@ -1,5 +1,4 @@ import { BN } from "bn.js"; -import { toBase58Check } from "../utils/address"; export const DATA_TYPE_UNKNOWN = new BN("0", 10); export const DATA_TYPE_MMRDATA = new BN("1", 10); @@ -11,20 +10,23 @@ export const DATA_TYPE_BASE64 = new BN("6", 10); export const DATA_TYPE_DATAHASH = new BN("7", 10); export const DATA_TYPE_RAWSTRINGDATA = new BN("8", 10); -export const HASH_TYPE_SHA256 = new BN("1", 10); -export const HASH_TYPE_SHA256D = new BN("2", 10); -export const HASH_TYPE_BLAKE2B = new BN("3", 10); -export const HASH_TYPE_KECCAK256 = new BN("4", 10); +export const HASH_TYPE_INVALID = new BN(0, 10); +export const HASH_TYPE_BLAKE2B = new BN(1, 10); +export const HASH_TYPE_BLAKE2BMMR2 = new BN(2, 10); +export const HASH_TYPE_KECCAK256 = new BN(3, 10); +export const HASH_TYPE_SHA256D = new BN(4, 10); +export const HASH_TYPE_SHA256 = new BN(5, 10); + export const HASH_TYPE_SHA256_NAME = "sha256"; export const HASH_TYPE_SHA256D_NAME = "sha256D"; export const HASH_TYPE_BLAKE2B_NAME = "blake2b"; export const HASH_TYPE_KECCAK256_NAME = "keccak256"; + export const DEFAULT_HASH_TYPE = HASH_TYPE_SHA256; export const DEFAULT_HASH_TYPE_MMR = HASH_TYPE_BLAKE2B; export const HASH_NAMES = [HASH_TYPE_SHA256_NAME, HASH_TYPE_SHA256D_NAME, HASH_TYPE_BLAKE2B_NAME, HASH_TYPE_KECCAK256_NAME]; export type AllowedHashes = (typeof HASH_NAMES)[number]; - export const UINT_256_LENGTH = 32; export const DEFAULT_VERUS_CHAINID = "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV"; diff --git a/src/constants/vdxf.ts b/src/constants/vdxf.ts index 6971a058..7c6614b0 100644 --- a/src/constants/vdxf.ts +++ b/src/constants/vdxf.ts @@ -6,6 +6,7 @@ export const HASH160_BYTE_LENGTH = 20 export const HASH256_BYTE_LENGTH = 32 export const I_ADDR_VERSION = 102 export const R_ADDR_VERSION = 60 +export const X_ADDR_VERSION = 137 export const NULL_ADDRESS = "i3UXS5QPRQGNRDDqVnyWTnmFCTHDbzmsYk" const VERUS_DATA_SIGNATURE_PREFIX_STRING = "Verus signed data:\n" diff --git a/src/constants/vdxf/veruspay.ts b/src/constants/vdxf/veruspay.ts new file mode 100644 index 00000000..96b2614a --- /dev/null +++ b/src/constants/vdxf/veruspay.ts @@ -0,0 +1,11 @@ +import { BN } from "bn.js" + +export const VERUSPAY_VERSION_3 = new BN(3, 10) +export const VERUSPAY_VERSION_4 = new BN(4, 10) +export const VERUSPAY_VERSION_CURRENT = new BN(4, 10) + +export const VERUSPAY_VERSION_FIRSTVALID = new BN(3, 10) +export const VERUSPAY_VERSION_LASTVALID = new BN(4, 10) + +export const VERUSPAY_VERSION_SIGNED = new BN('80000000', 16) +export const VERUSPAY_VERSION_MASK = VERUSPAY_VERSION_SIGNED; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index ed2ab6a4..7ebdc057 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,9 +20,17 @@ export * from './pbaas/index' export * from './pbaas/PartialIdentity' export * from './pbaas/PartialMMRData' export * from './pbaas/PartialSignData' + export * from './constants/pbaas' +export * from './constants/ordinals/register' +export * from './constants/ordinals/ordinals' +export * from './constants/ordinals/types' +export * from './constants/vdxf/veruspay' +export * from './constants/deeplink' export * from './identity/IdentityDefinition' export * from './currency/CurrencyDefinition' +export * from './vdxf/classes' + export { BN as BigNumber } from 'bn.js' \ No newline at end of file diff --git a/src/pbaas/ContentMultiMapRemove.ts b/src/pbaas/ContentMultiMapRemove.ts index 64b0170d..47649e11 100644 --- a/src/pbaas/ContentMultiMapRemove.ts +++ b/src/pbaas/ContentMultiMapRemove.ts @@ -4,7 +4,7 @@ import { fromBase58Check, toBase58Check } from "../utils/address"; import bufferutils from '../utils/bufferutils' import { BN } from 'bn.js'; import { BigNumber } from '../utils/types/BigNumber'; -import { I_ADDR_VERSION } from '../constants/vdxf'; +import { HASH160_BYTE_LENGTH, I_ADDR_VERSION, HASH256_BYTE_LENGTH } from '../constants/vdxf'; import { SerializableEntity } from '../utils/types/SerializableEntity'; const { BufferReader, BufferWriter } = bufferutils @@ -45,9 +45,9 @@ export class ContentMultiMapRemove implements SerializableEntity { byteLength += varint.encodingLength(this.version); byteLength += varint.encodingLength(this.action); if (this.action != ContentMultiMapRemove.ACTION_CLEAR_MAP) { - byteLength += 20 + byteLength += HASH160_BYTE_LENGTH if (this.action != ContentMultiMapRemove.ACTION_REMOVE_ALL_KEY) { - byteLength += 32 + byteLength += HASH256_BYTE_LENGTH; } } return byteLength diff --git a/src/pbaas/Credential.ts b/src/pbaas/Credential.ts index e4d01ab5..40f8f081 100644 --- a/src/pbaas/Credential.ts +++ b/src/pbaas/Credential.ts @@ -3,7 +3,7 @@ import { BigNumber } from "../utils/types/BigNumber"; import { SerializableEntity } from "../utils/types/SerializableEntity"; import bufferutils from "../utils/bufferutils"; import varuint from "../utils/varuint"; -import { I_ADDR_VERSION, NULL_ADDRESS } from '../constants/vdxf'; +import { HASH160_BYTE_LENGTH, I_ADDR_VERSION, NULL_ADDRESS } from '../constants/vdxf'; import varint from '../utils/varint'; import { readLimitedString } from '../utils/string'; import { fromBase58Check, toBase58Check } from '../utils/address'; @@ -77,7 +77,7 @@ export class Credential implements SerializableEntity { length += varint.encodingLength(this.version); length += varint.encodingLength(this.flags); - length += 20 // Credential key + length += HASH160_BYTE_LENGTH; // Credential key // Both the credential and scopes are serialized as JSON strings. const credStr = JSON.stringify(this.credential); diff --git a/src/pbaas/CurrencyValueMap.ts b/src/pbaas/CurrencyValueMap.ts index 7a34aa99..8ae00a46 100644 --- a/src/pbaas/CurrencyValueMap.ts +++ b/src/pbaas/CurrencyValueMap.ts @@ -4,7 +4,7 @@ import { fromBase58Check, toBase58Check } from "../utils/address"; import bufferutils from '../utils/bufferutils' import { BN } from 'bn.js'; import { BigNumber } from '../utils/types/BigNumber'; -import { I_ADDR_VERSION } from '../constants/vdxf'; +import { HASH160_BYTE_LENGTH, I_ADDR_VERSION } from '../constants/vdxf'; import { SerializableEntity } from '../utils/types/SerializableEntity'; const { BufferReader, BufferWriter } = bufferutils import { bnToDecimal, decimalToBn } from '../utils/numberConversion'; @@ -29,7 +29,7 @@ export class CurrencyValueMap implements SerializableEntity { } for (const [key, value] of this.value_map) { - byteLength += 20 + byteLength += HASH160_BYTE_LENGTH byteLength += this.multivalue ? 8 : varint.encodingLength(value) } diff --git a/src/pbaas/DataDescriptor.ts b/src/pbaas/DataDescriptor.ts index 63889442..abed6818 100644 --- a/src/pbaas/DataDescriptor.ts +++ b/src/pbaas/DataDescriptor.ts @@ -8,6 +8,7 @@ import { VdxfUniValue } from '.'; import { BufferDataVdxfObject } from '../vdxf/index'; import * as VDXF_Data from '../vdxf/vdxfdatakeys'; import { SerializableEntity } from '../utils/types/SerializableEntity'; +import { HASH_TYPE_BLAKE2B, HASH_TYPE_BLAKE2BMMR2, HASH_TYPE_INVALID, HASH_TYPE_KECCAK256, HASH_TYPE_SHA256, HASH_TYPE_SHA256D } from '../constants/pbaas'; export interface DataDescriptorJson { version: number; @@ -428,12 +429,12 @@ export class VDXFDataDescriptor extends BufferDataVdxfObject { }; export enum EHashTypes { - HASH_INVALID = 0, - HASH_BLAKE2BMMR = 1, - HASH_BLAKE2BMMR2 = 2, - HASH_KECCAK = 3, - HASH_SHA256D = 4, - HASH_SHA256 = 5, - HASH_LASTTYPE = 5 + HASH_INVALID = HASH_TYPE_INVALID.toNumber(), + HASH_BLAKE2BMMR = HASH_TYPE_BLAKE2B.toNumber(), + HASH_BLAKE2BMMR2 = HASH_TYPE_BLAKE2BMMR2.toNumber(), + HASH_KECCAK = HASH_TYPE_KECCAK256.toNumber(), + HASH_SHA256D = HASH_TYPE_SHA256D.toNumber(), + HASH_SHA256 = HASH_TYPE_SHA256.toNumber(), + HASH_LASTTYPE = HASH_TYPE_SHA256.toNumber() }; diff --git a/src/pbaas/EvidenceData.ts b/src/pbaas/EvidenceData.ts index 6e37a366..7aea4d02 100644 --- a/src/pbaas/EvidenceData.ts +++ b/src/pbaas/EvidenceData.ts @@ -4,7 +4,7 @@ import { fromBase58Check, toBase58Check } from "../utils/address"; import bufferutils from '../utils/bufferutils' import { BN } from 'bn.js'; import { BigNumber } from '../utils/types/BigNumber'; -import { I_ADDR_VERSION } from '../constants/vdxf'; +import { HASH160_BYTE_LENGTH, I_ADDR_VERSION } from '../constants/vdxf'; import { SerializableEntity } from '../utils/types/SerializableEntity'; import * as VDXF_Data from '../vdxf/vdxfdatakeys'; @@ -97,7 +97,7 @@ export class EvidenceData implements SerializableEntity { if (this.type.eq(new BN(ETypes.TYPE_MULTIPART_DATA))) { byteLength += this.md.getByteLength(); } else { - byteLength += 20; + byteLength += HASH160_BYTE_LENGTH; } byteLength += varuint.encodingLength(this.data_vec.length); byteLength += this.data_vec.length; diff --git a/src/pbaas/Identity.ts b/src/pbaas/Identity.ts index 06ce9315..517a6b65 100644 --- a/src/pbaas/Identity.ts +++ b/src/pbaas/Identity.ts @@ -3,14 +3,13 @@ import bufferutils from '../utils/bufferutils' import { BigNumber } from '../utils/types/BigNumber'; import { Principal } from './Principal'; import { fromBase58Check, nameAndParentAddrToIAddr, toBase58Check } from '../utils/address'; -import { I_ADDR_VERSION, R_ADDR_VERSION } from '../constants/vdxf'; +import { I_ADDR_VERSION, R_ADDR_VERSION, HASH160_BYTE_LENGTH, HASH256_BYTE_LENGTH } from '../constants/vdxf'; import { BN } from 'bn.js'; import { IdentityID } from './IdentityID'; import { SaplingPaymentAddress } from './SaplingPaymentAddress'; import { ContentMultiMap, ContentMultiMapJson } from './ContentMultiMap'; import { SerializableEntity } from '../utils/types/SerializableEntity'; import { KeyID } from './KeyID'; -import { PartialSignDataCLIJson } from './PartialSignData'; export const IDENTITY_VERSION_VAULT = new BN(2, 10); export const IDENTITY_VERSION_PBAAS = new BN(3, 10); @@ -158,16 +157,16 @@ export class Identity extends Principal implements SerializableEntity { length += varuint.encodingLength(this.content_map.size); for (const m of this.content_map.entries()) { - length += 20; //uint160 key - length += 32; //uint256 hash + length += HASH160_BYTE_LENGTH; //uint160 key + length += HASH256_BYTE_LENGTH; } } length += varuint.encodingLength(this.content_map.size); for (const m of this.content_map.entries()) { - length += 20; //uint160 key - length += 32; //uint256 hash + length += HASH160_BYTE_LENGTH; //uint160 key + length += HASH256_BYTE_LENGTH; //uint256 hash } } @@ -425,7 +424,7 @@ export class Identity extends Principal implements SerializableEntity { unlockAfter = IDENTITY_MAX_UNLOCK_DELAY; } - this.flags = this.flags.xor(IDENTITY_FLAG_LOCKED); + this.flags = this.flags.or(IDENTITY_FLAG_LOCKED); this.unlock_after = unlockAfter; } @@ -446,7 +445,7 @@ export class Identity extends Principal implements SerializableEntity { } revoke() { - this.flags = this.flags.xor(IDENTITY_FLAG_REVOKED); + this.flags = this.flags.or(IDENTITY_FLAG_REVOKED); this.unlock(); } diff --git a/src/pbaas/IdentityMultimapRef.ts b/src/pbaas/IdentityMultimapRef.ts index 2dc14492..aa7bc192 100644 --- a/src/pbaas/IdentityMultimapRef.ts +++ b/src/pbaas/IdentityMultimapRef.ts @@ -4,7 +4,7 @@ import { fromBase58Check, toBase58Check } from "../utils/address"; import bufferutils from '../utils/bufferutils' import { BN } from 'bn.js'; import { BigNumber } from '../utils/types/BigNumber'; -import { I_ADDR_VERSION } from '../constants/vdxf'; +import { HASH160_BYTE_LENGTH, I_ADDR_VERSION, HASH256_BYTE_LENGTH } from '../constants/vdxf'; import { SerializableEntity } from '../utils/types/SerializableEntity'; const { BufferReader, BufferWriter } = bufferutils @@ -66,18 +66,18 @@ export class IdentityMultimapRef implements SerializableEntity { byteLength += varint.encodingLength(this.version); byteLength += varint.encodingLength(this.flags); - byteLength += 20; // id_ID uint160 - byteLength += 20; // key uint160 + byteLength += HASH160_BYTE_LENGTH; // id_ID + byteLength += HASH160_BYTE_LENGTH; // vdxfkey byteLength += varint.encodingLength(this.height_start); // height_start uint32 byteLength += varint.encodingLength(this.height_end); // height_end uint32 if (this.flags.and(IdentityMultimapRef.FLAG_HAS_DATAHASH).gt(new BN(0))) { - byteLength += 32; + byteLength += HASH256_BYTE_LENGTH; } if (this.flags.and(IdentityMultimapRef.FLAG_HAS_SYSTEM).gt(new BN(0))) { - byteLength += 20 + byteLength += HASH160_BYTE_LENGTH } return byteLength } diff --git a/src/pbaas/PBaaSEvidenceRef.ts b/src/pbaas/PBaaSEvidenceRef.ts index dd203d94..fe2e4508 100644 --- a/src/pbaas/PBaaSEvidenceRef.ts +++ b/src/pbaas/PBaaSEvidenceRef.ts @@ -4,7 +4,7 @@ import { fromBase58Check, toBase58Check } from "../utils/address"; import bufferutils from '../utils/bufferutils' import { BN } from 'bn.js'; import { BigNumber } from '../utils/types/BigNumber'; -import { I_ADDR_VERSION } from '../constants/vdxf'; +import { HASH160_BYTE_LENGTH, I_ADDR_VERSION } from '../constants/vdxf'; import { SerializableEntity } from '../utils/types/SerializableEntity'; import { UTXORef } from './UTXORef'; import { IdentityMultimapRef } from './IdentityMultimapRef'; @@ -64,7 +64,7 @@ export class PBaaSEvidenceRef implements SerializableEntity { byteLength += varint.encodingLength(this.sub_object); if (this.flags.and(PBaaSEvidenceRef.FLAG_HAS_SYSTEM).gt(new BN(0))) { - byteLength += 20; + byteLength += HASH160_BYTE_LENGTH; } return byteLength diff --git a/src/pbaas/PartialSignData.ts b/src/pbaas/PartialSignData.ts index 00877ccb..fa62ee2c 100644 --- a/src/pbaas/PartialSignData.ts +++ b/src/pbaas/PartialSignData.ts @@ -19,15 +19,15 @@ const { BufferReader, BufferWriter } = bufferutils; export type PartialSignDataInitData = { flags?: BigNumber; address?: IdentityID | KeyID; - prefixstring?: Buffer; - vdxfkeys?: Array; - vdxfkeynames?: Array; - boundhashes?: Array; - hashtype?: BigNumber; - encrypttoaddress?: SaplingPaymentAddress; - createmmr?: boolean; + prefixString?: Buffer; + vdxfKeys?: Array; + vdxfKeyNames?: Array; + boundHashes?: Array; + hashType?: BigNumber; + encryptToAddress?: SaplingPaymentAddress; + createMMR?: boolean; signature?: Buffer; - datatype?: BigNumber; + dataType?: BigNumber; data?: Buffer | PartialMMRData | VdxfUniValue; } @@ -72,15 +72,15 @@ type SignDataKeys = { // Base fields (always optional) type BaseFields = { address?: string; - prefixstring?: string; - vdxfkeys?: Array; - vdxfkeynames?: Array; - boundhashes?: Array; - hashtype?: string; - encrypttoaddress?: string; - createmmr?: boolean; + prefixString?: string; + vdxfKeys?: Array; + vdxfKeyNames?: Array; + boundHashes?: Array; + hashType?: string; + encryptToAddress?: string; + createMMR?: boolean; signature?: string; - datatype?: string; + dataType?: string; data?: string; }; @@ -102,16 +102,16 @@ export type PartialSignDataCLIJson = ( export class PartialSignData implements SerializableEntity { flags: BigNumber; address?: IdentityID | KeyID; - prefixstring?: Buffer; // UTF-8 Encoded prefix string - vdxfkeys?: Array; - vdxfkeynames?: Array; // UTF-8 Encoded vdxf key names - boundhashes?: Array; - hashtype?: BigNumber; - encrypttoaddress?: SaplingPaymentAddress; - createmmr?: boolean; + prefixString?: Buffer; // UTF-8 Encoded prefix string + vdxfKeys?: Array; + vdxfKeyNames?: Array; // UTF-8 Encoded vdxf key names + boundHashes?: Array; + hashType?: BigNumber; + encryptToAddress?: SaplingPaymentAddress; + createMMR?: boolean; signature?: Buffer; - datatype?: BigNumber; + dataType?: BigNumber; data?: Buffer | PartialMMRData | VdxfUniValue; static CONTAINS_DATA = new BN("1", 10); @@ -125,40 +125,40 @@ export class PartialSignData implements SerializableEntity { constructor(data?: PartialSignDataInitData) { this.flags = data && data.flags ? data.flags : new BN("0"); - this.createmmr = data && data.createmmr ? data.createmmr : false; + this.createMMR = data && data.createMMR ? data.createMMR : false; if (data?.address) { if (!this.containsAddress()) this.toggleContainsAddress(); this.address = data.address; } - if (data?.prefixstring) { + if (data?.prefixString) { if (!this.containsPrefixString()) this.toggleContainsPrefixString(); - this.prefixstring = data.prefixstring; + this.prefixString = data.prefixString; } - if (data?.vdxfkeys) { + if (data?.vdxfKeys) { if (!this.containsVdxfKeys()) this.toggleContainsVdxfKeys(); - this.vdxfkeys = data.vdxfkeys; + this.vdxfKeys = data.vdxfKeys; } - if (data?.vdxfkeynames) { + if (data?.vdxfKeyNames) { if (!this.containsVdxfKeyNames()) this.toggleContainsVdxfKeyNames(); - this.vdxfkeynames = data.vdxfkeynames; + this.vdxfKeyNames = data.vdxfKeyNames; } - if (data?.hashtype) { - this.hashtype = data.hashtype; - } else this.hashtype = DEFAULT_HASH_TYPE; + if (data?.hashType) { + this.hashType = data.hashType; + } else this.hashType = DEFAULT_HASH_TYPE; - if (data?.boundhashes) { + if (data?.boundHashes) { if (!this.containsBoundhashes()) this.toggleContainsBoundHashes(); - this.boundhashes = data.boundhashes; + this.boundHashes = data.boundHashes; } - if (data?.encrypttoaddress) { + if (data?.encryptToAddress) { if (!this.containsEncrypttoAddress()) this.toggleContainsEncryptToAddress(); - this.encrypttoaddress = data.encrypttoaddress; + this.encryptToAddress = data.encryptToAddress; } if (data?.signature) { @@ -166,10 +166,10 @@ export class PartialSignData implements SerializableEntity { this.signature = data.signature; } - if (data?.datatype && data?.data) { + if (data?.dataType && data?.data) { if (!this.containsData()) this.toggleContainsData(); this.data = data.data; - this.datatype = data.datatype; + this.dataType = data.dataType; } } @@ -238,11 +238,11 @@ export class PartialSignData implements SerializableEntity { } isMMRData(): boolean { - return this.datatype && this.datatype.eq(DATA_TYPE_MMRDATA); + return this.dataType && this.dataType.eq(DATA_TYPE_MMRDATA); } isVdxfData(): boolean { - return this.datatype && this.datatype.eq(DATA_TYPE_VDXFDATA); + return this.dataType && this.dataType.eq(DATA_TYPE_VDXFDATA); } private getPartialSignDataByteLength(): number { @@ -263,39 +263,39 @@ export class PartialSignData implements SerializableEntity { let length = 0; - length += varint.encodingLength(this.flags); + length += varuint.encodingLength(this.flags.toNumber()); if (this.containsAddress()) length += this.address!.getByteLength(); if (this.containsPrefixString()) { - const prefixLen = this.prefixstring!.length; + const prefixLen = this.prefixString!.length; length += varuint.encodingLength(prefixLen); length += prefixLen; } if (this.containsVdxfKeys()) { - length += calculateVectorLength(this.vdxfkeys!, (vdxfkey) => vdxfkey.getByteLength(), false); + length += calculateVectorLength(this.vdxfKeys!, (vdxfkey) => vdxfkey.getByteLength(), false); } if (this.containsVdxfKeyNames()) { - length += calculateVectorLength(this.vdxfkeynames!, (vdxfname) => vdxfname.length); + length += calculateVectorLength(this.vdxfKeyNames!, (vdxfname) => vdxfname.length); } - length += varint.encodingLength(this.hashtype); + length += varuint.encodingLength(this.hashType.toNumber()); if (this.containsBoundhashes()) { - length += calculateVectorLength(this.boundhashes!, (hash) => hash.length); + length += calculateVectorLength(this.boundHashes!, (hash) => hash.length); } if (this.containsEncrypttoAddress()) { - length += this.encrypttoaddress!.getByteLength(); + length += this.encryptToAddress!.getByteLength(); } length += 1; // Createmmr boolean value if (this.containsData()) { - length += varint.encodingLength(this.datatype!); + length += varuint.encodingLength(this.dataType!.toNumber()); if (this.isMMRData()) { length += (this.data as PartialMMRData).getByteLength(); @@ -322,7 +322,7 @@ export class PartialSignData implements SerializableEntity { fromBuffer(buffer: Buffer, offset: number = 0): number { const reader = new BufferReader(buffer, offset); - this.flags = reader.readVarInt(); + this.flags = new BN(reader.readCompactSize()); if (this.containsAddress()) { const hash160 = new Hash160SerEnt(); @@ -337,12 +337,12 @@ export class PartialSignData implements SerializableEntity { } if (this.containsPrefixString()) { - this.prefixstring = reader.readVarSlice(); + this.prefixString = reader.readVarSlice(); } if (this.containsVdxfKeys()) { const count = reader.readCompactSize(); - this.vdxfkeys = []; + this.vdxfKeys = []; for (let i = 0; i < count; i++) { const varSlice = reader.readSlice(HASH160_BYTE_LENGTH); @@ -350,18 +350,18 @@ export class PartialSignData implements SerializableEntity { const idId = new IdentityID(); idId.fromBuffer(varSlice); - this.vdxfkeys.push(idId); + this.vdxfKeys.push(idId); } } if (this.containsVdxfKeyNames()) { - this.vdxfkeynames = reader.readVector(); + this.vdxfKeyNames = reader.readVector(); } - this.hashtype = reader.readVarInt(); + this.hashType = new BN(reader.readCompactSize()); if (this.containsBoundhashes()) { - this.boundhashes = reader.readVector(); + this.boundHashes = reader.readVector(); } if (this.containsEncrypttoAddress()) { @@ -369,13 +369,13 @@ export class PartialSignData implements SerializableEntity { reader.offset = saplingAddr.fromBuffer(reader.buffer, reader.offset); - this.encrypttoaddress = saplingAddr; + this.encryptToAddress = saplingAddr; } - this.createmmr = !!reader.readUInt8(); + this.createMMR = !!reader.readUInt8(); if (this.containsData()) { - this.datatype = reader.readVarInt(); + this.dataType = new BN(reader.readCompactSize()); if (this.isMMRData()) { const partialMMRData = new PartialMMRData(); @@ -403,7 +403,7 @@ export class PartialSignData implements SerializableEntity { const writer = new BufferWriter(Buffer.alloc(this.getPartialSignDataByteLength())); // Serialize flags - writer.writeVarInt(this.flags); + writer.writeCompactSize(this.flags.toNumber()); // Address if (this.containsAddress()) { @@ -415,60 +415,60 @@ export class PartialSignData implements SerializableEntity { // Prefix string if (this.containsPrefixString()) { - if (!this.prefixstring) { + if (!this.prefixString) { throw new Error("Prefix string is required but not provided"); } - writer.writeVarSlice(this.prefixstring); + writer.writeVarSlice(this.prefixString); } // VDXF keys if (this.containsVdxfKeys()) { - if (!this.vdxfkeys) { + if (!this.vdxfKeys) { throw new Error("VDXF keys are required but not provided"); } - writer.writeCompactSize(this.vdxfkeys.length); + writer.writeCompactSize(this.vdxfKeys.length); - for (const vdxfkey of this.vdxfkeys) { + for (const vdxfkey of this.vdxfKeys) { writer.writeSlice(vdxfkey.toBuffer()); } } // VDXF key names if (this.containsVdxfKeyNames()) { - if (!this.vdxfkeynames) { + if (!this.vdxfKeyNames) { throw new Error("VDXF key names are required but not provided"); } - writer.writeVector(this.vdxfkeynames); + writer.writeVector(this.vdxfKeyNames); } - writer.writeVarInt(this.hashtype); + writer.writeCompactSize(this.hashType.toNumber()); // Bound hashes if (this.containsBoundhashes()) { - if (!this.boundhashes) { + if (!this.boundHashes) { throw new Error("Bound hashes are required but not provided"); } - writer.writeVector(this.boundhashes); + writer.writeVector(this.boundHashes); } // Encrypt-to address (Sapling) if (this.containsEncrypttoAddress()) { - if (!this.encrypttoaddress || !(this.encrypttoaddress instanceof SaplingPaymentAddress)) { + if (!this.encryptToAddress || !(this.encryptToAddress instanceof SaplingPaymentAddress)) { throw new Error("Sapling payment address is required but not provided"); } - writer.writeSlice(this.encrypttoaddress.toBuffer()); + writer.writeSlice(this.encryptToAddress.toBuffer()); } - // createmmr (boolean) - writer.writeUInt8(this.createmmr ? 1 : 0); + // createMMR (boolean) + writer.writeUInt8(this.createMMR ? 1 : 0); // Data if (this.containsData()) { - if (!this.data || !this.datatype) { + if (!this.data || !this.dataType) { throw new Error("Data is required but not provided"); } - writer.writeVarInt(this.datatype); + writer.writeCompactSize(this.dataType.toNumber()); if (this.isMMRData()) { const mmrData = this.data as PartialMMRData; @@ -490,15 +490,15 @@ export class PartialSignData implements SerializableEntity { return { flags: this.flags ? this.flags.toString(10) : undefined, address: this.address ? this.address.toAddress() : undefined, - prefixstring: this.prefixstring ? this.prefixstring.toString('utf-8') : undefined, - vdxfkeys: this.vdxfkeys ? this.vdxfkeys.map(x => x.toAddress()) : undefined, - vdxfkeynames: this.vdxfkeynames ? this.vdxfkeynames.map(x => x.toString('utf-8')) : undefined, - boundhashes: this.boundhashes ? this.boundhashes.map(x => x.toString('hex')) : undefined, - hashtype: this.hashtype ? this.hashtype.toString(10) : undefined, - encrypttoaddress: this.encrypttoaddress ? this.encrypttoaddress.toAddressString() : undefined, - createmmr: this.createmmr, + prefixstring: this.prefixString ? this.prefixString.toString('utf-8') : undefined, + vdxfkeys: this.vdxfKeys ? this.vdxfKeys.map(x => x.toAddress()) : undefined, + vdxfkeynames: this.vdxfKeyNames ? this.vdxfKeyNames.map(x => x.toString('utf-8')) : undefined, + boundhashes: this.boundHashes ? this.boundHashes.map(x => x.toString('hex')) : undefined, + hashtype: this.hashType ? this.hashType.toString(10) : undefined, + encrypttoaddress: this.encryptToAddress ? this.encryptToAddress.toAddressString() : undefined, + createmmr: this.createMMR, signature: this.signature ? this.signature.toString('base64') : undefined, - datatype: this.datatype ? this.datatype.toString(10) : undefined, + datatype: this.dataType ? this.dataType.toString(10) : undefined, data: this.data ? this.data instanceof PartialMMRData ? this.data.toJson() : this.data.toString('hex') : undefined } } @@ -516,25 +516,25 @@ export class PartialSignData implements SerializableEntity { } else throw new Error("Unrecognized address version"); } - const datatype = json.datatype ? new BN(json.datatype, 10) : undefined; + const dataType = json.datatype ? new BN(json.datatype, 10) : undefined; return new PartialSignData({ flags: json.flags ? new BN(json.flags, 10) : undefined, address: addr, - prefixstring: json.prefixstring ? Buffer.from(json.prefixstring, 'utf-8') : undefined, - vdxfkeys: json.vdxfkeys ? json.vdxfkeys.map(x => IdentityID.fromAddress(x)) : undefined, - vdxfkeynames: json.vdxfkeynames ? json.vdxfkeynames.map(x => Buffer.from(x, 'utf-8')) : undefined, - boundhashes: json.boundhashes ? json.boundhashes.map(x => Buffer.from(x, 'hex')) : undefined, - hashtype: json.hashtype ? new BN(json.hashtype, 10) : undefined, - encrypttoaddress: json.encrypttoaddress ? SaplingPaymentAddress.fromAddressString(json.encrypttoaddress) : undefined, - createmmr: json.createmmr, + prefixString: json.prefixstring ? Buffer.from(json.prefixstring, 'utf-8') : undefined, + vdxfKeys: json.vdxfkeys ? json.vdxfkeys.map(x => IdentityID.fromAddress(x)) : undefined, + vdxfKeyNames: json.vdxfkeynames ? json.vdxfkeynames.map(x => Buffer.from(x, 'utf-8')) : undefined, + boundHashes: json.boundhashes ? json.boundhashes.map(x => Buffer.from(x, 'hex')) : undefined, + hashType: json.hashtype ? new BN(json.hashtype, 10) : undefined, + encryptToAddress: json.encrypttoaddress ? SaplingPaymentAddress.fromAddressString(json.encrypttoaddress) : undefined, + createMMR: json.createmmr, signature: json.signature ? Buffer.from(json.signature, 'base64') : undefined, - datatype: json.datatype ? new BN(json.datatype, 10) : undefined, + dataType: json.datatype ? new BN(json.datatype, 10) : undefined, data: json.data ? typeof json.data === 'string' ? Buffer.from(json.data, 'hex') : - datatype && datatype.eq(DATA_TYPE_MMRDATA) ? + dataType && dataType.eq(DATA_TYPE_MMRDATA) ? PartialMMRData.fromJson(json.data as PartialMMRDataJson) : VdxfUniValue.fromJson(json.data as VdxfUniValueJson) @@ -546,24 +546,24 @@ export class PartialSignData implements SerializableEntity { toCLIJson(): PartialSignDataCLIJson { const ret: PartialSignDataCLIJson = { address: this.address ? this.address.toAddress() : undefined, - prefixstring: this.prefixstring ? this.prefixstring.toString('utf-8') : undefined, - vdxfkeys: this.vdxfkeys ? this.vdxfkeys.map(x => x.toAddress()) : undefined, - vdxfkeynames: this.vdxfkeynames ? this.vdxfkeynames.map(x => x.toString('utf-8')) : undefined, - boundhashes: this.boundhashes ? this.boundhashes.map(x => x.toString('hex')) : undefined, - encrypttoaddress: this.encrypttoaddress ? this.encrypttoaddress.toAddressString() : undefined, - createmmr: this.createmmr, + prefixString: this.prefixString ? this.prefixString.toString('utf-8') : undefined, + vdxfKeys: this.vdxfKeys ? this.vdxfKeys.map(x => x.toAddress()) : undefined, + vdxfKeyNames: this.vdxfKeyNames ? this.vdxfKeyNames.map(x => x.toString('utf-8')) : undefined, + boundHashes: this.boundHashes ? this.boundHashes.map(x => x.toString('hex')) : undefined, + encryptToAddress: this.encryptToAddress ? this.encryptToAddress.toAddressString() : undefined, + createMMR: this.createMMR, signature: this.signature ? this.signature.toString('base64') : undefined }; - if (this.containsData() && this.data && this.datatype) { - if (this.datatype.eq(DATA_TYPE_MMRDATA)) { + if (this.containsData() && this.data && this.dataType) { + if (this.dataType.eq(DATA_TYPE_MMRDATA)) { const mmrCLIJson = (this.data as PartialMMRData).toCLIJson(); ret['mmrdata'] = mmrCLIJson.mmrdata; ret['mmrsalt'] = mmrCLIJson.mmrsalt; ret['mmrhashtype'] = mmrCLIJson.mmrhashtype; ret['priormmr'] = mmrCLIJson.priormmr; - } else if (this.datatype.eq(DATA_TYPE_VDXFDATA)) { + } else if (this.dataType.eq(DATA_TYPE_VDXFDATA)) { const uniJson = (this.data as VdxfUniValue).toJson(); if (Array.isArray(uniJson)) throw new Error("VDXF univalue arrays not supported as sign data param") @@ -572,28 +572,28 @@ export class PartialSignData implements SerializableEntity { } else { const dataBuf = this.data as Buffer; - if (this.datatype.eq(DATA_TYPE_FILENAME)){ + if (this.dataType.eq(DATA_TYPE_FILENAME)){ ret['filename'] = dataBuf.toString('utf-8'); - } else if (this.datatype.eq(DATA_TYPE_MESSAGE)) { + } else if (this.dataType.eq(DATA_TYPE_MESSAGE)) { ret['message'] = dataBuf.toString('utf-8'); - } else if (this.datatype.eq(DATA_TYPE_HEX)) { + } else if (this.dataType.eq(DATA_TYPE_HEX)) { ret['messagehex'] = dataBuf.toString('hex'); - } else if (this.datatype.eq(DATA_TYPE_BASE64)) { + } else if (this.dataType.eq(DATA_TYPE_BASE64)) { ret['messagebase64'] = dataBuf.toString('base64'); - } else if (this.datatype.eq(DATA_TYPE_DATAHASH)) { + } else if (this.dataType.eq(DATA_TYPE_DATAHASH)) { ret['datahash'] = dataBuf.toString('hex'); - } else throw new Error("Unrecognized datatype"); + } else throw new Error("Unrecognized dataType"); } } - if (this.hashtype.eq(HASH_TYPE_SHA256)){ - ret['hashtype'] = HASH_TYPE_SHA256_NAME; - } else if (this.hashtype.eq(HASH_TYPE_SHA256D)) { - ret['hashtype'] = HASH_TYPE_SHA256D_NAME; - } else if (this.hashtype.eq(HASH_TYPE_BLAKE2B)) { - ret['hashtype'] = HASH_TYPE_BLAKE2B_NAME; - } else if (this.hashtype.eq(HASH_TYPE_KECCAK256)) { - ret['hashtype'] = HASH_TYPE_KECCAK256_NAME; + if (this.hashType.eq(HASH_TYPE_SHA256)){ + ret['hashType'] = HASH_TYPE_SHA256_NAME; + } else if (this.hashType.eq(HASH_TYPE_SHA256D)) { + ret['hashType'] = HASH_TYPE_SHA256D_NAME; + } else if (this.hashType.eq(HASH_TYPE_BLAKE2B)) { + ret['hashType'] = HASH_TYPE_BLAKE2B_NAME; + } else if (this.hashType.eq(HASH_TYPE_KECCAK256)) { + ret['hashType'] = HASH_TYPE_KECCAK256_NAME; } else throw new Error("Unrecognized hash type"); for (const key in ret) { @@ -618,12 +618,12 @@ export class PartialSignData implements SerializableEntity { const config: PartialSignDataInitData = { address: addr, - prefixstring: json.prefixstring ? Buffer.from(json.prefixstring, 'utf-8') : undefined, - vdxfkeys: json.vdxfkeys ? json.vdxfkeys.map(x => IdentityID.fromAddress(x)) : undefined, - vdxfkeynames: json.vdxfkeynames ? json.vdxfkeynames.map(x => Buffer.from(x, 'utf-8')) : undefined, - boundhashes: json.boundhashes ? json.boundhashes.map(x => Buffer.from(x, 'hex')) : undefined, - encrypttoaddress: json.encrypttoaddress ? SaplingPaymentAddress.fromAddressString(json.encrypttoaddress) : undefined, - createmmr: json.createmmr, + prefixString: json.prefixString ? Buffer.from(json.prefixString, 'utf-8') : undefined, + vdxfKeys: json.vdxfKeys ? json.vdxfKeys.map(x => IdentityID.fromAddress(x)) : undefined, + vdxfKeyNames: json.vdxfKeyNames ? json.vdxfKeyNames.map(x => Buffer.from(x, 'utf-8')) : undefined, + boundHashes: json.boundHashes ? json.boundHashes.map(x => Buffer.from(x, 'hex')) : undefined, + encryptToAddress: json.encryptToAddress ? SaplingPaymentAddress.fromAddressString(json.encryptToAddress) : undefined, + createMMR: json.createMMR, signature: json.signature ? Buffer.from(json.signature, 'base64') : undefined }; @@ -636,40 +636,40 @@ export class PartialSignData implements SerializableEntity { }) config.data = pmd; - config.datatype = DATA_TYPE_MMRDATA; + config.dataType = DATA_TYPE_MMRDATA; } else if (json.filename) { config.data = Buffer.from(json.filename, 'utf-8'); - config.datatype = DATA_TYPE_FILENAME; + config.dataType = DATA_TYPE_FILENAME; } else if (json.message) { config.data = Buffer.from(json.message, 'utf-8'); - config.datatype = DATA_TYPE_MESSAGE; + config.dataType = DATA_TYPE_MESSAGE; } else if (json.vdxfdata) { config.data = VdxfUniValue.fromJson(json.vdxfdata); - config.datatype = DATA_TYPE_VDXFDATA; + config.dataType = DATA_TYPE_VDXFDATA; } else if (json.messagehex) { config.data = Buffer.from(json.messagehex, 'hex'); - config.datatype = DATA_TYPE_HEX; + config.dataType = DATA_TYPE_HEX; } else if (json.messagebase64) { config.data = Buffer.from(json.messagebase64, 'base64'); - config.datatype = DATA_TYPE_BASE64; + config.dataType = DATA_TYPE_BASE64; } else if (json.datahash) { config.data = Buffer.from(json.datahash, 'hex'); - config.datatype = DATA_TYPE_DATAHASH; + config.dataType = DATA_TYPE_DATAHASH; } - if (json.hashtype) { - switch (json.hashtype) { + if (json.hashType) { + switch (json.hashType) { case HASH_TYPE_SHA256_NAME: - config.hashtype = HASH_TYPE_SHA256; + config.hashType = HASH_TYPE_SHA256; break; case HASH_TYPE_SHA256D_NAME: - config.hashtype = HASH_TYPE_SHA256D; + config.hashType = HASH_TYPE_SHA256D; break; case HASH_TYPE_BLAKE2B_NAME: - config.hashtype = HASH_TYPE_BLAKE2B; + config.hashType = HASH_TYPE_BLAKE2B; break; case HASH_TYPE_KECCAK256_NAME: - config.hashtype = HASH_TYPE_KECCAK256; + config.hashType = HASH_TYPE_KECCAK256; break; default: throw new Error("Unrecognized hash type"); diff --git a/src/pbaas/Rating.ts b/src/pbaas/Rating.ts index 3e0ff7b5..d6015bca 100644 --- a/src/pbaas/Rating.ts +++ b/src/pbaas/Rating.ts @@ -3,7 +3,7 @@ import { fromBase58Check, toBase58Check } from "../utils/address"; import bufferutils from '../utils/bufferutils' import { BN } from 'bn.js'; import { BigNumber } from '../utils/types/BigNumber'; -import { I_ADDR_VERSION } from '../constants/vdxf'; +import { HASH160_BYTE_LENGTH, I_ADDR_VERSION } from '../constants/vdxf'; import { SerializableEntity } from '../utils/types/SerializableEntity'; const { BufferReader, BufferWriter } = bufferutils @@ -43,7 +43,7 @@ export class Rating implements SerializableEntity { byteLength += varuint.encodingLength(this.ratings.size); for (const [key, value] of this.ratings) { - byteLength += 20 + byteLength += HASH160_BYTE_LENGTH byteLength += varuint.encodingLength(value.length) byteLength += value.length diff --git a/src/pbaas/SaltedData.ts b/src/pbaas/SaltedData.ts index e0646317..4d62af9d 100644 --- a/src/pbaas/SaltedData.ts +++ b/src/pbaas/SaltedData.ts @@ -4,7 +4,7 @@ import { fromBase58Check, toBase58Check } from "../utils/address"; import bufferutils from '../utils/bufferutils' import { BN } from 'bn.js'; import { BigNumber } from '../utils/types/BigNumber'; -import { I_ADDR_VERSION } from '../constants/vdxf'; +import { HASH160_BYTE_LENGTH, I_ADDR_VERSION } from '../constants/vdxf'; import { VDXFData } from '../vdxf/index'; const { BufferReader, BufferWriter } = bufferutils const createHash = require("create-hash"); @@ -51,7 +51,7 @@ export class SaltedData extends VDXFData { getByteLength() { let byteLength = 0; - byteLength += 20; //key + byteLength += HASH160_BYTE_LENGTH; // vdxfkey byteLength += varint.encodingLength(this.version); byteLength += varuint.encodingLength(this.data.length + this.salt.length); byteLength += this.data.length + this.salt.length; diff --git a/src/pbaas/SaplingExtendedSpendingKey.ts b/src/pbaas/SaplingExtendedSpendingKey.ts new file mode 100644 index 00000000..d025eb11 --- /dev/null +++ b/src/pbaas/SaplingExtendedSpendingKey.ts @@ -0,0 +1,90 @@ +import bufferutils from '../utils/bufferutils'; +import { decodeSaplingExtendedSpendingKey, encodeSaplingExtendedSpendingKey } from '../utils/sapling'; +import { SerializableEntity } from '../utils/types/SerializableEntity'; + +const { BufferReader, BufferWriter } = bufferutils; + +export class SaplingExtendedSpendingKey implements SerializableEntity { + depth: number; + parentFVKTag: Buffer; // 4 bytes + childIndex: Buffer; // 4 bytes + chainCode: Buffer; // 32 bytes + ask: Buffer; // 32 bytes + nsk: Buffer; // 32 bytes + ovk: Buffer; // 32 bytes + dk: Buffer; // 32 bytes + + constructor(data?: { + depth?: number; + parentFVKTag?: Buffer; + childIndex?: Buffer; + chainCode?: Buffer; + ask?: Buffer; + nsk?: Buffer; + ovk?: Buffer; + dk?: Buffer; + }) { + if (data != null) { + this.depth = data.depth ?? 0; + this.parentFVKTag = data.parentFVKTag ?? Buffer.alloc(4); + this.childIndex = data.childIndex ?? Buffer.alloc(4); + this.chainCode = data.chainCode ?? Buffer.alloc(32); + this.ask = data.ask ?? Buffer.alloc(32); + this.nsk = data.nsk ?? Buffer.alloc(32); + this.ovk = data.ovk ?? Buffer.alloc(32); + this.dk = data.dk ?? Buffer.alloc(32); + } + } + + getByteLength() { + return 1 + 4 + 4 + 32 + 32 + 32 + 32 + 32; // 169 bytes total + } + + toBuffer() { + const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); + + writer.writeUInt8(this.depth); + writer.writeSlice(this.parentFVKTag); + writer.writeSlice(this.childIndex); + writer.writeSlice(this.chainCode); + writer.writeSlice(this.ask); + writer.writeSlice(this.nsk); + writer.writeSlice(this.ovk); + writer.writeSlice(this.dk); + + return writer.buffer; + } + + fromBuffer(buffer: Buffer, offset: number = 0) { + const reader = new BufferReader(buffer, offset); + + this.depth = reader.readUInt8(); + this.parentFVKTag = reader.readSlice(4); + this.childIndex = reader.readSlice(4); + this.chainCode = reader.readSlice(32); + this.ask = reader.readSlice(32); + this.nsk = reader.readSlice(32); + this.ovk = reader.readSlice(32); + this.dk = reader.readSlice(32); + + return reader.offset; + } + + static fromKeyString(key: string): SaplingExtendedSpendingKey { + const decoded = decodeSaplingExtendedSpendingKey(key); + return new SaplingExtendedSpendingKey(decoded); + } + + toKeyString(testnet: boolean = false): string { + return encodeSaplingExtendedSpendingKey({ + depth: this.depth, + parentFVKTag: this.parentFVKTag, + childIndex: this.childIndex, + chainCode: this.chainCode, + ask: this.ask, + nsk: this.nsk, + ovk: this.ovk, + dk: this.dk + }, testnet); + } +} diff --git a/src/pbaas/SaplingExtendedViewingKey.ts b/src/pbaas/SaplingExtendedViewingKey.ts new file mode 100644 index 00000000..2ef8fd8e --- /dev/null +++ b/src/pbaas/SaplingExtendedViewingKey.ts @@ -0,0 +1,90 @@ +import bufferutils from '../utils/bufferutils'; +import { decodeSaplingExtendedViewingKey, encodeSaplingExtendedViewingKey } from '../utils/sapling'; +import { SerializableEntity } from '../utils/types/SerializableEntity'; + +const { BufferReader, BufferWriter } = bufferutils; + +export class SaplingExtendedViewingKey implements SerializableEntity { + depth: number; + parentFVKTag: Buffer; // 4 bytes + childIndex: Buffer; // 4 bytes + chainCode: Buffer; // 32 bytes + ak: Buffer; // 32 bytes + nk: Buffer; // 32 bytes + ovk: Buffer; // 32 bytes + dk: Buffer; // 32 bytes + + constructor(data?: { + depth?: number; + parentFVKTag?: Buffer; + childIndex?: Buffer; + chainCode?: Buffer; + ak?: Buffer; + nk?: Buffer; + ovk?: Buffer; + dk?: Buffer; + }) { + if (data != null) { + this.depth = data.depth ?? 0; + this.parentFVKTag = data.parentFVKTag ?? Buffer.alloc(4); + this.childIndex = data.childIndex ?? Buffer.alloc(4); + this.chainCode = data.chainCode ?? Buffer.alloc(32); + this.ak = data.ak ?? Buffer.alloc(32); + this.nk = data.nk ?? Buffer.alloc(32); + this.ovk = data.ovk ?? Buffer.alloc(32); + this.dk = data.dk ?? Buffer.alloc(32); + } + } + + getByteLength() { + return 1 + 4 + 4 + 32 + 32 + 32 + 32 + 32; // 169 bytes total + } + + toBuffer() { + const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); + + writer.writeUInt8(this.depth); + writer.writeSlice(this.parentFVKTag); + writer.writeSlice(this.childIndex); + writer.writeSlice(this.chainCode); + writer.writeSlice(this.ak); + writer.writeSlice(this.nk); + writer.writeSlice(this.ovk); + writer.writeSlice(this.dk); + + return writer.buffer; + } + + fromBuffer(buffer: Buffer, offset: number = 0) { + const reader = new BufferReader(buffer, offset); + + this.depth = reader.readUInt8(); + this.parentFVKTag = reader.readSlice(4); + this.childIndex = reader.readSlice(4); + this.chainCode = reader.readSlice(32); + this.ak = reader.readSlice(32); + this.nk = reader.readSlice(32); + this.ovk = reader.readSlice(32); + this.dk = reader.readSlice(32); + + return reader.offset; + } + + static fromKeyString(key: string): SaplingExtendedViewingKey { + const decoded = decodeSaplingExtendedViewingKey(key); + return new SaplingExtendedViewingKey(decoded); + } + + toKeyString(testnet: boolean = false): string { + return encodeSaplingExtendedViewingKey({ + depth: this.depth, + parentFVKTag: this.parentFVKTag, + childIndex: this.childIndex, + chainCode: this.chainCode, + ak: this.ak, + nk: this.nk, + ovk: this.ovk, + dk: this.dk + }, testnet); + } +} diff --git a/src/pbaas/SignatureData.ts b/src/pbaas/SignatureData.ts index da386e01..02414cf5 100644 --- a/src/pbaas/SignatureData.ts +++ b/src/pbaas/SignatureData.ts @@ -4,7 +4,7 @@ import { fromBase58Check, toBase58Check } from "../utils/address"; import bufferutils from '../utils/bufferutils' import { BN } from 'bn.js'; import { BigNumber } from '../utils/types/BigNumber'; -import { I_ADDR_VERSION } from '../constants/vdxf'; +import { HASH160_BYTE_LENGTH, I_ADDR_VERSION } from '../constants/vdxf'; import { SerializableEntity } from '../utils/types/SerializableEntity'; import { EHashTypes } from './DataDescriptor'; const { BufferReader, BufferWriter } = bufferutils @@ -115,11 +115,11 @@ export class SignatureData implements SerializableEntity { let byteLength = 0; byteLength += varint.encodingLength(this.version); - byteLength += 20; // system_ID uint160 + byteLength += HASH160_BYTE_LENGTH; // system_ID uint160 byteLength += varint.encodingLength(this.hash_type); byteLength += varuint.encodingLength(this.signature_hash.length); byteLength += this.signature_hash.length; - byteLength += 20; // identity_ID uint160 + byteLength += HASH160_BYTE_LENGTH; // identity_ID uint160 byteLength += varint.encodingLength(this.sig_type); byteLength += varuint.encodingLength(this.vdxf_keys.length); byteLength += this.vdxf_keys.length * 20; @@ -240,7 +240,8 @@ export class SignatureData implements SerializableEntity { return returnObj; } - getIdentityHash(sigObject: { version: number, hash_type: number, height: number }) { + // To fully implement, refer to VerusCoin/src/pbaas/crosschainrpc.cpp line 337, IdentitySignatureHash + getIdentityHash(sigObject: { version: number, hash_type: number, height: number }): Buffer { var heightBuffer = Buffer.allocUnsafe(4) heightBuffer.writeUInt32LE(sigObject.height); diff --git a/src/pbaas/URLRef.ts b/src/pbaas/URLRef.ts index 4324d719..06222502 100644 --- a/src/pbaas/URLRef.ts +++ b/src/pbaas/URLRef.ts @@ -4,7 +4,7 @@ import { fromBase58Check, toBase58Check } from "../utils/address"; import bufferutils from '../utils/bufferutils' import { BN } from 'bn.js'; import { BigNumber } from '../utils/types/BigNumber'; -import { I_ADDR_VERSION } from '../constants/vdxf'; +import { HASH256_BYTE_LENGTH } from '../constants/vdxf'; import { SerializableEntity } from '../utils/types/SerializableEntity'; const { BufferReader, BufferWriter } = bufferutils @@ -52,7 +52,7 @@ export class URLRef implements SerializableEntity { if( this.flags.and(URLRef.FLAG_HAS_HASH).eq(URLRef.FLAG_HAS_HASH) ) { // If the FLAG_HAS_HASH is set, we include the data hash - byteLength += 32; // 32 bytes for the hash + byteLength += HASH256_BYTE_LENGTH; // 32 bytes for the hash } } diff --git a/src/pbaas/UTXORef.ts b/src/pbaas/UTXORef.ts index 18811f05..d5a5b127 100644 --- a/src/pbaas/UTXORef.ts +++ b/src/pbaas/UTXORef.ts @@ -1,10 +1,7 @@ -import varint from '../utils/varint' -import varuint from '../utils/varuint' -import { fromBase58Check, toBase58Check } from "../utils/address"; import bufferutils from '../utils/bufferutils' import { BN } from 'bn.js'; import { BigNumber } from '../utils/types/BigNumber'; -import { I_ADDR_VERSION } from '../constants/vdxf'; +import { HASH256_BYTE_LENGTH } from '../constants/vdxf'; import { SerializableEntity } from '../utils/types/SerializableEntity'; const { BufferReader, BufferWriter } = bufferutils @@ -21,7 +18,7 @@ export class UTXORef implements SerializableEntity { getByteLength() { let byteLength = 0; - byteLength += 32; // hash uint256 + byteLength += HASH256_BYTE_LENGTH; // hash uint256 byteLength += 4; // n uint32 return byteLength diff --git a/src/utils/address.ts b/src/utils/address.ts index 067bf111..1355bb14 100644 --- a/src/utils/address.ts +++ b/src/utils/address.ts @@ -1,5 +1,5 @@ import { DEFAULT_VERUS_CHAINID, DEFAULT_VERUS_CHAINNAME, KOMODO_ASSETCHAIN_MAXLEN, NULL_I_ADDR } from "../constants/pbaas"; -import { I_ADDR_VERSION } from "../constants/vdxf"; +import { I_ADDR_VERSION, X_ADDR_VERSION } from "../constants/vdxf"; import { hash, hash160 } from "./hash"; import { toLowerCaseCLocale } from "./tolower"; @@ -41,7 +41,7 @@ export const toBase58Check = (hash: Buffer, version: number): string => { return bs58check.encode(payload); }; -export const nameAndParentAddrToIAddr = (name: string, parentIAddr?: string): string => { +export const nameAndParentAddrToAddr = (name: string, parentIAddr?: string, version: number = I_ADDR_VERSION): string => { let idHash: Buffer; const nameBuffer = Buffer.from(toLowerCaseCLocale(name), "utf8"); @@ -52,10 +52,14 @@ export const nameAndParentAddrToIAddr = (name: string, parentIAddr?: string): st idHash = hash(fromBase58Check(parentIAddr).hash, idHash); } - return toBase58Check(hash160(idHash), 102); + return toBase58Check(hash160(idHash), version); } -export const toIAddress = (fullyqualifiedname: string, rootSystemName: string = ""): string => { +export const nameAndParentAddrToIAddr = (name: string, parentIAddr?: string): string => { + return nameAndParentAddrToAddr(name, parentIAddr, I_ADDR_VERSION) +} + +export const fqnToAddress = (fullyqualifiedname: string, rootSystemName: string = "", version = I_ADDR_VERSION): string => { const splitFqnAt = fullyqualifiedname.split("@").filter(x => x.length > 0); if (splitFqnAt.length !== 1) throw new Error("Invalid name") @@ -101,7 +105,15 @@ export const toIAddress = (fullyqualifiedname: string, rootSystemName: string = idHash = hash(Parent, idHash); } - return toBase58Check(hash160(idHash), 102); + return toBase58Check(hash160(idHash), version); +} + +export const toIAddress = (fullyqualifiedname: string, rootSystemName: string = ""): string => { + return fqnToAddress(fullyqualifiedname, rootSystemName, I_ADDR_VERSION) +} + +export const toXAddress = (fullyqualifiedname: string, rootSystemName: string = ""): string => { + return fqnToAddress(fullyqualifiedname, rootSystemName, X_ADDR_VERSION) } function trimSpaces( @@ -285,18 +297,19 @@ function cleanName( return { name: subNames[0], parent: newParent ? toBase58Check(newParent, I_ADDR_VERSION) : null }; } -function getID(name: string, parent: string, verusChainName: string = DEFAULT_VERUS_CHAINNAME): string { +function getID(name: string, parent: string, verusChainName: string = DEFAULT_VERUS_CHAINNAME, version: number = I_ADDR_VERSION): string { const _cleanName = name === "::" ? { name, parent } : cleanName(name, parent, false, verusChainName); if (_cleanName.name.length == 0) return NULL_I_ADDR; - return nameAndParentAddrToIAddr(_cleanName.name, _cleanName.parent); + return nameAndParentAddrToAddr(_cleanName.name, _cleanName.parent, version); } export function getDataKey( keyName: string, nameSpaceID?: string, - verusChainId: string = DEFAULT_VERUS_CHAINID + verusChainId: string = DEFAULT_VERUS_CHAINID, + version: number = I_ADDR_VERSION ): { id: string; namespace: string } { let keyCopy = keyName; const addressParts = keyName.split(":"); @@ -317,8 +330,8 @@ export function getDataKey( nameSpaceID = verusChainId; } - const parent = getID("::", nameSpaceID); - return { id: getID(keyCopy, parent), namespace: nameSpaceID }; + const parent = getID("::", nameSpaceID, undefined, version); + return { id: getID(keyCopy, parent, undefined, version), namespace: nameSpaceID }; } export const decodeDestination = (destination: string): Buffer => { diff --git a/src/utils/sapling.ts b/src/utils/sapling.ts index c4c31bea..0c2ef384 100644 --- a/src/utils/sapling.ts +++ b/src/utils/sapling.ts @@ -1,7 +1,7 @@ import { bech32 } from "bech32"; export const fromBech32 = (address: string): { version: number, prefix: string, data: Buffer } => { - var result = bech32.decode(address); + var result = bech32.decode(address, 1000); // Allow longer strings like extended keys var data = bech32.fromWords(result.words); return { @@ -13,7 +13,7 @@ export const fromBech32 = (address: string): { version: number, prefix: string, export const toBech32 = (prefix: string, data: Buffer): string => { const words = bech32.toWords(data); - var result = bech32.encode(prefix, words); + var result = bech32.encode(prefix, words, 1000); // Allow longer strings like extended keys return result; } @@ -68,4 +68,114 @@ export const encodeSaplingAddress = (data: { d: Buffer, pk_d: Buffer }): string //const data = convertBits(buffer, 8, 5, false); return toBech32('zs', buffer); +} + +export interface SaplingExtendedSpendingKeyData { + depth: number; + parentFVKTag: Buffer; + childIndex: Buffer; + chainCode: Buffer; + ask: Buffer; + nsk: Buffer; + ovk: Buffer; + dk: Buffer; +} + +export interface SaplingExtendedViewingKeyData { + depth: number; + parentFVKTag: Buffer; + childIndex: Buffer; + chainCode: Buffer; + ak: Buffer; + nk: Buffer; + ovk: Buffer; + dk: Buffer; +} + +export function decodeSaplingExtendedSpendingKey(encoded: string): SaplingExtendedSpendingKeyData { + const result = fromBech32(encoded); + + // Verify prefix is for extended spending key + if (!result.prefix.startsWith('secret-extended-key-')) { + throw new Error('Invalid Sapling extended spending key prefix'); + } + + // Data should be 169 bytes: 1 (depth) + 4 (parent) + 4 (child) + 32*4 (keys) + if (result.data.length !== 169) { + throw new Error(`Invalid Sapling extended spending key length: expected 169, got ${result.data.length}`); + } + + let offset = 0; + + return { + depth: result.data.readUInt8(offset++), + parentFVKTag: Buffer.from(result.data.subarray(offset, offset += 4)), + childIndex: Buffer.from(result.data.subarray(offset, offset += 4)), + chainCode: Buffer.from(result.data.subarray(offset, offset += 32)), + ask: Buffer.from(result.data.subarray(offset, offset += 32)), + nsk: Buffer.from(result.data.subarray(offset, offset += 32)), + ovk: Buffer.from(result.data.subarray(offset, offset += 32)), + dk: Buffer.from(result.data.subarray(offset, offset += 32)) + }; +} + +export function encodeSaplingExtendedSpendingKey(data: SaplingExtendedSpendingKeyData, testnet: boolean = false): string { + const prefix = testnet ? 'secret-extended-key-test' : 'secret-extended-key-main'; + + const buffer = Buffer.concat([ + Buffer.from([data.depth]), + data.parentFVKTag, + data.childIndex, + data.chainCode, + data.ask, + data.nsk, + data.ovk, + data.dk + ]); + + return toBech32(prefix, buffer); +} + +export function decodeSaplingExtendedViewingKey(encoded: string): SaplingExtendedViewingKeyData { + const result = fromBech32(encoded); + + // Verify prefix is for extended viewing key + if (!result.prefix.startsWith('zxview')) { + throw new Error('Invalid Sapling extended viewing key prefix'); + } + + // Data should be 169 bytes: 1 (depth) + 4 (parent) + 4 (child) + 32*5 (keys) + if (result.data.length !== 169) { + throw new Error('Invalid Sapling extended viewing key length'); + } + + let offset = 0; + + return { + depth: result.data.readUInt8(offset++), + parentFVKTag: Buffer.from(result.data.subarray(offset, offset += 4)), + childIndex: Buffer.from(result.data.subarray(offset, offset += 4)), + chainCode: Buffer.from(result.data.subarray(offset, offset += 32)), + ak: Buffer.from(result.data.subarray(offset, offset += 32)), + nk: Buffer.from(result.data.subarray(offset, offset += 32)), + ovk: Buffer.from(result.data.subarray(offset, offset += 32)), + dk: Buffer.from(result.data.subarray(offset, offset += 32)) + }; +} + +export function encodeSaplingExtendedViewingKey(data: SaplingExtendedViewingKeyData, testnet: boolean = false): string { + const prefix = testnet ? 'zxviewtestsapling' : 'zxviews'; + + const buffer = Buffer.concat([ + Buffer.from([data.depth]), + data.parentFVKTag, + data.childIndex, + data.chainCode, + data.ak, + data.nk, + data.ovk, + data.dk + ]); + + return toBech32(prefix, buffer); } \ No newline at end of file diff --git a/src/utils/types/SerializableEntity.ts b/src/utils/types/SerializableEntity.ts index 046c6b6d..f823ba18 100644 --- a/src/utils/types/SerializableEntity.ts +++ b/src/utils/types/SerializableEntity.ts @@ -2,4 +2,12 @@ export interface SerializableEntity { toBuffer(): Buffer; fromBuffer(buffer: Buffer, offset?: number): number; getByteLength(): number; +} + +export interface SerializableDataEntity { + getDataByteLength(): number; + toDataBuffer(): Buffer; + + // fromDataBuffer doesn't get passed an offset because it gets passed only the varslice of the buffer it is meant to interpret. + fromDataBuffer(buffer: Buffer): void; } \ No newline at end of file diff --git a/src/vdxf/classes/Challenge.ts b/src/vdxf/classes/Challenge.ts index 805417d1..0c8cf7d0 100644 --- a/src/vdxf/classes/Challenge.ts +++ b/src/vdxf/classes/Challenge.ts @@ -417,4 +417,4 @@ export class Challenge extends VDXFObject implements ChallengeInterface { skip: this.skip, }; } -} +} \ No newline at end of file diff --git a/src/vdxf/classes/CompactAddressObject.ts b/src/vdxf/classes/CompactAddressObject.ts new file mode 100644 index 00000000..e21e37e9 --- /dev/null +++ b/src/vdxf/classes/CompactAddressObject.ts @@ -0,0 +1,247 @@ +/** + * CompactIdentityObject - Class representing an id in the smallest possible format + * + * This class is used to represent an identity or address in a compact format, allowing for efficient + * storage and transmission. The compact id can be represented either as a fully qualified name (FQN) + * or as an identity address (iaddress) or as an x address (tag/index). The class includes methods for serialization, deserialization, + * and validation of the compact id object. + */ + +import { BN } from 'bn.js'; +import bufferutils from '../../utils/bufferutils'; +import { BigNumber } from '../../utils/types/BigNumber'; +const { BufferReader, BufferWriter } = bufferutils; +import { SerializableEntity } from '../../utils/types/SerializableEntity'; +import varuint from '../../utils/varuint'; +import { fromBase58Check, getDataKey, toBase58Check, toIAddress, toXAddress } from "../../utils/address"; +import { HASH160_BYTE_LENGTH, I_ADDR_VERSION, X_ADDR_VERSION } from '../../constants/vdxf'; +import { DEFAULT_VERUS_CHAINID } from '../../constants/pbaas'; + +export interface CompactAddressObjectJson { + version: number; + type: number; + address: string; + rootsystemname: string; + namespace?: string; +} + +export interface CompactAddressObjectInterface { + version?: BigNumber; + type: BigNumber; + address: string; + rootSystemName?: string; + nameSpace?: string; +} + +export type CompactAddressIVariant = "COMPACT_ADDR_I_VARIANT"; +export type CompactAddressXVariant = "COMPACT_ADDR_X_VARIANT"; +export type CompactAddressVariantName = CompactAddressIVariant | CompactAddressXVariant; + +// TODO: Find some way to not have to hardcode the version numbers into the types here and instead use the above constants +export type CompactAddressVariantAllowedType = + T extends CompactAddressIVariant ? `${1 | 2}` : + T extends CompactAddressXVariant ? `${1 | 3}` : + never; + +export class CompactAddressObject implements SerializableEntity { + static VERSION_INVALID = new BN(0); + static FIRST_VERSION = new BN(1); + static LAST_VERSION = new BN(1); + static DEFAULT_VERSION = new BN(1); + + static TYPE_FQN = new BN(1); + static TYPE_I_ADDRESS = new BN(2); + static TYPE_X_ADDRESS = new BN(3); + + version: BigNumber; + type: CompactAddressVariantAllowedType; + address: string; + rootSystemName: string; + nameSpace: string; + + constructor(data?: CompactAddressObjectInterface) { + this.version = data?.version || new BN(CompactAddressObject.DEFAULT_VERSION); + this.type = (data?.type.toString() as CompactAddressVariantAllowedType) || ("1" as CompactAddressVariantAllowedType); + this.address = data?.address || ''; + this.rootSystemName = data?.rootSystemName || 'VRSC'; + this.nameSpace = data?.nameSpace || toIAddress(this.rootSystemName); + } + + get BNType() { + return new BN(this.type); + } + + set setType(type: BigNumber) { + this.type = type.toString() as CompactAddressVariantAllowedType + } + + isFQN(): boolean { + return (this.BNType.eq(CompactAddressObject.TYPE_FQN)); + } + + isIaddress(): boolean { + return (this.BNType.eq(CompactAddressObject.TYPE_I_ADDRESS)); + } + + isXaddress(): boolean { + return (this.BNType.eq(CompactAddressObject.TYPE_X_ADDRESS)); + } + + isValid(): boolean { + return this.address != null; + } + + toIAddress(): string { + if (this.isXaddress()) throw new Error("Cannot convert I to X address") + else if (this.isIaddress()) return this.address; + else if (this.isFQN()) { + if (this.address.includes("::")) { + return getDataKey(this.address, this.nameSpace, toIAddress(this.rootSystemName), I_ADDR_VERSION).id; + } else { + return toIAddress(this.address, this.rootSystemName); + } + } else throw new Error("Unknown type") + } + + toXAddress(): string { + if (this.isIaddress()) throw new Error("Cannot convert X to I address") + else if (this.isXaddress()) return this.address; + else if (this.isFQN()) { + if (this.address.includes("::")) { + return getDataKey(this.address, this.nameSpace, toIAddress(this.rootSystemName), X_ADDR_VERSION).id; + } else { + return toXAddress(this.address, this.rootSystemName); + } + } else throw new Error("Unknown type") + } + + toString(): string { + if (this.isIaddress()) { + return this.toIAddress(); + } else if (this.isXaddress()) { + return this.toXAddress(); + } else return this.address + } + + static fromIAddress(iaddr: string): CompactAddressObject { + return new CompactAddressObject({ + address: iaddr, + type: CompactAddressObject.TYPE_I_ADDRESS + }) + } + + static fromXAddress(xaddr: string, nameSpace: string = DEFAULT_VERUS_CHAINID): CompactAddressObject { + return new CompactAddressObject({ + address: xaddr, + nameSpace: nameSpace, + type: CompactAddressObject.TYPE_X_ADDRESS + }) + } + + getByteLength(): number { + let length = 0; + + length += varuint.encodingLength(this.version.toNumber()); + length += varuint.encodingLength(this.BNType.toNumber()); + + if (this.isIaddress() || this.isXaddress()) { + length += HASH160_BYTE_LENGTH; // identityuint160 + } else { + const addrLen = Buffer.from(this.address, 'utf8').byteLength; + + length += varuint.encodingLength(addrLen) + addrLen + } + + return length; + } + + toBuffer(): Buffer { + const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); + + writer.writeCompactSize(this.version.toNumber()); + writer.writeCompactSize(this.BNType.toNumber()); + + if (this.isIaddress() || this.isXaddress()) { + writer.writeSlice(fromBase58Check(this.address).hash); + } else { + writer.writeVarSlice(Buffer.from(this.address, 'utf8')); + } + + return writer.buffer; + } + + fromBuffer(buffer: Buffer, offset?: number): number { + const reader = new BufferReader(buffer, offset); + + this.version = new BN(reader.readCompactSize()); + this.type = new BN(reader.readCompactSize()).toString() as CompactAddressVariantAllowedType; + + if (this.isIaddress() || this.isXaddress()) { + this.address = toBase58Check(reader.readSlice(20), this.isIaddress() ? I_ADDR_VERSION : X_ADDR_VERSION); + } else { + this.address = reader.readVarSlice().toString('utf8'); + } + + return reader.offset; + } + + toJson(): CompactAddressObjectJson { + return { + version: this.version.toNumber(), + type: this.BNType.toNumber(), + address: this.address, + rootsystemname: this.rootSystemName, + }; + } + + static fromJson(json: any): CompactAddressObject { + const instance = new CompactAddressObject(); + + instance.version = new BN(json.version); + instance.type = new BN(json.type).toString() as CompactAddressVariantAllowedType; + instance.address = json.address; + instance.rootSystemName = json.rootsystemname; + + return instance; + } +} + +export class CompactXAddressObject extends CompactAddressObject { + static fromAddress(xaddr: string, nameSpace: string = DEFAULT_VERUS_CHAINID): CompactXAddressObject { + return new CompactXAddressObject({ + address: xaddr, + nameSpace: nameSpace, + type: CompactAddressObject.TYPE_X_ADDRESS + }) + } + + toAddress() { + return this.toXAddress(); + } + + static fromCompactAddressObjectJson(json: any): CompactXAddressObject { + const inst = CompactAddressObject.fromJson(json); + + return inst as CompactXAddressObject; + } +}; + +export class CompactIAddressObject extends CompactAddressObject { + static fromAddress(iaddr: string, nameSpace: string = DEFAULT_VERUS_CHAINID): CompactIAddressObject { + return new CompactIAddressObject({ + address: iaddr, + nameSpace: nameSpace, + type: CompactAddressObject.TYPE_I_ADDRESS + }) + } + + toAddress() { + return this.toIAddress(); + } + + static fromCompactAddressObjectJson(json: any): CompactIAddressObject { + const inst = CompactAddressObject.fromJson(json); + + return inst as CompactIAddressObject; + } +}; \ No newline at end of file diff --git a/src/vdxf/classes/ResponseUri.ts b/src/vdxf/classes/ResponseURI.ts similarity index 70% rename from src/vdxf/classes/ResponseUri.ts rename to src/vdxf/classes/ResponseURI.ts index f872feb2..27a3bbdf 100644 --- a/src/vdxf/classes/ResponseUri.ts +++ b/src/vdxf/classes/ResponseURI.ts @@ -5,18 +5,20 @@ import varint from "../../utils/varint"; import varuint from "../../utils/varuint"; import bufferutils from "../../utils/bufferutils"; -export type ResponseUriJson = { +export type ResponseURIJson = { type: string; uri: string; } -export class ResponseUri implements SerializableEntity { +export class ResponseURI implements SerializableEntity { uri: Buffer; // utf8 uri string type: BigNumber; // type of place to send response static TYPE_INVALID = new BN(0, 10); static TYPE_REDIRECT = new BN(1, 10); static TYPE_POST = new BN(2, 10); + // TODO: Add TYPE_Z_ADDR_REF where response is encrypted and sent to encoded sapling address, + // with optional amount specified constructor(data?: { uri?: Buffer, @@ -37,14 +39,14 @@ export class ResponseUri implements SerializableEntity { return this.uri.toString('utf-8'); } - static fromUriString(str: string, type: BigNumber = ResponseUri.TYPE_REDIRECT): ResponseUri { - return new ResponseUri({ uri: Buffer.from(str, 'utf-8'), type }); + static fromUriString(str: string, type: BigNumber = ResponseURI.TYPE_REDIRECT): ResponseURI { + return new ResponseURI({ uri: Buffer.from(str, 'utf-8'), type }); } getByteLength(): number { let length = 0; - length += varint.encodingLength(this.type); + length += varuint.encodingLength(this.type.toNumber()); let uriBufLen = this.uri.length; @@ -57,7 +59,7 @@ export class ResponseUri implements SerializableEntity { toBuffer(): Buffer { const writer = new bufferutils.BufferWriter(Buffer.alloc(this.getByteLength())); - writer.writeVarInt(this.type); + writer.writeCompactSize(this.type.toNumber()); writer.writeVarSlice(this.uri); @@ -67,22 +69,22 @@ export class ResponseUri implements SerializableEntity { fromBuffer(buffer: Buffer, offset?: number): number { const reader = new bufferutils.BufferReader(buffer, offset); - this.type = reader.readVarInt(); + this.type = new BN(reader.readCompactSize()); this.uri = reader.readVarSlice(); return reader.offset; } - toJson(): ResponseUriJson { + toJson(): ResponseURIJson { return { type: this.type.toString(10), uri: this.getUriString() }; } - static fromJson(json: ResponseUriJson): ResponseUri { - return new ResponseUri({ + static fromJson(json: ResponseURIJson): ResponseURI { + return new ResponseURI({ type: new BN(json.type, 10), uri: Buffer.from(json.uri, 'utf-8') }); diff --git a/src/vdxf/classes/SaltedData.ts b/src/vdxf/classes/SaltedData.ts index ff60484d..91aa9b4d 100644 --- a/src/vdxf/classes/SaltedData.ts +++ b/src/vdxf/classes/SaltedData.ts @@ -4,7 +4,7 @@ import { fromBase58Check, toBase58Check } from "../../utils/address"; import bufferutils from '../../utils/bufferutils' import { BN } from 'bn.js'; import { BigNumber } from '../../utils/types/BigNumber'; -import { I_ADDR_VERSION } from '../../constants/vdxf'; +import { HASH160_BYTE_LENGTH, I_ADDR_VERSION } from '../../constants/vdxf'; import { VDXFData } from '../../'; import { EHashTypes } from '../../pbaas/DataDescriptor'; const { BufferReader, BufferWriter } = bufferutils @@ -51,7 +51,7 @@ export class SaltedData extends VDXFData { getByteLength() { let byteLength = 0; - byteLength += 20; //key + byteLength += HASH160_BYTE_LENGTH; byteLength += varint.encodingLength(this.version); byteLength += varuint.encodingLength(this.data.length + this.salt.length); byteLength += this.data.length + this.salt.length; diff --git a/src/vdxf/classes/VerifiableSignatureData.ts b/src/vdxf/classes/VerifiableSignatureData.ts new file mode 100644 index 00000000..1e39a6b7 --- /dev/null +++ b/src/vdxf/classes/VerifiableSignatureData.ts @@ -0,0 +1,452 @@ +import varuint from '../../utils/varuint' +import { fromBase58Check, toBase58Check } from "../../utils/address"; +import bufferutils from '../../utils/bufferutils' +import { BN } from 'bn.js'; +import { BigNumber } from '../../utils/types/BigNumber'; +import { HASH160_BYTE_LENGTH, HASH256_BYTE_LENGTH, I_ADDR_VERSION } from '../../constants/vdxf'; +import { SerializableEntity } from '../../utils/types/SerializableEntity'; +import { EHashTypes } from '../../pbaas/DataDescriptor'; +const { BufferReader, BufferWriter } = bufferutils +const createHash = require("create-hash"); +import { VERUS_DATA_SIGNATURE_PREFIX } from "../../constants/vdxf"; +import { CompactIAddressObject, CompactAddressObjectJson } from './CompactAddressObject'; +import { DEFAULT_VERUS_CHAINNAME, HASH_TYPE_SHA256 } from '../../constants/pbaas'; +import varint from '../../utils/varint'; +import { SignatureData, SignatureJsonDataInterface } from '../../pbaas'; + +export interface VerifiableSignatureDataJson { + version: number; + flags: number; + signatureversion: number; + hashtype: number; + systemid: CompactAddressObjectJson; + identityid: CompactAddressObjectJson; + vdxfkeys?: Array; + vdxfkeynames?: Array; + boundhashes?: Array; + statements?: Array; + signature: string +} + +export interface VerifiableSignatureDataInterface { + version?: BigNumber; + flags?: BigNumber; + signatureVersion?: BigNumber; + hashType?: BigNumber; + systemID?: CompactIAddressObject; + identityID: CompactIAddressObject; + vdxfKeys?: Array; + vdxfKeyNames?: Array; + boundHashes?: Array; + statements?: Array; + signatureAsVch?: Buffer; +} + +export interface CliSignatureData { + signaturedata: SignatureJsonDataInterface; + system: string; + systemid: string; + hashtype: string; + hash: string; + identity: string; + canonicalname: string; + address: string; + signatureheight: number; + signature: string; + signatureversion: number; + vdxfkeys?: Array; + vdxfkeynames?: Array; + boundhashes?: Array; +} + +export class VerifiableSignatureData implements SerializableEntity { + version: BigNumber; + flags: BigNumber; + signatureVersion: BigNumber; + hashType: BigNumber; + identityID: CompactIAddressObject; + systemID: CompactIAddressObject; + vdxfKeys?: Array; + vdxfKeyNames?: Array; + boundHashes?: Array; + statements?: Array; + signatureAsVch: Buffer; + + static VERSION_INVALID = new BN(0); + static FIRST_VERSION = new BN(1); + static LAST_VERSION = new BN(1); + static DEFAULT_VERSION = new BN(1); + static TYPE_VERUSID_DEFAULT = new BN(1); + + static FLAG_HAS_VDXF_KEYS = new BN(1); + static FLAG_HAS_VDXF_KEY_NAMES = new BN(2); + static FLAG_HAS_BOUND_HASHES = new BN(4); + static FLAG_HAS_STATEMENTS = new BN(8); + + constructor(data?: VerifiableSignatureDataInterface) { + this.version = data && data.version ? data.version : new BN(0); + this.flags = data && data.flags ? data.flags : new BN(0); + this.signatureVersion = data && data.signatureVersion ? data.signatureVersion : new BN(2, 10); + this.systemID = data && data.systemID ? data.systemID : new CompactIAddressObject({ type: CompactIAddressObject.TYPE_FQN, address: DEFAULT_VERUS_CHAINNAME }); + this.hashType = data && data.hashType ? data.hashType : HASH_TYPE_SHA256; + this.identityID = data ? data.identityID : undefined; + this.vdxfKeys = data ? data.vdxfKeys : undefined; + this.vdxfKeyNames = data ? data.vdxfKeyNames : undefined; + this.boundHashes = data ? data.boundHashes : undefined; + this.statements = data ? data.statements : undefined; + this.signatureAsVch = data && data.signatureAsVch ? data.signatureAsVch : Buffer.alloc(0); + + this.setFlags(); + } + + private hasFlag(flag: BigNumber) { + return !!(this.flags.and(flag).toNumber()); + } + + private setFlag(flag: BigNumber) { + this.flags = this.flags.or(flag); + } + + hasVdxfKeys() { + return this.hasFlag(VerifiableSignatureData.FLAG_HAS_VDXF_KEYS); + } + + hasVdxfKeyNames() { + return this.hasFlag(VerifiableSignatureData.FLAG_HAS_VDXF_KEY_NAMES); + } + + hasBoundHashes() { + return this.hasFlag(VerifiableSignatureData.FLAG_HAS_BOUND_HASHES); + } + + hasStatements() { + return this.hasFlag(VerifiableSignatureData.FLAG_HAS_STATEMENTS); + } + + setHasVdxfKeys() { + this.setFlag(VerifiableSignatureData.FLAG_HAS_VDXF_KEYS); + } + + setHasVdxfKeyNames() { + this.setFlag(VerifiableSignatureData.FLAG_HAS_VDXF_KEY_NAMES); + } + + setHasBoundHashes() { + this.setFlag(VerifiableSignatureData.FLAG_HAS_BOUND_HASHES); + } + + setHasStatements() { + this.setFlag(VerifiableSignatureData.FLAG_HAS_STATEMENTS); + } + + calcFlags(): BigNumber { + let flags = new BN(0); + if (this.hasVdxfKeys()) flags = flags.or(VerifiableSignatureData.FLAG_HAS_VDXF_KEYS); + if (this.hasVdxfKeyNames()) flags = flags.or(VerifiableSignatureData.FLAG_HAS_VDXF_KEY_NAMES); + if (this.hasBoundHashes()) flags = flags.or(VerifiableSignatureData.FLAG_HAS_BOUND_HASHES); + if (this.hasStatements()) flags = flags.or(VerifiableSignatureData.FLAG_HAS_STATEMENTS); + return flags; + } + + setFlags() { + if (this.vdxfKeys) this.setHasVdxfKeys(); + if (this.vdxfKeyNames) this.setHasVdxfKeyNames(); + if (this.boundHashes) this.setHasBoundHashes(); + if (this.statements) this.setHasStatements(); + } + + private getBufferEncodingLength(buf: Buffer) { + const bufLen = buf.byteLength; + + return varuint.encodingLength(bufLen) + bufLen; + } + + private getExtraHashDataByteLength(): number { + let byteLength = 0; + + if (this.vdxfKeys && this.vdxfKeys.length > 0) { + byteLength += varuint.encodingLength(this.vdxfKeys.length); + byteLength += this.vdxfKeys.length * HASH160_BYTE_LENGTH; + } + + if (this.vdxfKeyNames && this.vdxfKeyNames.length > 0) { + byteLength += varuint.encodingLength(this.vdxfKeyNames.length); + for (const name of this.vdxfKeyNames) { + byteLength += this.getBufferEncodingLength(Buffer.from(name, 'utf8')); + } + } + + if (this.boundHashes && this.boundHashes.length > 0) { + byteLength += varuint.encodingLength(this.boundHashes.length); + byteLength += this.boundHashes.length * HASH256_BYTE_LENGTH; + + } + + return byteLength; + } + + private getExtraHashData(): Buffer { + const byteLength = this.getExtraHashDataByteLength(); + + if (byteLength === 0) { + return Buffer.alloc(0); + } + + const bufferWriter = new BufferWriter(Buffer.alloc(byteLength)); + + if (this.vdxfKeys && this.vdxfKeys.length > 0) { + // Sort vdxfKeys by their 20-byte buffer values before writing + const keyBuffers = this.vdxfKeys.map(x => fromBase58Check(x).hash); + const sortedBuffers = keyBuffers.sort(Buffer.compare); + bufferWriter.writeArray(sortedBuffers); + } + + if (this.vdxfKeyNames && this.vdxfKeyNames.length > 0) { + // Sort vdxfKeyNames before writing + const sortedNames = [...this.vdxfKeyNames].sort(); + bufferWriter.writeVector(sortedNames.map(x => Buffer.from(x, 'utf8'))); + } + + if (this.boundHashes && this.boundHashes.length > 0) { + // Sort boundHashes before writing + const sortedHashes = [...this.boundHashes].sort(Buffer.compare); + bufferWriter.writeArray(sortedHashes); + } + + return bufferWriter.buffer; + } + + getByteLength() { + let byteLength = 0; + + byteLength += varint.encodingLength(this.version); + + byteLength += varuint.encodingLength(this.flags.toNumber()); + + byteLength += varuint.encodingLength(this.signatureVersion.toNumber()); + + byteLength += varuint.encodingLength(this.hashType.toNumber()); + + byteLength += this.systemID.getByteLength(); + byteLength += this.identityID.getByteLength(); + + if (this.hasVdxfKeys()) { + byteLength += varuint.encodingLength(this.vdxfKeys.length); + + for (const key of this.vdxfKeys) { + byteLength += HASH160_BYTE_LENGTH + } + } + + if (this.hasVdxfKeyNames()) { + byteLength += varuint.encodingLength(this.vdxfKeyNames.length); + + for (const key of this.vdxfKeyNames) { + byteLength += this.getBufferEncodingLength(Buffer.from(key, 'utf8')) + } + } + + if (this.hasBoundHashes()) { + byteLength += varuint.encodingLength(this.boundHashes.length); + + for (const hash of this.boundHashes) { + byteLength += this.getBufferEncodingLength(hash) + } + } + + if (this.hasStatements()) { + byteLength += varuint.encodingLength(this.statements.length); + + for (const statement of this.statements) { + byteLength += this.getBufferEncodingLength(statement) + } + } + + byteLength += this.getBufferEncodingLength(this.signatureAsVch) + + return byteLength + } + + toBuffer() { + const bufferWriter = new BufferWriter(Buffer.alloc(this.getByteLength())); + + bufferWriter.writeVarInt(this.version); + + bufferWriter.writeCompactSize(this.flags.toNumber()); + + bufferWriter.writeCompactSize(this.signatureVersion.toNumber()); + + bufferWriter.writeCompactSize(this.hashType.toNumber()); + + bufferWriter.writeSlice(this.systemID.toBuffer()); + bufferWriter.writeSlice(this.identityID.toBuffer()); + + if (this.hasVdxfKeys()) { + bufferWriter.writeArray(this.vdxfKeys!.map(x => fromBase58Check(x).hash)); + } + + if (this.hasVdxfKeyNames()) { + bufferWriter.writeVector(this.vdxfKeyNames!.map(x => Buffer.from(x, 'utf8'))); + } + + if (this.hasBoundHashes()) { + bufferWriter.writeVector(this.boundHashes!); + } + + if (this.hasStatements()) { + bufferWriter.writeVector(this.statements!); + } + + bufferWriter.writeVarSlice(this.signatureAsVch); + + return bufferWriter.buffer; + } + + fromBuffer(buffer: Buffer, offset: number = 0) { + const bufferReader = new BufferReader(buffer, offset); + + this.version = bufferReader.readVarInt(); + + this.flags = new BN(bufferReader.readCompactSize()); + + this.signatureVersion = new BN(bufferReader.readCompactSize()); + + this.hashType = new BN(bufferReader.readCompactSize()); + + this.systemID = new CompactIAddressObject(); + this.identityID = new CompactIAddressObject(); + + bufferReader.offset = this.systemID.fromBuffer(bufferReader.buffer, bufferReader.offset); + bufferReader.offset = this.identityID.fromBuffer(bufferReader.buffer, bufferReader.offset); + + if (this.hasVdxfKeys()) { + this.vdxfKeys = bufferReader.readArray(HASH160_BYTE_LENGTH).map(x => toBase58Check(x, I_ADDR_VERSION)); + } + + if (this.hasVdxfKeyNames()) { + this.vdxfKeyNames = bufferReader.readVector().map((x: Buffer) => x.toString('utf8')); + } + + if (this.hasBoundHashes()) { + this.boundHashes = bufferReader.readVector(); + } + + if (this.hasStatements()) { + this.statements = bufferReader.readVector(); + } + + this.signatureAsVch = bufferReader.readVarSlice(); + + return bufferReader.offset; + } + + // To fully implement, refer to VerusCoin/src/pbaas/crosschainrpc.cpp line 337, IdentitySignatureHash + getIdentityHash(height: number, sigHash: Buffer): Buffer { + var heightBuffer = Buffer.allocUnsafe(4) + heightBuffer.writeUInt32LE(height); + + if (!this.hashType.eq(new BN(EHashTypes.HASH_SHA256))) { + throw new Error("Only SHA256 hash type is currently supported."); + } + + if (this.signatureVersion.eq(new BN(0))) { + throw new Error("Invalid sig data version") + } else if (this.signatureVersion.eq(new BN(1))) { + return createHash("sha256") + .update(VERUS_DATA_SIGNATURE_PREFIX) + .update(fromBase58Check(this.systemID.toIAddress()).hash) + .update(heightBuffer) + .update(fromBase58Check(this.identityID.toIAddress()).hash) + .update(sigHash) + .digest(); + } else if (this.signatureVersion.eq(new BN(2))) { + const extraHashData = this.getExtraHashData(); + const hash = createHash("sha256"); + + if (extraHashData.length > 0) { + hash.update(extraHashData); + } + + return hash + .update(fromBase58Check(this.systemID.toIAddress()).hash) + .update(heightBuffer) + .update(fromBase58Check(this.identityID.toIAddress()).hash) + .update(VERUS_DATA_SIGNATURE_PREFIX) + .update(sigHash) + .digest(); + } else { + throw new Error("Unrecognized sig data version") + } + } + + toSignatureData(sigHash: Buffer): SignatureData { + return new SignatureData({ + version: this.version, + system_ID: this.systemID.toIAddress(), + hash_type: this.hashType, + signature_hash: sigHash, + identity_ID: this.identityID.toIAddress(), + sig_type: SignatureData.TYPE_VERUSID_DEFAULT, + vdxf_keys: this.vdxfKeys, + vdxf_key_names: this.vdxfKeyNames, + bound_hashes: this.boundHashes, + signature_as_vch: this.signatureAsVch + }) + } + + toJson(): VerifiableSignatureDataJson { + const flags = this.calcFlags(); + + return { + version: this.version.toNumber(), + flags: flags.toNumber(), + signatureversion: this.signatureVersion.toNumber(), + hashtype: this.hashType.toNumber(), + systemid: this.systemID.toJson(), + identityid: this.identityID.toJson(), + vdxfkeys: this.vdxfKeys, + vdxfkeynames: this.vdxfKeyNames, + boundhashes: this.boundHashes?.map(x => x.toString('hex')), + statements: this.statements?.map(x => x.toString('hex')), + signature: this.signatureAsVch.toString('hex') + }; + } + + static fromJson(json: VerifiableSignatureDataJson): VerifiableSignatureData { + const instance = new VerifiableSignatureData(); + instance.version = new BN(json.version); + instance.flags = new BN(json.flags); + instance.signatureVersion = new BN(json.signatureversion); + instance.hashType = new BN(json.hashtype); + instance.systemID = CompactIAddressObject.fromCompactAddressObjectJson(json.systemid); + instance.identityID = CompactIAddressObject.fromCompactAddressObjectJson(json.identityid); + instance.vdxfKeys = json?.vdxfkeys; + instance.vdxfKeyNames = json?.vdxfkeynames; + instance.boundHashes = json.boundhashes?.map(x => Buffer.from(x, 'hex')); + instance.statements = json.statements?.map(x => Buffer.from(x, 'hex')); + instance.signatureAsVch = Buffer.from(json.signature, 'hex'); + return instance; + } + + static fromCLIJson(json: CliSignatureData, rootSystemName = 'VRSC'): VerifiableSignatureData { + const instance = new VerifiableSignatureData(); + instance.version = new BN(VerifiableSignatureData.TYPE_VERUSID_DEFAULT); + instance.hashType = new BN(json.signaturedata.hashtype); + instance.signatureVersion = new BN(json.signatureversion); //default Signature Version + + instance.systemID = CompactIAddressObject.fromAddress(json.systemid, rootSystemName); + instance.identityID = CompactIAddressObject.fromAddress(json.address, rootSystemName); + + // Set optional fields + instance.vdxfKeys = json.vdxfkeys; + instance.vdxfKeyNames = json.vdxfkeynames; + instance.boundHashes = json.boundhashes?.map(x => Buffer.from(x, 'hex')); + + // Store the full signature (from daemon in base64 format) + instance.signatureAsVch = Buffer.from(json.signature, 'base64'); + + instance.setFlags(); + + return instance; + } +} \ No newline at end of file diff --git a/src/vdxf/classes/appencryption/AppEncryptionRequestDetails.ts b/src/vdxf/classes/appencryption/AppEncryptionRequestDetails.ts new file mode 100644 index 00000000..8dcd8bb7 --- /dev/null +++ b/src/vdxf/classes/appencryption/AppEncryptionRequestDetails.ts @@ -0,0 +1,227 @@ + +/** + * AppEncryptionRequestDetails - Class for handling application requests for encrypted derived seeds + * + * This class is used when an application is requesting an encrypted derived seed from the user's master seed, + * using specific parameters passed by the application. The request includes: + * - App or delegated ID making the request (mandatory) + * - A target encryption key (zaddress format) for encrypting the reply + * - Derivation number for seed generation + * - Optional derivation ID (defaults to Z-address from ID signing if not present) + * - Optional request ID for tracking + * + * The user's wallet can use these parameters to derive a specific seed from their master seed + * and encrypt it using the provided encryption key, ensuring the application receives only + * the specific derived seed it needs without exposing the master seed. + * + * The RETURN_ESK flag can be set to signal that the Extended Spending Key should be returned. + */ + +import { BigNumber } from '../../../utils/types/BigNumber'; +import { BN } from 'bn.js'; +import bufferutils from '../../../utils/bufferutils'; +const { BufferReader, BufferWriter } = bufferutils; +import { decodeSaplingAddress, toBech32 } from '../../../utils/sapling'; +import { SerializableEntity } from '../../../utils/types/SerializableEntity'; +import { CompactIAddressObject, CompactAddressObjectJson } from '../CompactAddressObject'; +import varuint from '../../../utils/varuint'; +import { fromBase58Check, toBase58Check } from '../../../utils/address'; +import { I_ADDR_VERSION, HASH160_BYTE_LENGTH } from '../../../constants/vdxf'; + +export interface AppEncryptionRequestInterface { + version?: BigNumber; + flags: BigNumber; + encryptToZAddress: string; + derivationNumber: BigNumber; + derivationID?: CompactIAddressObject; + requestID?: string; +} + +export interface AppEncryptionRequestJson { + version: number; + flags: number; + encrypttozaddress: string; + derivationnumber: number; + derivationid?: CompactAddressObjectJson; + requestid?: string; +} + +/** + * Checks if a string is a valid hexadecimal address + * @param flags - Optional flags for the request + * @flag HAS_REQUEST_ID - Indicates if a request ID is included + * + * @param encryptToZAddress - The encryption key to use for encrypting to + * @param derivationNumber - The derivation number to validate + */ + +export class AppEncryptionRequestDetails implements SerializableEntity { + static VERSION_INVALID = new BN(0); + static FIRST_VERSION = new BN(1); + static LAST_VERSION = new BN(1); + static DEFAULT_VERSION = new BN(1); + + static HAS_DERIVATION_ID = new BN(1); + static HAS_REQUEST_ID = new BN(2); + static RETURN_ESK = new BN(4); //flag to signal to return the Extended Spending Key + + version: BigNumber; + flags: BigNumber; + encryptToZAddress: string; // zaddress reply is encrypted to + derivationNumber: BigNumber; + derivationID?: CompactIAddressObject; // Defaults to choosing the Z-address from the ID signing if not present + requestID?: string; // Unique identifier for the request + + constructor(data?: AppEncryptionRequestInterface) { + this.version = data?.version || AppEncryptionRequestDetails.DEFAULT_VERSION; + this.flags = data?.flags || new BN(0); + this.encryptToZAddress = data?.encryptToZAddress || ''; + this.derivationNumber = data?.derivationNumber || new BN(0); + this.derivationID = data?.derivationID; + this.requestID = data?.requestID; + + this.setFlags(); + } + + setFlags(): void { + this.flags = this.calcFlags(); + } + + calcFlags(): BigNumber { + let flags = new BN(0); + + if (this.derivationID != null) { + flags = flags.or(AppEncryptionRequestDetails.HAS_DERIVATION_ID); + } + + if (this.requestID != null) { + flags = flags.or(AppEncryptionRequestDetails.HAS_REQUEST_ID); + } + + return flags; + } + + isValid(): boolean { + let valid = true; + valid &&= this.encryptToZAddress != null && this.encryptToZAddress.length > 0; + valid &&= this.derivationNumber != null && this.derivationNumber.gte(new BN(0)); + + return valid; + } + + hasDerivationID(flags: BigNumber = this.flags): boolean { + return flags.and(AppEncryptionRequestDetails.HAS_DERIVATION_ID).gt(new BN(0)); + } + + hasRequestID(flags: BigNumber = this.flags): boolean { + return flags.and(AppEncryptionRequestDetails.HAS_REQUEST_ID).gt(new BN(0)); + } + + getByteLength(): number { + + const flags = this.calcFlags(); + + let length = 0; + + length += varuint.encodingLength(flags.toNumber()); + + // encryptToKey - zaddress encoding (43 bytes for sapling address data) + length += 43; // Sapling address decoded data (11 + 32 bytes) + + length += varuint.encodingLength(this.derivationNumber.toNumber()); + + if (this.hasDerivationID(flags)) { + length += this.derivationID.getByteLength(); + } + + if (this.hasRequestID(flags)) { + length += HASH160_BYTE_LENGTH; + } + + return length; + } + + toBuffer(): Buffer { + const flags = this.calcFlags(); + const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); + + // Write flags + writer.writeCompactSize(flags.toNumber()); + + // Write encryptToAddress as decoded sapling address data + const saplingData = decodeSaplingAddress(this.encryptToZAddress); + writer.writeSlice(Buffer.concat([saplingData.d, saplingData.pk_d])); + + // Write mandatory derivation number + writer.writeVarInt(this.derivationNumber); + + if (this.hasDerivationID(flags)) { + writer.writeSlice(this.derivationID.toBuffer()); + } + + if (this.hasRequestID(flags)) { + + writer.writeSlice(fromBase58Check(this.requestID).hash); + } + + return writer.buffer; + } + + fromBuffer(buffer: Buffer, offset?: number): number { + const reader = new BufferReader(buffer, offset); + + // Read flags + this.flags = new BN(reader.readCompactSize()); + + // Read encryptToAddress as 43-byte sapling data and encode as sapling address + const saplingData = reader.readSlice(43); + this.encryptToZAddress = toBech32('zs', saplingData); + + // Read mandatory derivation number + this.derivationNumber = reader.readVarInt(); + + if (this.hasDerivationID()) { + const derivationIDObj = new CompactIAddressObject(); + reader.offset = derivationIDObj.fromBuffer(reader.buffer, reader.offset); + this.derivationID = derivationIDObj; + } + + if (this.hasRequestID()) { + this.requestID = toBase58Check(reader.readSlice(20), I_ADDR_VERSION); + } + + return reader.offset; + } + + toJson(): AppEncryptionRequestJson { + // Set flags before serialization + const flags = this.calcFlags(); + + return { + version: this.version.toNumber(), + flags: flags.toNumber(), + encrypttozaddress: this.encryptToZAddress, + derivationnumber: this.derivationNumber.toNumber(), + derivationid: this.derivationID?.toJson(), + requestid: this.requestID + }; + } + + static fromJson(json: AppEncryptionRequestJson): AppEncryptionRequestDetails { + const instance = new AppEncryptionRequestDetails(); + instance.version = new BN(json.version); + instance.flags = new BN(json.flags); + instance.encryptToZAddress = json.encrypttozaddress; + instance.derivationNumber = new BN(json.derivationnumber); + + if(instance.hasDerivationID()) { + instance.derivationID = CompactIAddressObject.fromCompactAddressObjectJson(json?.derivationid); + } + + if(instance.hasRequestID()) { + instance.requestID = json?.requestid; + } + + return instance; + } +} diff --git a/src/vdxf/classes/appencryption/AppEncryptionResponseDetails.ts b/src/vdxf/classes/appencryption/AppEncryptionResponseDetails.ts new file mode 100644 index 00000000..4d57a8dc --- /dev/null +++ b/src/vdxf/classes/appencryption/AppEncryptionResponseDetails.ts @@ -0,0 +1,173 @@ + +import { BigNumber } from '../../../utils/types/BigNumber'; +import { BN } from 'bn.js'; +import varint from '../../../utils/varint'; +import bufferutils from '../../../utils/bufferutils'; +const { BufferReader, BufferWriter } = bufferutils; +import { SerializableEntity } from '../../../utils/types/SerializableEntity'; +import { fromBase58Check, toBase58Check } from '../../../utils/address'; +import { HASH160_BYTE_LENGTH, I_ADDR_VERSION } from '../../../constants/vdxf'; +import { SaplingPaymentAddress } from '../../../pbaas'; +import createHash = require("create-hash"); +import { SaplingExtendedSpendingKey } from '../../../pbaas/SaplingExtendedSpendingKey'; +import { SaplingExtendedViewingKey } from '../../../pbaas/SaplingExtendedViewingKey'; + +export interface AppEncryptionResponseDetailsInterface { + version: BigNumber; + flags?: BigNumber; + requestID?: string; + incomingViewingKey: Buffer; + extendedViewingKey: SaplingExtendedViewingKey; + address: SaplingPaymentAddress; + extendedSpendingKey?: SaplingExtendedSpendingKey; +} + +export interface AppEncryptionResponseDetailsJson { + version: number; + flags?: number; + requestid?: string; + incomingviewingkey: string; + extendedviewingkey: string; + address: string; + extendedspendingkey?: string; +} + +export class AppEncryptionResponseDetails implements SerializableEntity { + version: BigNumber; + flags: BigNumber; + requestID?: string; + incomingViewingKey: Buffer; + extendedViewingKey: SaplingExtendedViewingKey; + address: SaplingPaymentAddress; + extendedSpendingKey?: SaplingExtendedSpendingKey; + + static RESPONSE_CONTAINS_REQUEST_ID = new BN(1, 10); + static RESPONSE_CONTAINS_EXTENDED_SPENDING_KEY = new BN(2, 10); + + constructor(data?: AppEncryptionResponseDetailsInterface) { + this.version = data?.version ?? new BN(1); + this.flags = data?.flags ?? new BN(0, 10); + this.incomingViewingKey = data?.incomingViewingKey ?? Buffer.alloc(32); + this.extendedViewingKey = data?.extendedViewingKey ?? new SaplingExtendedViewingKey(); + this.address = data?.address ?? new SaplingPaymentAddress(); + + if (data?.requestID) { + if (!this.containsRequestID()) this.toggleContainsRequestID(); + this.requestID = data.requestID; + } + + if (data?.extendedSpendingKey) { + if (!this.containsExtendedSpendingKey()) this.toggleContainsExtendedSpendingKey(); + this.extendedSpendingKey = data.extendedSpendingKey; + } + } + + containsRequestID() { + return !!(this.flags.and(AppEncryptionResponseDetails.RESPONSE_CONTAINS_REQUEST_ID).toNumber()); + } + + toggleContainsRequestID() { + this.flags = this.flags.xor(AppEncryptionResponseDetails.RESPONSE_CONTAINS_REQUEST_ID); + } + + containsExtendedSpendingKey() { + return !!(this.flags.and(AppEncryptionResponseDetails.RESPONSE_CONTAINS_EXTENDED_SPENDING_KEY).toNumber()); + } + + toggleContainsExtendedSpendingKey() { + this.flags = this.flags.xor(AppEncryptionResponseDetails.RESPONSE_CONTAINS_EXTENDED_SPENDING_KEY); + } + + toSha256() { + return createHash("sha256").update(this.toBuffer()).digest(); + } + + getByteLength(): number { + let length = 0; + + length += varint.encodingLength(this.flags); + + if (this.containsRequestID()) { + length += HASH160_BYTE_LENGTH; + } + + length += 32; // incomingViewingKey + length += this.extendedViewingKey.getByteLength(); + length += this.address.getByteLength(); + + if (this.containsExtendedSpendingKey()) { + length += this.extendedSpendingKey.getByteLength(); + } + + return length; + } + + toBuffer() { + const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); + + writer.writeVarInt(this.flags); + + if (this.containsRequestID()) { + writer.writeSlice(fromBase58Check(this.requestID).hash); + } + + writer.writeSlice(this.incomingViewingKey); + writer.writeSlice(this.extendedViewingKey.toBuffer()); + writer.writeSlice(this.address.toBuffer()); + + if (this.containsExtendedSpendingKey()) { + writer.writeSlice(this.extendedSpendingKey.toBuffer()); + } + + return writer.buffer; + } + + fromBuffer(buffer: Buffer, offset: number = 0) { + const reader = new BufferReader(buffer, offset); + + this.flags = reader.readVarInt(); + + if (this.containsRequestID()) { + this.requestID = toBase58Check(reader.readSlice(HASH160_BYTE_LENGTH), I_ADDR_VERSION); + } + + this.incomingViewingKey = reader.readSlice(32); + + this.extendedViewingKey = new SaplingExtendedViewingKey(); + reader.offset = this.extendedViewingKey.fromBuffer(reader.buffer, reader.offset); + + this.address = new SaplingPaymentAddress(); + reader.offset = this.address.fromBuffer(reader.buffer, reader.offset); + + if (this.containsExtendedSpendingKey()) { + this.extendedSpendingKey = new SaplingExtendedSpendingKey(); + reader.offset = this.extendedSpendingKey.fromBuffer(reader.buffer, reader.offset); + } + + return reader.offset; + } + + toJson(): AppEncryptionResponseDetailsJson { + return { + version: this.version.toNumber(), + flags: this.flags.toNumber(), + requestid: this.containsRequestID() ? this.requestID : undefined, + incomingviewingkey: this.incomingViewingKey.toString('hex'), + extendedviewingkey: this.extendedViewingKey.toKeyString(), + address: this.address.toAddressString(), + extendedspendingkey: this.containsExtendedSpendingKey() ? this.extendedSpendingKey.toKeyString() : undefined + }; + } + + static fromJson(json: AppEncryptionResponseDetailsJson): AppEncryptionResponseDetails { + return new AppEncryptionResponseDetails({ + version: new BN(json.version, 10), + flags: new BN(json.flags ?? 0, 10), + requestID: json.requestid, + incomingViewingKey: Buffer.from(json.incomingviewingkey, 'hex'), + extendedViewingKey: SaplingExtendedViewingKey.fromKeyString(json.extendedviewingkey), + address: SaplingPaymentAddress.fromAddressString(json.address), + extendedSpendingKey: json.extendedspendingkey ? SaplingExtendedSpendingKey.fromKeyString(json.extendedspendingkey) : undefined + }); + } +} diff --git a/src/vdxf/classes/attestation/AttestationDetails.ts b/src/vdxf/classes/attestation/AttestationDetails.ts deleted file mode 100644 index ef8eb122..00000000 --- a/src/vdxf/classes/attestation/AttestationDetails.ts +++ /dev/null @@ -1,434 +0,0 @@ -import { BigNumber } from '../../../utils/types/BigNumber'; -import { BN } from 'bn.js'; -import varint from '../../../utils/varint'; -import varuint from '../../../utils/varuint'; -import bufferutils from '../../../utils/bufferutils'; -const { BufferReader, BufferWriter } = bufferutils; -import { MMRDescriptor, MMRDescriptorJson } from '../../../pbaas/MMRDescriptor'; -import { SignatureData, SignatureJsonDataInterface } from '../../../pbaas/SignatureData'; -import { SerializableEntity } from '../../../utils/types/SerializableEntity'; - -export interface AttestationPairJson { - mmrdescriptor: MMRDescriptorJson; - signaturedata: SignatureJsonDataInterface; -} - -export interface AttestationDetailsJson { - version: number; - flags?: number; - label?: string; - id?: string; - timestamp?: number; - attestations: AttestationPairJson[]; -} - -export class AttestationPair implements SerializableEntity { - mmrDescriptor: MMRDescriptor; - signatureData: SignatureData; - - constructor(data?: { - mmrDescriptor?: MMRDescriptor; - signatureData?: SignatureData; - }) { - if (data) { - this.mmrDescriptor = data.mmrDescriptor || new MMRDescriptor(); - this.signatureData = data.signatureData || new SignatureData(); - } else { - this.mmrDescriptor = new MMRDescriptor(); - this.signatureData = new SignatureData(); - } - } - - static fromJson(data: AttestationPairJson): AttestationPair { - return new AttestationPair({ - mmrDescriptor: MMRDescriptor.fromJson(data.mmrdescriptor), - signatureData: SignatureData.fromJson(data.signaturedata) - }); - } - - getByteLength(): number { - return this.mmrDescriptor.getByteLength() + this.signatureData.getByteLength(); - } - - toBuffer(): Buffer { - const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); - writer.writeSlice(this.mmrDescriptor.toBuffer()); - writer.writeSlice(this.signatureData.toBuffer()); - return writer.buffer; - } - - fromBuffer(buffer: Buffer, offset?: number): number { - const reader = new BufferReader(buffer, offset); - - this.mmrDescriptor = new MMRDescriptor(); - reader.offset = this.mmrDescriptor.fromBuffer(reader.buffer, reader.offset); - - this.signatureData = new SignatureData(); - reader.offset = this.signatureData.fromBuffer(reader.buffer, reader.offset); - - return reader.offset; - } - - toJson(): AttestationPairJson { - return { - mmrdescriptor: this.mmrDescriptor.toJson(), - signaturedata: this.signatureData.toJson() - }; - } -} - -export class AttestationDetails implements SerializableEntity { - static VERSION_INVALID = new BN(0); - static FIRST_VERSION = new BN(1); - static LAST_VERSION = new BN(1); - static DEFAULT_VERSION = new BN(1); - - // Flags - static FLAG_LABEL = 1; - static FLAG_ID = 2; - static FLAG_TIMESTAMP = 4; - - version: BigNumber; - flags: BigNumber; - label?: string; - id?: string; - timestamp?: BigNumber; - attestations: AttestationPair[]; - - constructor(data?: { - version?: BigNumber; - flags?: BigNumber; - label?: string; - id?: string; - timestamp?: BigNumber; - attestations?: AttestationPair[]; - }) { - if (data) { - this.version = data.version || AttestationDetails.DEFAULT_VERSION; - this.flags = data.flags || new BN(0); - this.label = data.label; - this.id = data.id; - this.timestamp = data.timestamp; - this.attestations = data.attestations || []; - } else { - this.version = AttestationDetails.DEFAULT_VERSION; - this.flags = new BN(0); - this.attestations = []; - } - } - - static fromJson(data: AttestationDetailsJson): AttestationDetails { - const newAttestationDetails = new AttestationDetails(); - - if (data) { - if (data.version) newAttestationDetails.version = new BN(data.version); - if (data.flags !== undefined) newAttestationDetails.flags = new BN(data.flags); - if (data.label) newAttestationDetails.label = data.label; - if (data.id) newAttestationDetails.id = data.id; - if (data.timestamp) newAttestationDetails.timestamp = new BN(data.timestamp); - - if (data.attestations) { - newAttestationDetails.attestations = data.attestations.map( - attestation => AttestationPair.fromJson(attestation) - ); - } - } - - return newAttestationDetails; - } - - /** - * Create AttestationDetails from a single Verus node response - * @param nodeResponse - The JSON object from Verus node: {"signaturedata": ..., "mmrdescriptor": ...} - * @param options - Optional metadata (label, id, timestamp) - */ - static fromNodeResponse( - nodeResponse: { signaturedata: any; mmrdescriptor: any }, - options?: { - label?: string; - id?: string; - timestamp?: number; - } - ): AttestationDetails { - const attestationPair = new AttestationPair({ - mmrDescriptor: MMRDescriptor.fromJson(nodeResponse.mmrdescriptor), - signatureData: SignatureData.fromJson(nodeResponse.signaturedata) - }); - - const attestationDetails = new AttestationDetails({ - attestations: [attestationPair] - }); - - // Set optional metadata - if (options?.label) { - attestationDetails.setLabel(options.label); - } - if (options?.id) { - attestationDetails.setId(options.id); - } - if (options?.timestamp) { - attestationDetails.setTimestamp(new BN(options.timestamp)); - } - - // Update flags based on set metadata - attestationDetails.setFlags(); - - return attestationDetails; - } - - /** - * Create AttestationDetails from multiple Verus node responses - * @param nodeResponses - Array of JSON objects from Verus node - * @param options - Optional metadata (label, id, timestamp) - */ - static fromNodeResponses( - nodeResponses: Array<{ signaturedata: any; mmrdescriptor: any }>, - options?: { - label?: string; - id?: string; - timestamp?: number; - } - ): AttestationDetails { - const attestationPairs = nodeResponses.map(response => - new AttestationPair({ - mmrDescriptor: MMRDescriptor.fromJson(response.mmrdescriptor), - signatureData: SignatureData.fromJson(response.signaturedata) - }) - ); - - const attestationDetails = new AttestationDetails({ - attestations: attestationPairs - }); - - // Set optional metadata - if (options?.label) { - attestationDetails.setLabel(options.label); - } - if (options?.id) { - attestationDetails.setId(options.id); - } - if (options?.timestamp) { - attestationDetails.setTimestamp(new BN(options.timestamp)); - } - - // Update flags based on set metadata - attestationDetails.setFlags(); - - return attestationDetails; - } - - hasLabel(): boolean { - return (this.flags.toNumber() & AttestationDetails.FLAG_LABEL) !== 0; - } - - hasId(): boolean { - return (this.flags.toNumber() & AttestationDetails.FLAG_ID) !== 0; - } - - hasTimestamp(): boolean { - return (this.flags.toNumber() & AttestationDetails.FLAG_TIMESTAMP) !== 0; - } - - setLabel(label: string): void { - this.label = label; - } - - setId(id: string): void { - this.id = id; - } - - setTimestamp(timestamp: BigNumber): void { - this.timestamp = timestamp; - } - - /** - * Calculate flags based on the presence of optional fields - */ - calcFlags(): BigNumber { - let flags = new BN(0); - - if (this.label && this.label.length > 0) { - flags = flags.or(new BN(AttestationDetails.FLAG_LABEL)); - } - - if (this.id && this.id.length > 0) { - flags = flags.or(new BN(AttestationDetails.FLAG_ID)); - } - - if (this.timestamp) { - flags = flags.or(new BN(AttestationDetails.FLAG_TIMESTAMP)); - } - - return flags; - } - - /** - * Set the flags based on calculated values from present fields - */ - setFlags(): void { - this.flags = this.calcFlags(); - } - - /** - * Add a new attestation from a Verus node response - * @param nodeResponse - The JSON object from Verus node: {"signaturedata": ..., "mmrdescriptor": ...} - */ - addAttestation(nodeResponse: { signaturedata: any; mmrdescriptor: any }): void { - const attestationPair = new AttestationPair({ - mmrDescriptor: MMRDescriptor.fromJson(nodeResponse.mmrdescriptor), - signatureData: SignatureData.fromJson(nodeResponse.signaturedata) - }); - - this.attestations.push(attestationPair); - } - - /** - * Add multiple attestations from Verus node responses - * @param nodeResponses - Array of JSON objects from Verus node - */ - addAttestations(nodeResponses: Array<{ signaturedata: any; mmrdescriptor: any }>): void { - const attestationPairs = nodeResponses.map(response => - new AttestationPair({ - mmrDescriptor: MMRDescriptor.fromJson(response.mmrdescriptor), - signatureData: SignatureData.fromJson(response.signaturedata) - }) - ); - - this.attestations.push(...attestationPairs); - } - - /** - * Add an existing AttestationPair to this collection - * @param attestationPair - The AttestationPair to add - */ - addAttestationPair(attestationPair: AttestationPair): void { - this.attestations.push(attestationPair); - } - - /** - * Get the number of attestations in this collection - */ - getAttestationCount(): number { - return this.attestations.length; - } - - getByteLength(): number { - this.setFlags(); - let length = 0; - - length += varint.encodingLength(this.version); - length += varint.encodingLength(this.flags); - - if (this.hasLabel() && this.label) { - const labelBuffer = Buffer.from(this.label, 'utf8'); - length += varuint.encodingLength(labelBuffer.length); - length += labelBuffer.length; - } - - if (this.hasId() && this.id) { - const idBuffer = Buffer.from(this.id, 'utf8'); - length += varuint.encodingLength(idBuffer.length); - length += idBuffer.length; - } - - if (this.hasTimestamp() && this.timestamp) { - length += varint.encodingLength(this.timestamp); - } - - length += varuint.encodingLength(this.attestations.length); - this.attestations.forEach((attestation) => { - length += attestation.getByteLength(); - }); - - return length; - } - - toBuffer(): Buffer { - const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); - - writer.writeVarInt(this.version); - writer.writeVarInt(this.flags); - - if (this.hasLabel() && this.label) { - const labelBuffer = Buffer.from(this.label, 'utf8'); - writer.writeVarSlice(labelBuffer); - } - - if (this.hasId() && this.id) { - const idBuffer = Buffer.from(this.id, 'utf8'); - writer.writeVarSlice(idBuffer); - } - - if (this.hasTimestamp() && this.timestamp) { - writer.writeVarInt(this.timestamp); - } - - writer.writeCompactSize(this.attestations.length); - this.attestations.forEach((attestation) => { - writer.writeSlice(attestation.toBuffer()); - }); - - return writer.buffer; - } - - fromBuffer(buffer: Buffer, offset?: number): number { - const reader = new BufferReader(buffer, offset); - - this.version = reader.readVarInt(); - this.flags = reader.readVarInt(); - - if (this.hasLabel()) { - this.label = reader.readVarSlice().toString('utf8'); - } - - if (this.hasId()) { - this.id = reader.readVarSlice().toString('utf8'); - } - - if (this.hasTimestamp()) { - this.timestamp = reader.readVarInt(); - } - - const attestationsLength = reader.readCompactSize(); - this.attestations = []; - - for (let i = 0; i < attestationsLength; i++) { - const attestation = new AttestationPair(); - reader.offset = attestation.fromBuffer(reader.buffer, reader.offset); - this.attestations.push(attestation); - } - - return reader.offset; - } - - isValid(): boolean { - return this.version.gte(AttestationDetails.FIRST_VERSION) && - this.version.lte(AttestationDetails.LAST_VERSION) && - this.attestations.length > 0; - } - - toJson(): AttestationDetailsJson { - const retval: AttestationDetailsJson = { - version: this.version.toNumber(), - attestations: this.attestations.map((attestation) => attestation.toJson()) - }; - - if (this.flags.gt(new BN(0))) { - retval.flags = this.flags.toNumber(); - } - - if (this.hasLabel() && this.label) { - retval.label = this.label; - } - - if (this.hasId() && this.id) { - retval.id = this.id; - } - - if (this.hasTimestamp() && this.timestamp) { - retval.timestamp = this.timestamp.toNumber(); - } - - return retval; - } -} diff --git a/src/vdxf/classes/datapacket/DataPacketResponse.ts b/src/vdxf/classes/datapacket/DataPacketResponse.ts new file mode 100644 index 00000000..2a701499 --- /dev/null +++ b/src/vdxf/classes/datapacket/DataPacketResponse.ts @@ -0,0 +1,157 @@ + + + +/** + * DataPacketResponse - Class for providing structured responses to various request types + * + * This class serves as a universal response mechanism that can be used to reply to multiple + * types of requests. It packages response data within a DataDescriptor along with metadata + * for request tracking and timestamping. + * + * USAGE AS RESPONSE TO DIFFERENT REQUEST TYPES: + * + * 1. AppEncryptionRequestDetails Response: + * - The DataDescriptor 'data' field contains the encrypted derived seed + * - The requestID references the original AppEncryptionRequestDetails.requestID + * - Enables secure delivery of application-specific encrypted keys + * + * 2. UserDataRequestDetails Response: + * - The DataDescriptor 'data' field contains requested user data/attestations + * - The requestID references the original UserDataRequestDetails.requestID + * - Allows selective disclosure of personal information + * + * 3. UserSpecificDataPacketDetails Response: + * - The DataDescriptor 'data' field contains the response data or signed content + * - The requestID references the original UserSpecificDataPacketDetails.requestID + * - Supports bidirectional data exchange with signatures and statements + * + * REQUEST-RESPONSE CORRELATION: + * Each of the above request types includes its own requestID field. This response object's + * requestID field can be used to match responses back to their originating requests, enabling + * proper request-response correlation in asynchronous communication flows. + * + * GENERAL DATA REPLIES: + * This response format can also be used for other general data replies where: + * - Structured data needs to be transmitted via DataDescriptor + * - Request tracking through requestID is desired + * - Timestamp metadata (createdAt) is needed for the response + * - Response validation and integrity checking via SHA-256 is required + */ + +import { BigNumber } from '../../../utils/types/BigNumber'; +import { BN } from 'bn.js'; +import varint from '../../../utils/varint'; +import bufferutils from '../../../utils/bufferutils'; +const { BufferReader, BufferWriter } = bufferutils; +import { SerializableEntity } from '../../../utils/types/SerializableEntity'; +import { fromBase58Check, toBase58Check } from '../../../utils/address'; +import { HASH160_BYTE_LENGTH, I_ADDR_VERSION } from '../../../constants/vdxf'; +import { DataDescriptor, DataDescriptorJson } from '../../../pbaas'; +import createHash = require("create-hash"); + +export interface DataResponseInterface { + flags?: BigNumber; + requestID?: string; // ID of request, to be referenced in response + data: DataDescriptor; +} + +export interface DataResponseJson { + flags?: number; + requestid?: string; // ID of request, to be referenced in response + data: DataDescriptorJson; +} + +export class DataPacketResponse implements SerializableEntity { + flags?: BigNumber; + requestID?: string; // ID of request, to be referenced in response + data: DataDescriptor; + + static RESPONSE_CONTAINS_REQUEST_ID = new BN(1, 10); + + constructor (initialData?: { + flags?: BigNumber, + requestID?: string, + data: DataDescriptor + }) { + this.flags = initialData && initialData.flags ? initialData.flags : new BN("0", 10); + + if (initialData?.requestID) { + if (!this.containsRequestID()) this.toggleContainsRequestID(); + this.requestID = initialData.requestID; + } + + this.data = initialData && initialData.data ? initialData.data : new DataDescriptor(); + } + + containsRequestID() { + return !!(this.flags.and(DataPacketResponse.RESPONSE_CONTAINS_REQUEST_ID).toNumber()); + } + + toggleContainsRequestID() { + this.flags = this.flags.xor(DataPacketResponse.RESPONSE_CONTAINS_REQUEST_ID); + } + + toSha256() { + return createHash("sha256").update(this.toBuffer()).digest(); + } + + getByteLength(): number { + let length = 0; + + length += varint.encodingLength(this.flags); + + if (this.containsRequestID()) { + length += HASH160_BYTE_LENGTH; + } + + length += this.data.getByteLength(); + + return length; + } + + toBuffer() { + const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); + + writer.writeVarInt(this.flags); + + if (this.containsRequestID()) { + writer.writeSlice(fromBase58Check(this.requestID).hash); + } + + writer.writeSlice(this.data.toBuffer()); + + return writer.buffer; + } + + fromBuffer(buffer: Buffer, offset: number = 0) { + const reader = new BufferReader(buffer, offset); + + this.flags = reader.readVarInt(); + + if (this.containsRequestID()) { + this.requestID = toBase58Check(reader.readSlice(HASH160_BYTE_LENGTH), I_ADDR_VERSION); + } + + this.data = new DataDescriptor(); + this.data.fromBuffer(reader.buffer, reader.offset); + reader.offset += this.data.getByteLength(); + + return reader.offset; + } + + toJson(): DataResponseJson { + return { + flags: this.flags.toNumber(), + requestid: this.containsRequestID() ? this.requestID : undefined, + data: this.data.toJson() + } + } + + static fromJson(json: DataResponseJson): DataPacketResponse { + return new DataPacketResponse({ + flags: new BN(json.flags, 10), + requestID: json.requestid, + data: DataDescriptor.fromJson(json.data) + }); + } +} diff --git a/src/vdxf/classes/envelope/GenericEnvelope.ts b/src/vdxf/classes/envelope/GenericEnvelope.ts new file mode 100644 index 00000000..ed340b8c --- /dev/null +++ b/src/vdxf/classes/envelope/GenericEnvelope.ts @@ -0,0 +1,354 @@ +import bufferutils from "../../../utils/bufferutils"; +import base64url from "base64url"; +import { BN } from 'bn.js'; +import { BigNumber } from "../../../utils/types/BigNumber"; +import { OrdinalVDXFObject, OrdinalVDXFObjectJson } from "../ordinals/OrdinalVDXFObject"; +import varuint from "../../../utils/varuint"; +import { SerializableEntity } from "../../../utils/types/SerializableEntity"; +import { createHash } from "crypto"; +import { VerifiableSignatureData, VerifiableSignatureDataJson } from "../VerifiableSignatureData"; +import { CompactAddressObjectJson, CompactIAddressObject } from "../CompactAddressObject"; + +export interface GenericEnvelopeInterface { + version?: BigNumber; + flags?: BigNumber; + signature?: VerifiableSignatureData; + requestID?: CompactIAddressObject; + createdAt?: BigNumber; + salt?: Buffer; + appOrDelegatedID?: CompactIAddressObject; + details: Array; +} + +export type GenericEnvelopeJson = { + version: string; + flags?: string; + signature?: VerifiableSignatureDataJson; + requestid?: CompactAddressObjectJson; + createdat?: string; + salt?: string; + appOrDelegatedID?: CompactAddressObjectJson; + details: Array; +} + +export class GenericEnvelope implements SerializableEntity { + version: BigNumber; + flags: BigNumber; + signature?: VerifiableSignatureData; + requestID?: CompactIAddressObject; + createdAt?: BigNumber; + salt?: Buffer; // var length buffer + appOrDelegatedID?: CompactIAddressObject; + details: Array; + + static VERSION_CURRENT = new BN(1, 10) + static VERSION_FIRSTVALID = new BN(1, 10) + static VERSION_LASTVALID = new BN(1, 10) + + static BASE_FLAGS = new BN(0, 10) + static FLAG_SIGNED = new BN(1, 10) + static FLAG_HAS_REQUEST_ID = new BN(2, 10) + static FLAG_HAS_CREATED_AT = new BN(4, 10) + static FLAG_MULTI_DETAILS = new BN(8, 10) + static FLAG_IS_TESTNET = new BN(16, 10) + static FLAG_HAS_SALT = new BN(32, 10) + static FLAG_HAS_APP_OR_DELEGATED_ID = new BN(64, 10); + + constructor( + envelope: GenericEnvelopeInterface = { + details: [], + flags: GenericEnvelope.BASE_FLAGS + } + ) { + this.signature = envelope?.signature; + this.requestID = envelope?.requestID; + this.details = envelope?.details; + this.createdAt = envelope?.createdAt; + this.salt = envelope?.salt; + this.appOrDelegatedID = envelope?.appOrDelegatedID; + + if (envelope?.flags) this.flags = envelope.flags; + else this.flags = GenericEnvelope.BASE_FLAGS; + + if (envelope?.version) this.version = envelope.version; + else this.version = GenericEnvelope.VERSION_CURRENT; + + this.setFlags(); + } + + isValidVersion(): boolean { + return this.version.gte(GenericEnvelope.VERSION_FIRSTVALID) && this.version.lte(GenericEnvelope.VERSION_LASTVALID); + } + + isSigned() { + return !!(this.flags.and(GenericEnvelope.FLAG_SIGNED).toNumber()); + } + + hasRequestID() { + return !!(this.flags.and(GenericEnvelope.FLAG_HAS_REQUEST_ID).toNumber()); + } + + hasMultiDetails() { + return !!(this.flags.and(GenericEnvelope.FLAG_MULTI_DETAILS).toNumber()); + } + + hasCreatedAt() { + return !!(this.flags.and(GenericEnvelope.FLAG_HAS_CREATED_AT).toNumber()); + } + + hasSalt() { + return !!(this.flags.and(GenericEnvelope.FLAG_HAS_SALT).toNumber()); + } + + hasAppOrDelegatedID() { + return !!(this.flags.and(GenericEnvelope.FLAG_HAS_APP_OR_DELEGATED_ID).toNumber()); + } + + isTestnet() { + return !!(this.flags.and(GenericEnvelope.FLAG_IS_TESTNET).toNumber()); + } + + setSigned() { + this.flags = this.flags.or(GenericEnvelope.FLAG_SIGNED); + } + + setHasRequestID() { + this.flags = this.flags.or(GenericEnvelope.FLAG_HAS_REQUEST_ID); + } + + setHasMultiDetails() { + this.flags = this.flags.or(GenericEnvelope.FLAG_MULTI_DETAILS); + } + + setHasCreatedAt() { + this.flags = this.flags.or(GenericEnvelope.FLAG_HAS_CREATED_AT); + } + + setHasSalt() { + this.flags = this.flags.or(GenericEnvelope.FLAG_HAS_SALT); + } + + setHasAppOrDelegatedID() { + this.flags = this.flags.or(GenericEnvelope.FLAG_HAS_APP_OR_DELEGATED_ID); + } + + setIsTestnet() { + this.flags = this.flags.or(GenericEnvelope.FLAG_IS_TESTNET); + } + + setFlags() { + if (this.signature) this.setSigned(); + if (this.requestID) this.setHasRequestID(); + if (this.createdAt) this.setHasCreatedAt(); + if (this.salt) this.setHasSalt(); + if (this.appOrDelegatedID) this.setHasAppOrDelegatedID(); + if (this.details && this.details.length > 1) this.setHasMultiDetails(); + } + + getRawDataSha256(includeSig = false) { + return createHash("sha256").update(this.toBufferOptionalSig(includeSig)).digest(); + } + + getDetailsIdentitySignatureHash(signedBlockheight: number): Buffer { + if (this.isSigned()) { + return this.signature.getIdentityHash(signedBlockheight, this.getRawDataSha256()); + } else throw new Error("Must contain verifiable signature with at least systemID and identityID to generate details identity signature hash") + } + + getDetails(index = 0): OrdinalVDXFObject { + return this.details[index]; + } + + protected getDataBufferLengthAfterSig(): number { + let length = 0; + + if (this.hasRequestID()) { + length += this.requestID.getByteLength(); + } + + if (this.hasCreatedAt()) { + length += varuint.encodingLength(this.createdAt.toNumber()); + } + + if (this.hasSalt()) { + const saltLen = this.salt.length; + + length += varuint.encodingLength(saltLen); + length += saltLen; + } + + if (this.hasAppOrDelegatedID()) { + length += this.appOrDelegatedID.getByteLength(); + } + + if (this.hasMultiDetails()) { + length += varuint.encodingLength(this.details.length); + + for (const detail of this.details) { + length += detail.getByteLength(); + } + } else { + length += this.getDetails().getByteLength(); + } + + return length; + } + + protected getDataBufferAfterSig(): Buffer { + const writer = new bufferutils.BufferWriter( + Buffer.alloc(this.getDataBufferLengthAfterSig()) + ); + + if (this.hasRequestID()) { + writer.writeSlice(this.requestID.toBuffer()); + } + + if (this.hasCreatedAt()) { + writer.writeCompactSize(this.createdAt.toNumber()); + } + + if (this.hasSalt()) { + writer.writeVarSlice(this.salt); + } + + if (this.hasAppOrDelegatedID()) { + writer.writeSlice(this.appOrDelegatedID.toBuffer()); + } + + if (this.hasMultiDetails()) { + writer.writeCompactSize(this.details.length); + + for (const detail of this.details) { + writer.writeSlice(detail.toBuffer()); + } + } else { + writer.writeSlice(this.getDetails().toBuffer()); + } + + return writer.buffer; + } + + private internalGetByteLength(includeSig = true): number { + let length = 0; + + length += varuint.encodingLength(this.version.toNumber()); + length += varuint.encodingLength(this.flags.toNumber()); + + if (this.isSigned() && includeSig) { + length += this.signature!.getByteLength(); + } + + length += this.getDataBufferLengthAfterSig(); + + return length; + } + + protected getByteLengthOptionalSig(includeSig?: boolean): number { + return this.internalGetByteLength(includeSig); + } + + getByteLength(): number { + return this.getByteLengthOptionalSig(true); + } + + protected toBufferOptionalSig(includeSig = true) { + const writer = new bufferutils.BufferWriter( + Buffer.alloc(this.internalGetByteLength(includeSig)) + ); + + writer.writeCompactSize(this.version.toNumber()); + writer.writeCompactSize(this.flags.toNumber()); + + if (this.isSigned() && includeSig) { + writer.writeSlice(this.signature!.toBuffer()); + } + + writer.writeSlice(this.getDataBufferAfterSig()); + + return writer.buffer; + } + + toBuffer(): Buffer { + return this.toBufferOptionalSig(true); + } + + fromBuffer(buffer: Buffer, offset?: number): number { + if (buffer.length == 0) throw new Error("Cannot create envelope from empty buffer"); + + const reader = new bufferutils.BufferReader(buffer, offset); + + this.version = new BN(reader.readCompactSize()); + this.flags = new BN(reader.readCompactSize()); + + if (this.isSigned()) { + const _sig = new VerifiableSignatureData(); + reader.offset = _sig.fromBuffer(reader.buffer, reader.offset); + this.signature = _sig; + } + + if (this.hasRequestID()) { + this.requestID = new CompactIAddressObject(); + + reader.offset = this.requestID.fromBuffer(reader.buffer, reader.offset); + } + + if (this.hasCreatedAt()) { + this.createdAt = new BN(reader.readCompactSize()); + } + + if (this.hasSalt()) { + this.salt = reader.readVarSlice(); + } + + if (this.hasAppOrDelegatedID()) { + this.appOrDelegatedID = new CompactIAddressObject(); + + reader.offset = this.appOrDelegatedID.fromBuffer(reader.buffer, reader.offset); + } + + if (this.hasMultiDetails()) { + this.details = []; + + const numItems = reader.readCompactSize(); + + for (let i = 0; i < numItems; i++) { + const ord = OrdinalVDXFObject.createFromBuffer(reader.buffer, reader.offset); + + reader.offset = ord.offset; + this.details.push(ord.obj); + } + } else { + const ord = OrdinalVDXFObject.createFromBuffer(reader.buffer, reader.offset); + + reader.offset = ord.offset; + this.details = [ord.obj]; + } + + return reader.offset; + } + + toString() { + return base64url.encode(this.toBuffer()); + } + + toJson(): GenericEnvelopeJson { + const details = []; + + if (this.details != null) { + for (const detail of this.details) { + details.push(detail.toJson()) + } + } + + return { + version: this.version.toString(), + flags: this.flags.toString(), + signature: this.isSigned() ? this.signature.toJson() : undefined, + requestid: this.hasRequestID() ? this.requestID.toJson() : undefined, + createdat: this.hasCreatedAt() ? this.createdAt.toString() : undefined, + salt: this.hasSalt() ? this.salt.toString('hex') : undefined, + appOrDelegatedID: this.hasAppOrDelegatedID() ? this.appOrDelegatedID.toJson() : undefined, + details: details + }; + } +} \ No newline at end of file diff --git a/src/vdxf/classes/identity/IdentityUpdateEnvelope.ts b/src/vdxf/classes/identity/IdentityUpdateEnvelope.ts deleted file mode 100644 index 5e7b32ac..00000000 --- a/src/vdxf/classes/identity/IdentityUpdateEnvelope.ts +++ /dev/null @@ -1,301 +0,0 @@ -import { - WALLET_VDXF_KEY, - VDXFObject, - VerusIDSignature, - VerusIDSignatureJson, -} from "../.."; -import { IDENTITY_AUTH_SIG_VDXF_KEY, IDENTITY_UPDATE_REQUEST_VDXF_KEY, IDENTITY_UPDATE_RESPONSE_VDXF_KEY } from "../../keys"; -import bufferutils from "../../../utils/bufferutils"; -import { VERUS_DATA_SIGNATURE_PREFIX } from "../../../constants/vdxf"; -import createHash = require("create-hash"); -import base64url from "base64url"; -import { BN } from 'bn.js'; -import { BigNumber } from "../../../utils/types/BigNumber"; -import { IdentityUpdateRequestDetails, IdentityUpdateRequestDetailsJson } from "./IdentityUpdateRequestDetails"; -import { IdentityID } from "../../../pbaas"; -import { IdentityUpdateResponseDetails, IdentityUpdateResponseDetailsJson } from "./IdentityUpdateResponseDetails"; - -export const IDENTITY_UPDATE_VERSION_CURRENT = new BN(1, 10) -export const IDENTITY_UPDATE_VERSION_FIRSTVALID = new BN(1, 10) -export const IDENTITY_UPDATE_VERSION_LASTVALID = new BN(1, 10) -export const IDENTITY_UPDATE_VERSION_SIGNED = new BN('80000000', 16) -export const IDENTITY_UPDATE_VERSION_MASK = IDENTITY_UPDATE_VERSION_SIGNED; - -export type IdentityUpdateDetails = IdentityUpdateRequestDetails | IdentityUpdateResponseDetails; -export type IdentityUpdateDetailsJson = IdentityUpdateRequestDetailsJson | IdentityUpdateResponseDetailsJson; - -export interface IdentityUpdateEnvelopeInterface { - details: IdentityUpdateDetails; - systemid?: IdentityID; - signingid?: IdentityID; - signature?: string; - version?: BigNumber; -} - -export interface IdentityUpdateEnvelopeJson { - details: IdentityUpdateDetailsJson; - systemid?: string; - signingid?: string; - signature?: string; - version?: string; -} - -export class IdentityUpdateEnvelope extends VDXFObject { - systemid: IdentityID; - signingid: IdentityID; - signature?: VerusIDSignature; - details: IdentityUpdateDetails; - - constructor( - vdxfkey: string, - request: IdentityUpdateEnvelopeInterface = { - details: undefined - } - ) { - super(vdxfkey); - - if (request.version) this.version = request.version; - else this.version = IDENTITY_UPDATE_VERSION_CURRENT; - - if (!request.details) { - this.details = this.createEmptyDetails(); - } - - this.systemid = request.systemid; - this.signingid = request.signingid; - - if (request.signature) { - this.signature = new VerusIDSignature( - { signature: request.signature }, - IDENTITY_AUTH_SIG_VDXF_KEY, - false - ); - - this.setSigned() - } - - this.details = request.details; - } - - private createEmptyDetails(): IdentityUpdateDetails { - if (this.vdxfkey === IDENTITY_UPDATE_REQUEST_VDXF_KEY.vdxfid) { - return new IdentityUpdateRequestDetails(); - } else if (this.vdxfkey === IDENTITY_UPDATE_RESPONSE_VDXF_KEY.vdxfid) { - return new IdentityUpdateResponseDetails(); - } else throw new Error("Unrecognized vdxf key for identity update"); - } - - getVersionNoFlags(): BigNumber { - return this.version.and(IDENTITY_UPDATE_VERSION_MASK.notn(IDENTITY_UPDATE_VERSION_MASK.bitLength())) - } - - isValidVersion(): boolean { - return this.getVersionNoFlags().gte(IDENTITY_UPDATE_VERSION_FIRSTVALID) && this.getVersionNoFlags().lte(IDENTITY_UPDATE_VERSION_LASTVALID); - } - - isSigned() { - return !!(this.version.and(IDENTITY_UPDATE_VERSION_SIGNED).toNumber()); - } - - setSigned() { - this.version = this.version.xor(IDENTITY_UPDATE_VERSION_SIGNED); - } - - getDetailsHash(signedBlockheight: number, signatureVersion: number = 2) { - if (this.isSigned()) { - var heightBufferWriter = new bufferutils.BufferWriter( - Buffer.allocUnsafe(4) - ); - heightBufferWriter.writeUInt32(signedBlockheight); - - if (signatureVersion === 1) { - return createHash("sha256") - .update(VERUS_DATA_SIGNATURE_PREFIX) - .update(this.systemid.toBuffer()) - .update(heightBufferWriter.buffer) - .update(this.signingid.toBuffer()) - .update(this.details.toSha256()) - .digest(); - } else { - return createHash("sha256") - .update(this.systemid.toBuffer()) - .update(heightBufferWriter.buffer) - .update(this.signingid.toBuffer()) - .update(VERUS_DATA_SIGNATURE_PREFIX) - .update(this.details.toSha256()) - .digest(); - } - } else return this.details.toSha256() - } - - protected _dataByteLength(signer: IdentityID = this.signingid): number { - if (this.isSigned()) { - let length = 0; - - const _signature = this.signature - ? this.signature - : new VerusIDSignature( - { signature: "" }, - IDENTITY_AUTH_SIG_VDXF_KEY, - false - ); - - length += this.systemid.getByteLength(); - - length += signer.getByteLength(); - - length += _signature.byteLength(); - length += this.details.getByteLength(); - - return length; - } else return this.details.getByteLength() - } - - protected _toDataBuffer(signer: IdentityID = this.signingid): Buffer { - const writer = new bufferutils.BufferWriter( - Buffer.alloc(this.dataByteLength()) - ); - - if (this.isSigned()) { - const _signature = this.signature - ? this.signature - : new VerusIDSignature( - { signature: "" }, - IDENTITY_AUTH_SIG_VDXF_KEY, - false - ); - - writer.writeSlice(this.systemid.toBuffer()); - - writer.writeSlice(signer.toBuffer()); - - writer.writeSlice(_signature.toBuffer()); - } - - writer.writeSlice(this.details.toBuffer()); - - return writer.buffer; - } - - dataByteLength(): number { - return this._dataByteLength(); - } - - toDataBuffer(): Buffer { - return this._toDataBuffer(); - } - - protected _fromDataBuffer(buffer: Buffer, offset?: number): number { - const reader = new bufferutils.BufferReader(buffer, offset); - const reqLength = reader.readCompactSize(); - - if (reqLength == 0) { - throw new Error("Cannot create request from empty buffer"); - } else { - if (this.isSigned()) { - this.systemid = new IdentityID(); - reader.offset = this.systemid.fromBuffer(reader.buffer, reader.offset); - - this.signingid = new IdentityID(); - reader.offset = this.signingid.fromBuffer(reader.buffer, reader.offset); - - const _sig = new VerusIDSignature(undefined, IDENTITY_AUTH_SIG_VDXF_KEY, false); - reader.offset = _sig.fromBuffer(reader.buffer, reader.offset, IDENTITY_AUTH_SIG_VDXF_KEY.vdxfid); - this.signature = _sig; - } - - const _details = this.createEmptyDetails(); - reader.offset = _details.fromBuffer(reader.buffer, reader.offset); - this.details = _details; - } - - return reader.offset; - } - - fromDataBuffer(buffer: Buffer, offset?: number): number { - return this._fromDataBuffer(buffer, offset); - } - - toWalletDeeplinkUri(): string { - return `${WALLET_VDXF_KEY.vdxfid.toLowerCase()}://x-callback-url/${ - IDENTITY_UPDATE_REQUEST_VDXF_KEY.vdxfid - }/${this.toString(false)}`; - } - - static fromWalletDeeplinkUri(vdxfkey: string, uri: string): IdentityUpdateEnvelope { - const split = uri.split(`${IDENTITY_UPDATE_REQUEST_VDXF_KEY.vdxfid}/`); - const inv = new IdentityUpdateEnvelope(vdxfkey); - inv.fromBuffer(base64url.toBuffer(split[1]), 0, IDENTITY_UPDATE_REQUEST_VDXF_KEY.vdxfid); - - return inv; - } - - toQrString(): string { - return this.toString(true); - } - - static fromQrString(vdxfkey: string, qrstring: string): IdentityUpdateEnvelope { - const inv = new IdentityUpdateEnvelope(vdxfkey); - inv.fromBuffer(base64url.toBuffer(qrstring), 0); - - return inv; - } - - toJson(): IdentityUpdateEnvelopeJson { - return { - systemid: this.systemid ? this.systemid.toAddress() : undefined, - signingid: this.signingid ? this.signingid.toAddress() : undefined, - signature: this.signature ? this.signature.signature : undefined, - details: this.details ? this.details.toJson() : undefined - } - } - - protected static internalFromJson( - json: IdentityUpdateEnvelopeJson, - ctor: new (...args: any[]) => T, - detailsFromJson: (json: IdentityUpdateDetailsJson) => IdentityUpdateDetails - ): T { - return new ctor({ - systemid: json.systemid ? IdentityID.fromAddress(json.systemid) : undefined, - signingid: json.signingid ? IdentityID.fromAddress(json.signingid) : undefined, - signature: json.signature, - details: json.details ? detailsFromJson(json.details) : undefined - }); - } -} - -export class IdentityUpdateRequest extends IdentityUpdateEnvelope { - constructor(request?: IdentityUpdateEnvelopeInterface) { - super(IDENTITY_UPDATE_REQUEST_VDXF_KEY.vdxfid, request); - } - - static fromWalletDeeplinkUri(uri: string): IdentityUpdateRequest { - return (IdentityUpdateEnvelope.fromWalletDeeplinkUri(IDENTITY_UPDATE_REQUEST_VDXF_KEY.vdxfid, uri) as IdentityUpdateRequest); - } - - static fromQrString(qrstring: string): IdentityUpdateRequest { - return (IdentityUpdateEnvelope.fromQrString(IDENTITY_UPDATE_REQUEST_VDXF_KEY.vdxfid, qrstring) as IdentityUpdateRequest); - } - - static fromJson(json: IdentityUpdateEnvelopeJson) { - return IdentityUpdateEnvelope.internalFromJson(json, IdentityUpdateRequest, IdentityUpdateRequestDetails.fromJson); - } -} - -export class IdentityUpdateResponse extends IdentityUpdateEnvelope { - constructor(response?: IdentityUpdateEnvelopeInterface) { - super(IDENTITY_UPDATE_RESPONSE_VDXF_KEY.vdxfid, response); - } - - static fromWalletDeeplinkUri(uri: string): IdentityUpdateEnvelope { - return IdentityUpdateEnvelope.fromWalletDeeplinkUri(IDENTITY_UPDATE_RESPONSE_VDXF_KEY.vdxfid, uri); - } - - static fromQrString(qrstring: string): IdentityUpdateResponse { - return (IdentityUpdateEnvelope.fromQrString(IDENTITY_UPDATE_RESPONSE_VDXF_KEY.vdxfid, qrstring) as IdentityUpdateResponse); - } - - static fromJson(json: IdentityUpdateEnvelopeJson) { - return IdentityUpdateEnvelope.internalFromJson(json, IdentityUpdateResponse, IdentityUpdateResponseDetails.fromJson); - } -} diff --git a/src/vdxf/classes/identity/IdentityUpdateRequestDetails.ts b/src/vdxf/classes/identity/IdentityUpdateRequestDetails.ts index b5062244..d225e2ce 100644 --- a/src/vdxf/classes/identity/IdentityUpdateRequestDetails.ts +++ b/src/vdxf/classes/identity/IdentityUpdateRequestDetails.ts @@ -1,4 +1,3 @@ -import varint from '../../../utils/varint' import varuint from '../../../utils/varuint' import bufferutils from '../../../utils/bufferutils' import { fromBase58Check, nameAndParentAddrToIAddr, toBase58Check } from '../../../utils/address'; @@ -9,7 +8,6 @@ import { PartialSignData, PartialSignDataCLIJson, PartialSignDataJson } from '.. import { BigNumber } from '../../../utils/types/BigNumber'; import { BN } from 'bn.js'; import { ContentMultiMapJsonValue, IdentityID, VerusCLIVerusIDJson, VerusCLIVerusIDJsonBase } from '../../../pbaas'; -import { ResponseUri, ResponseUriJson } from '../ResponseUri'; import { SerializableEntity } from '../../../utils/types/SerializableEntity'; import { UINT_256_LENGTH } from '../../../constants/pbaas'; @@ -22,72 +20,58 @@ export type VerusCLIVerusIDJsonWithData = VerusCLIVerusIDJsonBase<{ [key: string export type IdentityUpdateRequestDetailsJson = { flags?: string; requestid?: string; - createdat?: string; identity?: VerusCLIVerusIDJson; expiryheight?: string; systemid?: string; - responseuris?: Array; signdatamap?: { [key: string]: PartialSignDataJson }; - salt?: string; txid?: string; } export class IdentityUpdateRequestDetails implements SerializableEntity { flags?: BigNumber; - requestid?: BigNumber; // ID of request, to be referenced in response - createdat?: BigNumber; // Unix timestamp of request creation + requestID?: string; // ID of request, to be referenced in response identity?: PartialIdentity; // Parts of the identity to update - expiryheight?: BigNumber; // Time after which update request will no longer be accepted - systemid?: IdentityID; // System that identity should be updated on (will default to VRSC/VRSCTEST if not present, depending on testnet flag) - responseuris?: Array; // Array of uris + type to send response to (type can be post, redirect, etc. depending on how response is expected to be received) - signdatamap?: SignDataMap; // Map of data to pass to signdata - salt?: Buffer; // Optional salt + expiryHeight?: BigNumber; // Time after which update request will no longer be accepted + systemID?: IdentityID; // System that identity should be updated on (will default to VRSC/VRSCTEST if not present, depending on testnet flag) + signDataMap?: SignDataMap; // Map of data to pass to signdata txid?: Buffer; // 32 byte transaction ID of transaction that must be spent to update identity, on same system asked for in request // stored in natural order, if displayed as text make sure to reverse! static IDENTITY_UPDATE_REQUEST_VALID = new BN(0, 10); static IDENTITY_UPDATE_REQUEST_CONTAINS_SIGNDATA = new BN(1, 10); static IDENTITY_UPDATE_REQUEST_EXPIRES = new BN(2, 10); - static IDENTITY_UPDATE_REQUEST_CONTAINS_RESPONSE_URIS = new BN(4, 10); + static IDENTITY_UPDATE_REQUEST_CONTAINS_REQUEST_ID = new BN(4, 10); static IDENTITY_UPDATE_REQUEST_CONTAINS_SYSTEM = new BN(8, 10); static IDENTITY_UPDATE_REQUEST_CONTAINS_TXID = new BN(16, 10); - static IDENTITY_UPDATE_REQUEST_CONTAINS_SALT = new BN(32, 10); - static IDENTITY_UPDATE_REQUEST_IS_TESTNET = new BN(64, 10); constructor (data?: { flags?: BigNumber, - requestid?: BigNumber, - createdat?: BigNumber, + requestID?: string, identity?: PartialIdentity, - expiryheight?: BigNumber, - systemid?: IdentityID, + expiryHeight?: BigNumber, + systemID?: IdentityID, txid?: Buffer, - responseuris?: Array, - signdatamap?: SignDataMap, - salt?: Buffer + signDataMap?: SignDataMap }) { this.flags = data && data.flags ? data.flags : new BN("0", 10); - if (data?.requestid) { - this.requestid = data.requestid; - } else this.requestid = new BN("0", 10); - - if (data?.createdat) { - this.createdat = data.createdat; - } else this.createdat = new BN("0", 10); + if (data?.requestID) { + if (!this.containsRequestID()) this.toggleContainsRequestID(); + this.requestID = data.requestID; + } if (data?.identity) { this.identity = data.identity; } - if (data?.expiryheight) { + if (data?.expiryHeight) { if (!this.expires()) this.toggleExpires(); - this.expiryheight = data.expiryheight; + this.expiryHeight = data.expiryHeight; } - if (data?.systemid) { + if (data?.systemID) { if (!this.containsSystem()) this.toggleContainsSystem(); - this.systemid = data.systemid; + this.systemID = data.systemID; } if (data?.txid) { @@ -95,19 +79,9 @@ export class IdentityUpdateRequestDetails implements SerializableEntity { this.txid = data.txid; } - if (data?.responseuris) { - if (!this.containsResponseUris()) this.toggleContainsResponseUris(); - this.responseuris = data.responseuris; - } - - if (data?.signdatamap) { + if (data?.signDataMap) { if (!this.containsSignData()) this.toggleContainsSignData(); - this.signdatamap = data.signdatamap; - } - - if (data?.salt) { - if (!this.containsSalt()) this.toggleContainsSalt(); - this.salt = data.salt; + this.signDataMap = data.signDataMap; } } @@ -123,20 +97,12 @@ export class IdentityUpdateRequestDetails implements SerializableEntity { return !!(this.flags.and(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_SYSTEM).toNumber()); } - containsTxid() { - return !!(this.flags.and(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_TXID).toNumber()); + containsRequestID() { + return !!(this.flags.and(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_REQUEST_ID).toNumber()); } - containsResponseUris() { - return !!(this.flags.and(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_RESPONSE_URIS).toNumber()); - } - - containsSalt() { - return !!(this.flags.and(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_SALT).toNumber()); - } - - isTestnet() { - return !!(this.flags.and(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_IS_TESTNET).toNumber()); + containsTxid() { + return !!(this.flags.and(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_TXID).toNumber()); } toggleExpires() { @@ -151,32 +117,24 @@ export class IdentityUpdateRequestDetails implements SerializableEntity { this.flags = this.flags.xor(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_SYSTEM); } - toggleContainsTxid() { - this.flags = this.flags.xor(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_TXID); - } - - toggleContainsResponseUris() { - this.flags = this.flags.xor(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_RESPONSE_URIS); + toggleContainsRequestID() { + this.flags = this.flags.xor(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_REQUEST_ID); } - toggleContainsSalt() { - this.flags = this.flags.xor(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_SALT); - } - - toggleIsTestnet() { - this.flags = this.flags.xor(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_IS_TESTNET); + toggleContainsTxid() { + this.flags = this.flags.xor(IdentityUpdateRequestDetails.IDENTITY_UPDATE_REQUEST_CONTAINS_TXID); } toSha256() { return createHash("sha256").update(this.toBuffer()).digest(); } - getIdentityAddress() { + getIdentityAddress(isTestnet: boolean = false) { if (this.identity.name === "VRSC" || this.identity.name === "VRSCTEST") { return nameAndParentAddrToIAddr(this.identity.name); } else if (this.identity.parent) { return this.identity.getIdentityAddress(); - } else if (this.isTestnet()) { + } else if (isTestnet) { return nameAndParentAddrToIAddr(this.identity.name, nameAndParentAddrToIAddr("VRSCTEST")); } else { return nameAndParentAddrToIAddr(this.identity.name, nameAndParentAddrToIAddr("VRSC")); @@ -186,60 +144,47 @@ export class IdentityUpdateRequestDetails implements SerializableEntity { getByteLength(): number { let length = 0; - length += varint.encodingLength(this.flags); - - length += varint.encodingLength(this.requestid); + length += varuint.encodingLength(this.flags.toNumber()); - length += varint.encodingLength(this.createdat); + if (this.containsRequestID()) { + length += HASH160_BYTE_LENGTH; + } length += this.identity.getByteLength(); - if (this.expires()) length += varint.encodingLength(this.expiryheight); + if (this.expires()) length += varuint.encodingLength(this.expiryHeight.toNumber()); - if (this.containsSystem()) length += this.systemid.getByteLength(); + if (this.containsSystem()) length += this.systemID.getByteLength(); if (this.containsTxid()) { length += UINT_256_LENGTH; } - if (this.containsResponseUris()) { - length += varuint.encodingLength(this.responseuris.length); - length += this.responseuris.reduce( - (sum: number, current: ResponseUri) => sum + current.getByteLength(), - 0 - ); - } - if (this.containsSignData()) { - length += varuint.encodingLength(this.signdatamap.size); - for (const [key, value] of this.signdatamap.entries()) { + length += varuint.encodingLength(this.signDataMap.size); + for (const [key, value] of this.signDataMap.entries()) { length += fromBase58Check(key).hash.length; length += value.getByteLength(); } } - if (this.containsSalt()) { - length += varuint.encodingLength(this.salt.length); - length += this.salt.length; - } - return length; } toBuffer() { const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); - writer.writeVarInt(this.flags); - - writer.writeVarInt(this.requestid); + writer.writeCompactSize(this.flags.toNumber()); - writer.writeVarInt(this.createdat); + if (this.containsRequestID()) { + writer.writeSlice(fromBase58Check(this.requestID).hash); + } writer.writeSlice(this.identity.toBuffer()); - if (this.expires()) writer.writeVarInt(this.expiryheight); + if (this.expires()) writer.writeCompactSize(this.expiryHeight.toNumber()); - if (this.containsSystem()) writer.writeSlice(this.systemid.toBuffer()); + if (this.containsSystem()) writer.writeSlice(this.systemID.toBuffer()); if (this.containsTxid()) { if (this.txid.length !== UINT_256_LENGTH) throw new Error("invalid txid length"); @@ -247,66 +192,44 @@ export class IdentityUpdateRequestDetails implements SerializableEntity { writer.writeSlice(this.txid); } - if (this.containsResponseUris()) { - writer.writeArray(this.responseuris.map((x) => x.toBuffer())); - } - if (this.containsSignData()) { - writer.writeCompactSize(this.signdatamap.size); - for (const [key, value] of this.signdatamap.entries()) { + writer.writeCompactSize(this.signDataMap.size); + for (const [key, value] of this.signDataMap.entries()) { writer.writeSlice(fromBase58Check(key).hash); writer.writeSlice(value.toBuffer()); } } - if (this.containsSalt()) { - writer.writeVarSlice(this.salt); - } - return writer.buffer; } fromBuffer(buffer: Buffer, offset: number = 0, parseVdxfObjects: boolean = true) { const reader = new BufferReader(buffer, offset); - this.flags = reader.readVarInt(); - - this.requestid = reader.readVarInt(); + this.flags = new BN(reader.readCompactSize()); - this.createdat = reader.readVarInt(); + if (this.containsRequestID()) { + this.requestID = toBase58Check(reader.readSlice(HASH160_BYTE_LENGTH), I_ADDR_VERSION); + } this.identity = new PartialIdentity(); reader.offset = this.identity.fromBuffer(reader.buffer, reader.offset, parseVdxfObjects); if (this.expires()) { - this.expiryheight = reader.readVarInt(); + this.expiryHeight = new BN(reader.readCompactSize()); } if (this.containsSystem()) { - this.systemid = new IdentityID(); - reader.offset = this.systemid.fromBuffer(reader.buffer, reader.offset); + this.systemID = new IdentityID(); + reader.offset = this.systemID.fromBuffer(reader.buffer, reader.offset); } if (this.containsTxid()) { this.txid = reader.readSlice(UINT_256_LENGTH); } - if (this.containsResponseUris()) { - this.responseuris = []; - const urisLength = reader.readCompactSize(); - - for (let i = 0; i < urisLength; i++) { - const uri = new ResponseUri(); - reader.offset = uri.fromBuffer( - reader.buffer, - reader.offset - ); - this.responseuris.push(uri); - } - } - if (this.containsSignData()) { - this.signdatamap = new Map(); + this.signDataMap = new Map(); const size = reader.readCompactSize(); @@ -316,63 +239,53 @@ export class IdentityUpdateRequestDetails implements SerializableEntity { reader.offset = value.fromBuffer(reader.buffer, reader.offset); - this.signdatamap.set(key, value); + this.signDataMap.set(key, value); } } - if (this.containsSalt()) { - this.salt = reader.readVarSlice() - } - return reader.offset; } toJson(): IdentityUpdateRequestDetailsJson { let signDataJson: { [key: string]: PartialSignDataJson }; - if (this.signdatamap) { + if (this.signDataMap) { signDataJson = {}; - for (const [key, psd] of this.signdatamap.entries()) { + for (const [key, psd] of this.signDataMap.entries()) { signDataJson[key] = psd.toJson(); } } return { flags: this.flags ? this.flags.toString(10) : undefined, - requestid: this.requestid ? this.requestid.toString(10) : undefined, - createdat: this.createdat ? this.createdat.toString(10) : undefined, + requestid: this.containsRequestID() ? this.requestID : undefined, identity: this.identity ? this.identity.toJson() : undefined, - expiryheight: this.expiryheight ? this.expiryheight.toString(10) : undefined, - systemid: this.systemid ? this.systemid.toAddress() : undefined, + expiryheight: this.expiryHeight ? this.expiryHeight.toString(10) : undefined, + systemid: this.systemID ? this.systemID.toAddress() : undefined, txid: this.txid ? (Buffer.from(this.txid.toString('hex'), 'hex').reverse()).toString('hex') : undefined, - responseuris: this.responseuris ? this.responseuris.map(x => x.toJson()) : undefined, - signdatamap: signDataJson, - salt: this.salt ? this.salt.toString('hex') : undefined + signdatamap: signDataJson } } static fromJson(json: IdentityUpdateRequestDetailsJson): IdentityUpdateRequestDetails { - let signdatamap: SignDataMap; + let signDataMap: SignDataMap; if (json.signdatamap) { - signdatamap = new Map(); + signDataMap = new Map(); for (const key in json.signdatamap) { - signdatamap.set(key, PartialSignData.fromJson(json.signdatamap[key])) + signDataMap.set(key, PartialSignData.fromJson(json.signdatamap[key])) } } return new IdentityUpdateRequestDetails({ flags: json.flags ? new BN(json.flags, 10) : undefined, - requestid: json.requestid ? new BN(json.requestid, 10) : undefined, - createdat: json.createdat ? new BN(json.createdat, 10) : undefined, + requestID: json.requestid, identity: json.identity ? PartialIdentity.fromJson(json.identity) : undefined, - expiryheight: json.expiryheight ? new BN(json.expiryheight, 10) : undefined, - systemid: json.systemid ? IdentityID.fromAddress(json.systemid) : undefined, - responseuris: json.responseuris ? json.responseuris.map(x => ResponseUri.fromJson(x)) : undefined, - signdatamap, - salt: json.salt ? Buffer.from(json.salt, 'hex') : undefined, + expiryHeight: json.expiryheight ? new BN(json.expiryheight, 10) : undefined, + systemID: json.systemid ? IdentityID.fromAddress(json.systemid) : undefined, + signDataMap, txid: json.txid ? Buffer.from(json.txid, 'hex').reverse() : undefined, }) } @@ -383,7 +296,7 @@ export class IdentityUpdateRequestDetails implements SerializableEntity { const idJson = (this.identity.toJson() as VerusCLIVerusIDJsonWithData); if (this.containsSignData()) { - for (const [key, psd] of this.signdatamap.entries()) { + for (const [key, psd] of this.signDataMap.entries()) { idJson.contentmultimap[key] = { "data": psd.toCLIJson() } @@ -398,17 +311,17 @@ export class IdentityUpdateRequestDetails implements SerializableEntity { details?: IdentityUpdateRequestDetailsJson ): IdentityUpdateRequestDetails { let identity: PartialIdentity; - let signdatamap: SignDataMap; + let signDataMap: SignDataMap; if (json.contentmultimap) { const cmm = { ...json.contentmultimap }; for (const key in cmm) { if (cmm[key]['data']) { - if (!signdatamap) signdatamap = new Map(); + if (!signDataMap) signDataMap = new Map(); const psd = PartialSignData.fromCLIJson(cmm[key]['data']); - signdatamap.set(key, psd); + signDataMap.set(key, psd); delete cmm[key]; } @@ -421,14 +334,11 @@ export class IdentityUpdateRequestDetails implements SerializableEntity { return new IdentityUpdateRequestDetails({ identity, - signdatamap, - systemid: details?.systemid ? IdentityID.fromAddress(details.systemid) : undefined, - requestid: details?.requestid ? new BN(details.requestid, 10) : undefined, - createdat: details?.createdat ? new BN(details.createdat, 10) : undefined, - expiryheight: details?.expiryheight ? new BN(details.expiryheight, 10) : undefined, - responseuris: details?.responseuris ? details.responseuris.map(x => ResponseUri.fromJson(x)) : undefined, - salt: details?.salt ? Buffer.from(details.salt, 'hex') : undefined, + signDataMap, + systemID: details?.systemid ? IdentityID.fromAddress(details.systemid) : undefined, + requestID: details?.requestid, + expiryHeight: details?.expiryheight ? new BN(details.expiryheight, 10) : undefined, txid: details?.txid ? Buffer.from(details.txid, 'hex').reverse() : undefined, }) } -} \ No newline at end of file +} diff --git a/src/vdxf/classes/identity/IdentityUpdateResponseDetails.ts b/src/vdxf/classes/identity/IdentityUpdateResponseDetails.ts index d73611af..81868c01 100644 --- a/src/vdxf/classes/identity/IdentityUpdateResponseDetails.ts +++ b/src/vdxf/classes/identity/IdentityUpdateResponseDetails.ts @@ -4,72 +4,58 @@ import createHash = require('create-hash'); import { BigNumber } from '../../../utils/types/BigNumber'; import { BN } from 'bn.js'; import { UINT_256_LENGTH } from '../../../constants/pbaas'; -import varuint from '../../../utils/varuint'; import { SerializableEntity } from '../../../utils/types/SerializableEntity'; +import { HASH160_BYTE_LENGTH, I_ADDR_VERSION } from '../../../constants/vdxf'; +import { fromBase58Check, toBase58Check } from '../../../utils/address'; const { BufferReader, BufferWriter } = bufferutils; export type IdentityUpdateResponseDetailsJson = { flags: string, requestid: string, - createdat: string, - txid?: string, - salt?: string + txid?: string } export class IdentityUpdateResponseDetails implements SerializableEntity { flags?: BigNumber; - requestid?: BigNumber; // ID of request, to be referenced in response - createdat?: BigNumber; // Unix timestamp of request creation + requestID?: string; // ID of request, to be referenced in response txid?: Buffer; // 32 byte transaction ID of identity update tx posted to blockchain, on same system asked for in request // stored in natural order, if displayed as text make sure to reverse! - salt?: Buffer; // Optional salt - static IDENTITY_UPDATE_RESPONSE_VALID = new BN(0, 10); static IDENTITY_UPDATE_RESPONSE_CONTAINS_TXID = new BN(1, 10); - static IDENTITY_UPDATE_RESPONSE_CONTAINS_SALT = new BN(2, 10); + static IDENTITY_UPDATE_RESPONSE_CONTAINS_REQUEST_ID = new BN(2, 10); constructor (data?: { flags?: BigNumber, - requestid?: BigNumber, - createdat?: BigNumber, - txid?: Buffer, - salt?: Buffer + requestID?: string, + txid?: Buffer }) { this.flags = data && data.flags ? data.flags : new BN("0", 10); - if (data?.requestid) { - this.requestid = data.requestid; - } else this.requestid = new BN("0", 10); - - if (data?.createdat) { - this.createdat = data.createdat; + if (data?.requestID) { + if (!this.containsRequestID()) this.toggleContainsRequestID(); + this.requestID = data.requestID; } if (data?.txid) { if (!this.containsTxid()) this.toggleContainsTxid(); this.txid = data.txid; } - - if (data?.salt) { - if (!this.containsSalt()) this.toggleContainsSalt(); - this.salt = data.salt; - } } containsTxid() { return !!(this.flags.and(IdentityUpdateResponseDetails.IDENTITY_UPDATE_RESPONSE_CONTAINS_TXID).toNumber()); } - containsSalt() { - return !!(this.flags.and(IdentityUpdateResponseDetails.IDENTITY_UPDATE_RESPONSE_CONTAINS_SALT).toNumber()); + containsRequestID() { + return !!(this.flags.and(IdentityUpdateResponseDetails.IDENTITY_UPDATE_RESPONSE_CONTAINS_REQUEST_ID).toNumber()); } toggleContainsTxid() { this.flags = this.flags.xor(IdentityUpdateResponseDetails.IDENTITY_UPDATE_RESPONSE_CONTAINS_TXID); } - toggleContainsSalt() { - this.flags = this.flags.xor(IdentityUpdateResponseDetails.IDENTITY_UPDATE_RESPONSE_CONTAINS_SALT); + toggleContainsRequestID() { + this.flags = this.flags.xor(IdentityUpdateResponseDetails.IDENTITY_UPDATE_RESPONSE_CONTAINS_REQUEST_ID); } toSha256() { @@ -81,21 +67,14 @@ export class IdentityUpdateResponseDetails implements SerializableEntity { length += varint.encodingLength(this.flags); - length += varint.encodingLength(this.requestid); - - length += varint.encodingLength(this.createdat); + if (this.containsRequestID()) { + length += HASH160_BYTE_LENGTH; + } if (this.containsTxid()) { length += UINT_256_LENGTH; } - if (this.containsSalt()) { - const saltLen = this.salt.length; - - length += varuint.encodingLength(saltLen); - length += saltLen; - } - return length; } @@ -104,9 +83,9 @@ export class IdentityUpdateResponseDetails implements SerializableEntity { writer.writeVarInt(this.flags); - writer.writeVarInt(this.requestid); - - writer.writeVarInt(this.createdat); + if (this.containsRequestID()) { + writer.writeSlice(fromBase58Check(this.requestID).hash); + } if (this.containsTxid()) { if (this.txid.length !== UINT_256_LENGTH) throw new Error("invalid txid length"); @@ -114,10 +93,6 @@ export class IdentityUpdateResponseDetails implements SerializableEntity { writer.writeSlice(this.txid); } - if (this.containsSalt()) { - writer.writeVarSlice(this.salt); - } - return writer.buffer; } @@ -126,38 +101,30 @@ export class IdentityUpdateResponseDetails implements SerializableEntity { this.flags = reader.readVarInt(); - this.requestid = reader.readVarInt(); - - this.createdat = reader.readVarInt(); + if (this.containsRequestID()) { + this.requestID = toBase58Check(reader.readSlice(HASH160_BYTE_LENGTH), I_ADDR_VERSION); + } if (this.containsTxid()) { this.txid = reader.readSlice(UINT_256_LENGTH); } - if (this.containsSalt()) { - this.salt = reader.readVarSlice(); - } - return reader.offset; } toJson(): IdentityUpdateResponseDetailsJson { return { flags: this.flags.toString(10), - requestid: this.requestid.toString(10), - createdat: this.createdat.toString(10), - txid: this.containsTxid() ? (Buffer.from(this.txid.toString('hex'), 'hex').reverse()).toString('hex') : undefined, - salt: this.containsSalt() ? this.salt.toString('hex') : undefined + requestid: this.containsRequestID() ? this.requestID : undefined, + txid: this.containsTxid() ? (Buffer.from(this.txid.toString('hex'), 'hex').reverse()).toString('hex') : undefined } } static fromJson(json: IdentityUpdateResponseDetailsJson): IdentityUpdateResponseDetails { return new IdentityUpdateResponseDetails({ flags: new BN(json.flags, 10), - requestid: new BN(json.requestid, 10), - createdat: new BN(json.createdat, 10), - txid: json.txid ? Buffer.from(json.txid, 'hex').reverse() : undefined, - salt: json.salt ? Buffer.from(json.salt, 'hex') : undefined + requestID: json.requestid, + txid: json.txid ? Buffer.from(json.txid, 'hex').reverse() : undefined }); } } \ No newline at end of file diff --git a/src/vdxf/classes/index.ts b/src/vdxf/classes/index.ts index bfa93d8b..017d15fc 100644 --- a/src/vdxf/classes/index.ts +++ b/src/vdxf/classes/index.ts @@ -24,10 +24,14 @@ export { ProvisioningResponseInterface as LoginConsentProvisioningResponseInterf export { ProvisioningDecisionInterface as LoginConsentProvisioningDecisionInterface } from "./provisioning/ProvisioningDecision"; export { ProvisioningResultInterface as LoginConsentProvisioningResultInterface } from "./provisioning/ProvisioningResult"; -export * from "./identity/IdentityUpdateEnvelope"; export * from "./identity/IdentityUpdateRequestDetails"; export * from "./identity/IdentityUpdateResponseDetails"; -export * from './ResponseUri'; +export * from './ResponseURI'; +export * from './request/GenericRequest'; +export * from './response/GenericResponse'; +export * from './appencryption/AppEncryptionResponseDetails' + +export * from './ordinals'; export { Hash160 } from './Hash160' export { @@ -43,4 +47,12 @@ export { ProvisioningTxid } from './provisioning/ProvisioningResult' export { Context } from './Context' -export { DataCategory } from './PersonalProfile' \ No newline at end of file +export { DataCategory } from './PersonalProfile' +export * from './requestobjects/UserDataRequestDetails' +export * from './login/AuthenticationRequestDetails' +export * from './login/AuthenticationResponseDetails' +export * from './requestobjects/ProvisionIdentityDetails' +export * from './appencryption/AppEncryptionRequestDetails' +export * from './requestobjects/UserSpecificDataPacketDetails' +export * from './CompactAddressObject' +export * from './VerifiableSignatureData' \ No newline at end of file diff --git a/src/vdxf/classes/login/AuthenticationRequestDetails.ts b/src/vdxf/classes/login/AuthenticationRequestDetails.ts new file mode 100644 index 00000000..59f8aa78 --- /dev/null +++ b/src/vdxf/classes/login/AuthenticationRequestDetails.ts @@ -0,0 +1,241 @@ + +/** + * AuthenticationRequestDetails - Class for handling application login and authentication requests + * + * This class is used when an application is requesting authentication or login from the user, + * including specific recipientConstraints and callback information. The request includes: + * - Request ID for tracking the authentication session + * - Permission sets defining what access the application is requesting + * - Optional expiry time for the authentication session + * + * The user's wallet can use these parameters to present a clear authentication request + * to the user, showing exactly what recipientConstraints are being requested and where they will + * be redirected after successful authentication. This enables secure, user-controlled + * authentication flows with granular permission management. + */ + +import bufferutils from "../../../utils/bufferutils"; +import { BigNumber } from "../../../utils/types/BigNumber"; +import { BN } from "bn.js"; +import { SerializableEntity } from "../../../utils/types/SerializableEntity"; +import varuint from "../../../utils/varuint"; +import { CompactIAddressObject, CompactAddressObjectJson } from "../CompactAddressObject"; + +export interface AuthenticationRequestDetailsInterface { + flags?: BigNumber; + requestID?: CompactIAddressObject; + recipientConstraints?: Array; + expiryTime?: BigNumber; // UNIX Timestamp +} + +export interface RecipientConstraintJson { + type: number; + identity: CompactAddressObjectJson; +} + +export interface RecipientConstraint { + type: number; + identity: CompactIAddressObject; +} + +export interface AuthenticationRequestDetailsJson { + requestid?: CompactAddressObjectJson; + flags: number; + recipientconstraints?: Array; + expirytime?: number; +} + +export class AuthenticationRequestDetails implements SerializableEntity { + flags?: BigNumber; + requestID?: CompactIAddressObject; + recipientConstraints?: Array; + expiryTime?: BigNumber; // UNIX Timestamp + + static FLAG_HAS_REQUEST_ID = new BN(1, 10); + static FLAG_HAS_RECIPIENT_CONSTRAINTS = new BN(2, 10); + static FLAG_HAS_EXPIRY_TIME = new BN(4, 10); + + // Recipient Constraint Types - What types of Identity can login, e.g. REQUIRED_SYSTEM and "VRSC" means only identities on the Verus chain can login + static REQUIRED_ID = 1; + static REQUIRED_SYSTEM = 2; + static REQUIRED_PARENT = 3; + + constructor( + request?: AuthenticationRequestDetailsInterface + ) { + this.flags = request?.flags || new BN(0, 10); + this.requestID = request?.requestID || null; + this.recipientConstraints = request?.recipientConstraints || null; + this.expiryTime = request?.expiryTime || null; + + this.setFlags(); + } + + hasRequestID(): boolean { + return this.flags.and(AuthenticationRequestDetails.FLAG_HAS_REQUEST_ID).eq(AuthenticationRequestDetails.FLAG_HAS_REQUEST_ID); + } + + hasRecipentConstraints(): boolean { + return this.flags.and(AuthenticationRequestDetails.FLAG_HAS_RECIPIENT_CONSTRAINTS).eq(AuthenticationRequestDetails.FLAG_HAS_RECIPIENT_CONSTRAINTS); + } + + hasExpiryTime(): boolean { + return this.flags.and(AuthenticationRequestDetails.FLAG_HAS_EXPIRY_TIME).eq(AuthenticationRequestDetails.FLAG_HAS_EXPIRY_TIME); + } + + calcFlags(flags: BigNumber = this.flags): BigNumber { + if (this.requestID) { + flags = flags.or(AuthenticationRequestDetails.FLAG_HAS_REQUEST_ID); + } + if (this.recipientConstraints) { + flags = flags.or(AuthenticationRequestDetails.FLAG_HAS_RECIPIENT_CONSTRAINTS); + } + if (this.expiryTime) { + flags = flags.or(AuthenticationRequestDetails.FLAG_HAS_EXPIRY_TIME); + } + return flags; + } + + getByteLength(): number { + let length = 0; + + length += varuint.encodingLength(this.flags.toNumber()); + + if (this.hasRequestID()) { + length += this.requestID.getByteLength(); + } + + if (this.hasRecipentConstraints()) { + length += varuint.encodingLength(this.recipientConstraints.length); + for (let i = 0; i < this.recipientConstraints.length; i++) { + length += varuint.encodingLength(this.recipientConstraints[i].type); + length += this.recipientConstraints[i].identity.getByteLength(); + } + } + + if (this.hasExpiryTime()) { + length += varuint.encodingLength(this.expiryTime.toNumber()); + } + + return length; + } + + toBuffer(): Buffer { + const writer = new bufferutils.BufferWriter(Buffer.alloc(this.getByteLength())) + + writer.writeCompactSize(this.flags.toNumber()); + + if (this.hasRequestID()) { + writer.writeSlice(this.requestID.toBuffer()); + } + + if (this.hasRecipentConstraints()) { + writer.writeCompactSize(this.recipientConstraints.length); + for (let i = 0; i < this.recipientConstraints.length; i++) { + writer.writeCompactSize(this.recipientConstraints[i].type); + writer.writeSlice(this.recipientConstraints[i].identity.toBuffer()); + } + } + + if (this.hasExpiryTime()) { + writer.writeCompactSize(this.expiryTime.toNumber()); + } + + return writer.buffer; + } + + fromBuffer(buffer: Buffer, offset?: number): number { + const reader = new bufferutils.BufferReader(buffer, offset); + + this.flags = new BN(reader.readCompactSize()); + + if (this.hasRequestID()) { + this.requestID = new CompactIAddressObject(); + + reader.offset = this.requestID.fromBuffer(reader.buffer, reader.offset); + } + + if (this.hasRecipentConstraints()) { + this.recipientConstraints = []; + const recipientConstraintsLength = reader.readCompactSize(); + + for (let i = 0; i < recipientConstraintsLength; i++) { + const compactId = new CompactIAddressObject(); + const type = reader.readCompactSize(); + const identityOffset = reader.offset; + reader.offset = compactId.fromBuffer(buffer, identityOffset); + this.recipientConstraints.push({ + type: type, + identity: compactId + }); + } + } + + if (this.hasExpiryTime()) { + this.expiryTime = new BN(reader.readCompactSize()); + } + + return reader.offset; + } + + toJson(): AuthenticationRequestDetailsJson { + const flags = this.calcFlags(); + + const retval = { + flags: flags.toNumber(), + requestid: this.requestID.toJson(), + recipientConstraints: this.recipientConstraints ? this.recipientConstraints.map(p => ({type: p.type, + identity: p.identity.toJson()})) : undefined, + expirytime: this.expiryTime ? this.expiryTime.toNumber() : undefined + }; + + return retval; + } + + static fromJson(data: AuthenticationRequestDetailsJson): AuthenticationRequestDetails { + const loginDetails = new AuthenticationRequestDetails(); + + loginDetails.flags = new BN(data?.flags || 0); + loginDetails.requestID = CompactIAddressObject.fromCompactAddressObjectJson(data.requestid); + + if(loginDetails.hasRecipentConstraints() && data.recipientconstraints) { + loginDetails.recipientConstraints = data.recipientconstraints.map(p => ({type: p.type, + identity: CompactIAddressObject.fromCompactAddressObjectJson(p.identity)})); + } + + if(loginDetails.hasExpiryTime() && data.expirytime) { + loginDetails.expiryTime = new BN(data.expirytime); + } + + return loginDetails; + } + + setFlags() { + this.flags = this.calcFlags(); + } + + isValid(): boolean { + let valid = true; + valid &&= this.flags != null && this.flags.gte(new BN(0)); + + if (this.hasRequestID()) { + if (!this.requestID || !this.requestID.isValid()) { + return false; + } + } + + if (this.hasRecipentConstraints()) { + if (!this.recipientConstraints || this.recipientConstraints.length === 0) { + return false; + } + } + + if (this.hasExpiryTime()) { + if (!this.expiryTime || this.expiryTime.isZero()) { + return false; + } + } + + return valid; + } +} diff --git a/src/vdxf/classes/login/AuthenticationResponseDetails.ts b/src/vdxf/classes/login/AuthenticationResponseDetails.ts new file mode 100644 index 00000000..3eb24d37 --- /dev/null +++ b/src/vdxf/classes/login/AuthenticationResponseDetails.ts @@ -0,0 +1,101 @@ +import varint from '../../../utils/varint' +import bufferutils from '../../../utils/bufferutils' +import createHash = require('create-hash'); +import { BigNumber } from '../../../utils/types/BigNumber'; +import { BN } from 'bn.js'; +import { SerializableEntity } from '../../../utils/types/SerializableEntity'; +import { CompactIAddressObject, CompactAddressObjectJson } from '../CompactAddressObject'; +const { BufferReader, BufferWriter } = bufferutils; + +export type AuthenticationResponseDetailsJson = { + flags: string, + requestid?: CompactAddressObjectJson +} + +export class AuthenticationResponseDetails implements SerializableEntity { + flags?: BigNumber; + requestID?: CompactIAddressObject; // ID of request, to be referenced in response + + static FLAG_HAS_REQUEST_ID = new BN(1, 10); + + constructor (data?: { + flags?: BigNumber, + requestID?: CompactIAddressObject + }) { + this.flags = data && data.flags ? data.flags : new BN("0", 10); + this.requestID = data?.requestID || null; + + this.setFlags(); + } + + hasRequestID(): boolean { + return this.flags.and(AuthenticationResponseDetails.FLAG_HAS_REQUEST_ID).eq(AuthenticationResponseDetails.FLAG_HAS_REQUEST_ID); + } + + setFlags() { + this.flags = this.calcFlags(); + } + + calcFlags(flags: BigNumber = this.flags): BigNumber { + if (this.requestID) { + flags = flags.or(AuthenticationResponseDetails.FLAG_HAS_REQUEST_ID); + } + return flags; + } + + toSha256() { + return createHash("sha256").update(this.toBuffer()).digest(); + } + + getByteLength(): number { + let length = 0; + + length += varint.encodingLength(this.flags); + + if (this.hasRequestID()) { + length += this.requestID.getByteLength(); + } + + return length; + } + + toBuffer() { + const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); + + writer.writeVarInt(this.flags); + + if (this.hasRequestID()) { + writer.writeSlice(this.requestID.toBuffer()); + } + + return writer.buffer; + } + + fromBuffer(buffer: Buffer, offset: number = 0) { + const reader = new BufferReader(buffer, offset); + + this.flags = reader.readVarInt(); + + if (this.hasRequestID()) { + this.requestID = new CompactIAddressObject(); + + reader.offset = this.requestID.fromBuffer(reader.buffer, reader.offset); + } + + return reader.offset; + } + + toJson(): AuthenticationResponseDetailsJson { + return { + flags: this.flags.toString(10), + requestid: this.hasRequestID() ? this.requestID.toJson() : undefined + } + } + + static fromJson(json: AuthenticationResponseDetailsJson): AuthenticationResponseDetails { + return new AuthenticationResponseDetails({ + flags: new BN(json.flags, 10), + requestID: CompactIAddressObject.fromCompactAddressObjectJson(json.requestid) + }); + } +} \ No newline at end of file diff --git a/src/vdxf/classes/ordinals/AppEncryptionRequestOrdinalVDXFObject.ts b/src/vdxf/classes/ordinals/AppEncryptionRequestOrdinalVDXFObject.ts new file mode 100644 index 00000000..c87c7972 --- /dev/null +++ b/src/vdxf/classes/ordinals/AppEncryptionRequestOrdinalVDXFObject.ts @@ -0,0 +1,29 @@ +import { VDXF_ORDINAL_APP_ENCRYPTION_REQUEST } from "../../../constants/ordinals/ordinals"; +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; +import { AppEncryptionRequestDetails, AppEncryptionRequestJson } from "../appencryption/AppEncryptionRequestDetails"; + +export class AppEncryptionRequestOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: AppEncryptionRequestDetails; + + constructor( + request: OrdinalVDXFObjectInterfaceTemplate = { + data: new AppEncryptionRequestDetails() + } + ) { + super( + { + type: VDXF_ORDINAL_APP_ENCRYPTION_REQUEST, + data: request.data + }, + AppEncryptionRequestDetails + ); + } + + static fromJson(details: OrdinalVDXFObjectJsonTemplate): AppEncryptionRequestOrdinalVDXFObject { + return new AppEncryptionRequestOrdinalVDXFObject({ + data: AppEncryptionRequestDetails.fromJson(details.data) + }) + } +} \ No newline at end of file diff --git a/src/vdxf/classes/ordinals/AppEncryptionResponseOrdinalVDXFObject.ts b/src/vdxf/classes/ordinals/AppEncryptionResponseOrdinalVDXFObject.ts new file mode 100644 index 00000000..fc249c0e --- /dev/null +++ b/src/vdxf/classes/ordinals/AppEncryptionResponseOrdinalVDXFObject.ts @@ -0,0 +1,29 @@ +import { VDXF_ORDINAL_APP_ENCRYPTION_RESPONSE } from "../../../constants/ordinals/ordinals"; +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; +import { AppEncryptionResponseDetails, AppEncryptionResponseDetailsJson } from "../appencryption/AppEncryptionResponseDetails"; + +export class AppEncryptionResponseOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: AppEncryptionResponseDetails; + + constructor( + request: OrdinalVDXFObjectInterfaceTemplate = { + data: new AppEncryptionResponseDetails() + } + ) { + super( + { + type: VDXF_ORDINAL_APP_ENCRYPTION_RESPONSE, + data: request.data + }, + AppEncryptionResponseDetails + ); + } + + static fromJson(details: OrdinalVDXFObjectJsonTemplate): AppEncryptionResponseOrdinalVDXFObject { + return new AppEncryptionResponseOrdinalVDXFObject({ + data: AppEncryptionResponseDetails.fromJson(details.data) + }) + } +} \ No newline at end of file diff --git a/src/vdxf/classes/ordinals/AuthenticationRequestOrdinalVDXFObject.ts b/src/vdxf/classes/ordinals/AuthenticationRequestOrdinalVDXFObject.ts new file mode 100644 index 00000000..b659eb92 --- /dev/null +++ b/src/vdxf/classes/ordinals/AuthenticationRequestOrdinalVDXFObject.ts @@ -0,0 +1,29 @@ +import { VDXF_ORDINAL_AUTHENTICATION_REQUEST } from "../../../constants/ordinals/ordinals"; +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; +import { AuthenticationRequestDetails, AuthenticationRequestDetailsJson } from "../login/AuthenticationRequestDetails"; + +export class AuthenticationRequestOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: AuthenticationRequestDetails; + + constructor( + request: OrdinalVDXFObjectInterfaceTemplate = { + data: new AuthenticationRequestDetails() + } + ) { + super( + { + type: VDXF_ORDINAL_AUTHENTICATION_REQUEST, + data: request.data + }, + AuthenticationRequestDetails + ); + } + + static fromJson(details: OrdinalVDXFObjectJsonTemplate): AuthenticationRequestOrdinalVDXFObject { + return new AuthenticationRequestOrdinalVDXFObject({ + data: AuthenticationRequestDetails.fromJson(details.data) + }) + } +} \ No newline at end of file diff --git a/src/vdxf/classes/ordinals/AuthenticationResponseOrdinalVDXFObject.ts b/src/vdxf/classes/ordinals/AuthenticationResponseOrdinalVDXFObject.ts new file mode 100644 index 00000000..63d9664a --- /dev/null +++ b/src/vdxf/classes/ordinals/AuthenticationResponseOrdinalVDXFObject.ts @@ -0,0 +1,29 @@ +import { VDXF_ORDINAL_AUTHENTICATION_RESPONSE } from "../../../constants/ordinals/ordinals"; +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; +import { AuthenticationResponseDetails, AuthenticationResponseDetailsJson } from "../login/AuthenticationResponseDetails"; + +export class AuthenticationResponseOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: AuthenticationResponseDetails; + + constructor( + response: OrdinalVDXFObjectInterfaceTemplate = { + data: new AuthenticationResponseDetails() + } + ) { + super( + { + type: VDXF_ORDINAL_AUTHENTICATION_RESPONSE, + data: response.data + }, + AuthenticationResponseDetails + ); + } + + static fromJson(details: OrdinalVDXFObjectJsonTemplate): AuthenticationResponseOrdinalVDXFObject { + return new AuthenticationResponseOrdinalVDXFObject({ + data: AuthenticationResponseDetails.fromJson(details.data) + }) + } +} \ No newline at end of file diff --git a/src/vdxf/classes/ordinals/DataDescriptorOrdinalVDXFObject.ts b/src/vdxf/classes/ordinals/DataDescriptorOrdinalVDXFObject.ts new file mode 100644 index 00000000..0299a85a --- /dev/null +++ b/src/vdxf/classes/ordinals/DataDescriptorOrdinalVDXFObject.ts @@ -0,0 +1,29 @@ +import { VDXF_ORDINAL_DATA_DESCRIPTOR } from "../../../constants/ordinals/ordinals"; +import { DataDescriptor, DataDescriptorJson } from "../../../pbaas"; +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; + +export class DataDescriptorOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: DataDescriptor; + + constructor( + request: OrdinalVDXFObjectInterfaceTemplate = { + data: new DataDescriptor() + } + ) { + super( + { + type: VDXF_ORDINAL_DATA_DESCRIPTOR, + data: request.data + }, + DataDescriptor + ); + } + + static fromJson(details: OrdinalVDXFObjectJsonTemplate): DataDescriptorOrdinalVDXFObject { + return new DataDescriptorOrdinalVDXFObject({ + data: DataDescriptor.fromJson(details.data) + }) + } +} \ No newline at end of file diff --git a/src/vdxf/classes/ordinals/DataPacketResponseOrdinalVDXFObject.ts b/src/vdxf/classes/ordinals/DataPacketResponseOrdinalVDXFObject.ts new file mode 100644 index 00000000..d7413436 --- /dev/null +++ b/src/vdxf/classes/ordinals/DataPacketResponseOrdinalVDXFObject.ts @@ -0,0 +1,29 @@ +import { VDXF_ORDINAL_DATA_RESPONSE } from "../../../constants/ordinals/ordinals"; +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; +import { DataPacketResponse, DataResponseJson } from "../datapacket/DataPacketResponse"; + +export class DataPacketResponseOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: DataPacketResponse; + + constructor( + request: OrdinalVDXFObjectInterfaceTemplate = { + data: new DataPacketResponse() + } + ) { + super( + { + type: VDXF_ORDINAL_DATA_RESPONSE, + data: request.data + }, + DataPacketResponse + ); + } + + static fromJson(details: OrdinalVDXFObjectJsonTemplate): DataPacketResponseOrdinalVDXFObject { + return new DataPacketResponseOrdinalVDXFObject({ + data: DataPacketResponse.fromJson(details.data) + }) + } +} \ No newline at end of file diff --git a/src/vdxf/classes/ordinals/IdentityUpdateRequestOrdinalVDXFObject.ts b/src/vdxf/classes/ordinals/IdentityUpdateRequestOrdinalVDXFObject.ts new file mode 100644 index 00000000..cfed177f --- /dev/null +++ b/src/vdxf/classes/ordinals/IdentityUpdateRequestOrdinalVDXFObject.ts @@ -0,0 +1,29 @@ +import { VDXF_ORDINAL_IDENTITY_UPDATE_REQUEST } from "../../../constants/ordinals/ordinals"; +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { IdentityUpdateRequestDetails, IdentityUpdateRequestDetailsJson } from "../identity/IdentityUpdateRequestDetails"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; + +export class IdentityUpdateRequestOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: IdentityUpdateRequestDetails; + + constructor( + request: OrdinalVDXFObjectInterfaceTemplate = { + data: new IdentityUpdateRequestDetails() + } + ) { + super( + { + type: VDXF_ORDINAL_IDENTITY_UPDATE_REQUEST, + data: request.data + }, + IdentityUpdateRequestDetails + ); + } + + static fromJson(details: OrdinalVDXFObjectJsonTemplate): IdentityUpdateRequestOrdinalVDXFObject { + return new IdentityUpdateRequestOrdinalVDXFObject({ + data: IdentityUpdateRequestDetails.fromJson(details.data) + }) + } +} \ No newline at end of file diff --git a/src/vdxf/classes/ordinals/IdentityUpdateResponseOrdinalVDXFObject.ts b/src/vdxf/classes/ordinals/IdentityUpdateResponseOrdinalVDXFObject.ts new file mode 100644 index 00000000..332e5f47 --- /dev/null +++ b/src/vdxf/classes/ordinals/IdentityUpdateResponseOrdinalVDXFObject.ts @@ -0,0 +1,29 @@ +import { VDXF_ORDINAL_IDENTITY_UPDATE_RESPONSE } from "../../../constants/ordinals/ordinals"; +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { IdentityUpdateResponseDetails, IdentityUpdateResponseDetailsJson } from "../identity/IdentityUpdateResponseDetails"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; + +export class IdentityUpdateResponseOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: IdentityUpdateResponseDetails; + + constructor( + response: OrdinalVDXFObjectInterfaceTemplate = { + data: new IdentityUpdateResponseDetails() + } + ) { + super( + { + type: VDXF_ORDINAL_IDENTITY_UPDATE_RESPONSE, + data: response.data + }, + IdentityUpdateResponseDetails + ); + } + + static fromJson(details: OrdinalVDXFObjectJsonTemplate): IdentityUpdateResponseOrdinalVDXFObject { + return new IdentityUpdateResponseOrdinalVDXFObject({ + data: IdentityUpdateResponseDetails.fromJson(details.data) + }) + } +} \ No newline at end of file diff --git a/src/vdxf/classes/ordinals/OrdinalVDXFObject.ts b/src/vdxf/classes/ordinals/OrdinalVDXFObject.ts new file mode 100644 index 00000000..6ebde8ef --- /dev/null +++ b/src/vdxf/classes/ordinals/OrdinalVDXFObject.ts @@ -0,0 +1,296 @@ +import bufferutils from "../../../utils/bufferutils"; +import { BN } from 'bn.js'; +import { BigNumber } from "../../../utils/types/BigNumber"; +import { SerializableDataEntity, SerializableEntity } from "../../../utils/types/SerializableEntity"; +import varuint from "../../../utils/varuint"; +import { fromBase58Check, getDataKey, toBase58Check, toIAddress } from "../../../utils/address"; +import varint from "../../../utils/varint"; +import { HASH160_BYTE_LENGTH, I_ADDR_VERSION, NULL_ADDRESS } from "../../../constants/vdxf"; +import { OrdinalVDXFObjectOrdinalMap } from "./OrdinalVDXFObjectOrdinalMap"; +import { DEFAULT_VERUS_CHAINNAME } from "../../../constants/pbaas"; +import { OrdinalVDXFObjectReservedData, OrdinalVDXFObjectReservedDataJson } from "../../../constants/ordinals/types"; +import { + VDXF_OBJECT_RESERVED_BYTE_I_ADDR, + VDXF_OBJECT_RESERVED_BYTE_ID_OR_CURRENCY, + VDXF_OBJECT_RESERVED_BYTE_VDXF_ID_STRING, + VDXF_ORDINAL_DATA_DESCRIPTOR +} from "../../../constants/ordinals/ordinals"; + +export interface OrdinalVDXFObjectInterfaceTemplate { + version?: BigNumber; + type?: BigNumber; + key?: string; + data?: T; +} + +export type OrdinalVDXFObjectJsonTemplate = { + version: string; + type: string; + vdxfkey?: string; + data?: T; +} + +export type BufferOrOrdinalVDXFObjectReservedData = Buffer | OrdinalVDXFObjectReservedData; +export type StringOrOrdinalVDXFObjectReservedDataJson = string | OrdinalVDXFObjectReservedDataJson; + +export type OrdinalVDXFObjectInterface = OrdinalVDXFObjectInterfaceTemplate; +export type OrdinalVDXFObjectJson = OrdinalVDXFObjectJsonTemplate; + +export type OrdinalVDXFObjectDataClass = new (...args: any[]) => OrdinalVDXFObjectReservedData; +export type OrdinalVDXFObjectClass = new (...args: any[]) => OrdinalVDXFObject; + +export const getOrdinalVDXFObjectClassForType = (type: BigNumber): OrdinalVDXFObjectClass => { + if (OrdinalVDXFObjectOrdinalMap.isRecognizedOrdinal(type.toNumber())) { + const key = OrdinalVDXFObjectOrdinalMap.getVdxfKeyForOrdinal(type.toNumber()); + + if (OrdinalVDXFObjectOrdinalMap.hasClassForVdxfKey(key)) { + return OrdinalVDXFObjectOrdinalMap.getClassForVdxfKey(OrdinalVDXFObjectOrdinalMap.getVdxfKeyForOrdinal(type.toNumber())); + } else { + throw new Error("No class found for " + key) + } + } else if ( + type.eq(VDXF_OBJECT_RESERVED_BYTE_I_ADDR) || + type.eq(VDXF_OBJECT_RESERVED_BYTE_VDXF_ID_STRING) || + type.eq(VDXF_OBJECT_RESERVED_BYTE_ID_OR_CURRENCY) + ) return GeneralTypeOrdinalVDXFObject; + else throw new Error("Unrecognized vdxf ordinal object type " + type.toNumber()); +} + +export class OrdinalVDXFObject implements SerializableEntity { + version: BigNumber; + type: BigNumber; + key?: string; + data?: BufferOrOrdinalVDXFObjectReservedData; + + static VERSION_INVALID = new BN(0, 10) + static VERSION_FIRST = new BN(1, 10) + static VERSION_LAST = new BN(1, 10) + static VERSION_CURRENT = new BN(1, 10) + + constructor( + request: OrdinalVDXFObjectInterfaceTemplate = { + type: VDXF_ORDINAL_DATA_DESCRIPTOR + } + ) { + if (request.key) { + this.type = request.type ? request.type : VDXF_OBJECT_RESERVED_BYTE_I_ADDR; + this.key = request.key; + + if (request.data) { + this.data = request.data; + } else this.data = Buffer.alloc(0); + } else if (request.type == null) { + this.type = VDXF_ORDINAL_DATA_DESCRIPTOR; + } else { + this.type = request.type; + } + + if (request.version) this.version = request.version; + else this.version = OrdinalVDXFObject.VERSION_CURRENT; + } + + isDefinedByVdxfKey() { + return this.type.eq(VDXF_OBJECT_RESERVED_BYTE_I_ADDR); + } + + isDefinedByTextVdxfKey() { + return this.type.eq(VDXF_OBJECT_RESERVED_BYTE_VDXF_ID_STRING); + } + + isDefinedByIDOrCurrencyFQN() { + return this.type.eq(VDXF_OBJECT_RESERVED_BYTE_ID_OR_CURRENCY); + } + + isDefinedByCustomKey() { + return this.isDefinedByIDOrCurrencyFQN() || this.isDefinedByTextVdxfKey() || this.isDefinedByVdxfKey(); + } + + // Returns the I address vdxf key of this vdxf object + getIAddressKey(): string { + if (this.isDefinedByVdxfKey()) { + return this.key; + } else if (this.isDefinedByTextVdxfKey()) { + return getDataKey(this.key).id; + } else if (this.isDefinedByIDOrCurrencyFQN()) { + return toIAddress(this.key); + } else if (OrdinalVDXFObjectOrdinalMap.isRecognizedOrdinal(this.type.toNumber())) { + return OrdinalVDXFObjectOrdinalMap.getVdxfKeyForOrdinal(this.type.toNumber()) + } else throw new Error("Could not get I address for ordinal VDXF object") + } + + getDataByteLength(): number { + return 0; + } + + toDataBuffer(): Buffer { + return Buffer.alloc(0); + } + + fromDataBuffer(buffer: Buffer): void {} + + getByteLength(): number { + let length = 0; + + length += varuint.encodingLength(this.type.toNumber()); + + if (this.isDefinedByVdxfKey()) { + length += fromBase58Check(this.key).hash.length; + } else if (this.isDefinedByTextVdxfKey() || this.isDefinedByIDOrCurrencyFQN()) { + const utf8Key = Buffer.from(this.key, 'utf8'); + + length += varuint.encodingLength(utf8Key.length); + length += utf8Key.length; + } + + length += varint.encodingLength(this.version); + + const dataLength = this.getDataByteLength(); + + length += varuint.encodingLength(dataLength); + length += dataLength; + + return length; + } + + toBuffer(): Buffer { + const writer = new bufferutils.BufferWriter( + Buffer.alloc(this.getByteLength()) + ); + + writer.writeCompactSize(this.type.toNumber()); + + if (this.isDefinedByVdxfKey()) { + writer.writeSlice(fromBase58Check(this.key).hash); + } else if (this.isDefinedByTextVdxfKey() || this.isDefinedByIDOrCurrencyFQN()) { + writer.writeVarSlice(Buffer.from(this.key, 'utf8')); + } + + writer.writeVarInt(this.version); + + writer.writeVarSlice(this.toDataBuffer()); + + return writer.buffer; + } + + fromBufferOptionalType(buffer: Buffer, offset?: number, type?: BigNumber, key?: string): number { + if (buffer.length == 0) throw new Error("Cannot create request from empty buffer"); + + const reader = new bufferutils.BufferReader(buffer, offset); + + if (!type) { + this.type = new BN(reader.readCompactSize()); + } else this.type = type; + + if (!key) { + if (this.isDefinedByVdxfKey()) { + this.key = toBase58Check(reader.readSlice(HASH160_BYTE_LENGTH), I_ADDR_VERSION); + } else if (this.isDefinedByTextVdxfKey() || this.isDefinedByIDOrCurrencyFQN()) { + this.key = reader.readVarSlice().toString('utf8'); + } + } else { + this.key = key; + } + + this.version = reader.readVarInt(); + const dataBuf = reader.readVarSlice(); + + this.fromDataBuffer(dataBuf); + + return reader.offset; + } + + fromBuffer(buffer: Buffer, offset?: number): number { + return this.fromBufferOptionalType(buffer, offset); + } + + toJson(): OrdinalVDXFObjectJson { + return { + type: this.type ? this.type.toString() : undefined, + version: this.version ? this.version.toString() : undefined, + vdxfkey: this.key, + data: this.data ? this.isDefinedByCustomKey() ? this.data.toString('hex') : (this.data as OrdinalVDXFObjectReservedData).toJson() : undefined + }; + } + + static createFromBuffer( + buffer: Buffer, + offset?: number, + optimizeWithOrdinal: boolean = false, + rootSystemName: string = DEFAULT_VERUS_CHAINNAME + ): { offset: number, obj: OrdinalVDXFObject } { + if (buffer.length == 0) throw new Error("Cannot create request from empty buffer"); + + const reader = new bufferutils.BufferReader(buffer, offset); + let type = new BN(reader.readCompactSize()); + const rootSystemId = toIAddress(rootSystemName); + + const Entity = getOrdinalVDXFObjectClassForType(type); + const ord = new Entity({ type }); + + let key: string; + + if (optimizeWithOrdinal) { + let vdxfKey: string; + + if (ord.isDefinedByVdxfKey()) { + key = toBase58Check(reader.readSlice(HASH160_BYTE_LENGTH), I_ADDR_VERSION); + vdxfKey = key; + } else if (ord.isDefinedByTextVdxfKey() || ord.isDefinedByIDOrCurrencyFQN()) { + key = reader.readVarSlice().toString('utf8'); + + if (ord.isDefinedByTextVdxfKey()) { + vdxfKey = getDataKey(key, undefined, rootSystemId).id; + } else { + vdxfKey = toIAddress(key, rootSystemName); + } + } + + if (OrdinalVDXFObjectOrdinalMap.vdxfKeyHasOrdinal(vdxfKey)) { + type = new BN(OrdinalVDXFObjectOrdinalMap.getOrdinalForVdxfKey(vdxfKey)); + } + } + + reader.offset = ord.fromBufferOptionalType(buffer, reader.offset, type, key); + + return { offset: reader.offset, obj: ord }; + } +} + +export class GeneralTypeOrdinalVDXFObject extends OrdinalVDXFObject implements SerializableDataEntity { + data: Buffer; + key: string; + + constructor( + request: OrdinalVDXFObjectInterfaceTemplate = { + type: VDXF_OBJECT_RESERVED_BYTE_I_ADDR, + data: Buffer.alloc(0), + key: NULL_ADDRESS + } + ) { + super({ + type: request.type, + data: request.data, + key: request.key + }) + } + + getDataByteLength(): number { + return this.data.length; + } + + toDataBuffer(): Buffer { + return this.data; + } + + fromDataBuffer(buffer: Buffer): void { + this.data = Buffer.from(buffer) + } + + static fromJson(details: OrdinalVDXFObjectJson): GeneralTypeOrdinalVDXFObject { + return new GeneralTypeOrdinalVDXFObject({ + key: details.vdxfkey, + data: details.data ? Buffer.from(details.data as string, 'hex') : undefined, + type: details.type ? new BN(details.type) : VDXF_OBJECT_RESERVED_BYTE_I_ADDR + }); + } +} \ No newline at end of file diff --git a/src/vdxf/classes/ordinals/OrdinalVDXFObjectOrdinalMap.ts b/src/vdxf/classes/ordinals/OrdinalVDXFObjectOrdinalMap.ts new file mode 100644 index 00000000..171104f9 --- /dev/null +++ b/src/vdxf/classes/ordinals/OrdinalVDXFObjectOrdinalMap.ts @@ -0,0 +1,55 @@ +import { OrdinalVDXFObjectClass } from "./OrdinalVDXFObject"; + +// Singleton class that exists to create a bidirectional map of ordinals <-> vdxf keys +class _OrdinalVDXFObjectOrdinalMap { + private keyToOrdinalMap: Map; + private ordinalToKeyMap: Map; + keyToOrdinalClass: Map; + + constructor() { + this.keyToOrdinalMap = new Map(); + this.ordinalToKeyMap = new Map(); + this.keyToOrdinalClass = new Map(); + } + + private updateOrdinalToKeyMap() { + this.ordinalToKeyMap = new Map(Array.from(this.keyToOrdinalMap, a => a.reverse() as [number,string])); + } + + registerOrdinal(ordinal: number, vdxfKey: string, ordinalClass: OrdinalVDXFObjectClass, throwOnDuplicate: boolean = true): void { + if (this.isRecognizedOrdinal(ordinal) || this.vdxfKeyHasOrdinal(vdxfKey)) { + if (throwOnDuplicate) throw new Error("Cannot overwrite existing ordinal"); + else return; + } + + this.keyToOrdinalMap.set(vdxfKey, ordinal); + this.keyToOrdinalClass.set(vdxfKey, ordinalClass); + this.updateOrdinalToKeyMap(); + } + + isRecognizedOrdinal(ordinal: number): boolean { + return this.ordinalToKeyMap.has(ordinal); + } + + vdxfKeyHasOrdinal(vdxfKey: string): boolean { + return this.keyToOrdinalMap.has(vdxfKey); + } + + hasClassForVdxfKey(vdxfKey: string): boolean { + return this.keyToOrdinalClass.has(vdxfKey); + } + + getOrdinalForVdxfKey(vdxfKey: string): number { + return this.keyToOrdinalMap.get(vdxfKey); + } + + getVdxfKeyForOrdinal(ordinal: number): string { + return this.ordinalToKeyMap.get(ordinal); + } + + getClassForVdxfKey(vdxfKey: string): OrdinalVDXFObjectClass { + return this.keyToOrdinalClass.get(vdxfKey); + } +} + +export const OrdinalVDXFObjectOrdinalMap = new _OrdinalVDXFObjectOrdinalMap(); \ No newline at end of file diff --git a/src/vdxf/classes/ordinals/ProvisionIdentityDetailsOrdinalVDXFObject.ts b/src/vdxf/classes/ordinals/ProvisionIdentityDetailsOrdinalVDXFObject.ts new file mode 100644 index 00000000..ed4cff29 --- /dev/null +++ b/src/vdxf/classes/ordinals/ProvisionIdentityDetailsOrdinalVDXFObject.ts @@ -0,0 +1,29 @@ +import { VDXF_ORDINAL_PROVISION_IDENTITY_DETAILS } from "../../../constants/ordinals/ordinals"; +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; +import { ProvisionIdentityDetails, ProvisionIdentityDetailsJson } from "../requestobjects/ProvisionIdentityDetails"; + +export class ProvisionIdentityDetailsOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: ProvisionIdentityDetails; + + constructor( + request: OrdinalVDXFObjectInterfaceTemplate = { + data: new ProvisionIdentityDetails() + } + ) { + super( + { + type: VDXF_ORDINAL_PROVISION_IDENTITY_DETAILS, + data: request.data + }, + ProvisionIdentityDetails + ); + } + + static fromJson(details: OrdinalVDXFObjectJsonTemplate): ProvisionIdentityDetailsOrdinalVDXFObject { + return new ProvisionIdentityDetailsOrdinalVDXFObject({ + data: ProvisionIdentityDetails.fromJson(details.data) + }) + } +} \ No newline at end of file diff --git a/src/vdxf/classes/ordinals/SerializableEntityOrdinalVDXFObject.ts b/src/vdxf/classes/ordinals/SerializableEntityOrdinalVDXFObject.ts new file mode 100644 index 00000000..e168bab0 --- /dev/null +++ b/src/vdxf/classes/ordinals/SerializableEntityOrdinalVDXFObject.ts @@ -0,0 +1,35 @@ +import { OrdinalVDXFObjectReservedData } from "../../../constants/ordinals/types"; +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObject, OrdinalVDXFObjectDataClass, OrdinalVDXFObjectInterfaceTemplate } from "./OrdinalVDXFObject"; + +export class SerializableEntityOrdinalVDXFObject extends OrdinalVDXFObject implements SerializableDataEntity { + data: OrdinalVDXFObjectReservedData; + entity: OrdinalVDXFObjectDataClass; + + constructor( + request: OrdinalVDXFObjectInterfaceTemplate, + entity: OrdinalVDXFObjectDataClass + ) { + if (!request || !request.type) throw new Error("Expected request with data and type") + + super({ + type: request.type + }); + + this.entity = entity; + this.data = request.data ? request.data : new entity(); + } + + getDataByteLength(): number { + return this.data.getByteLength() + } + + toDataBuffer(): Buffer { + return this.data.toBuffer(); + } + + fromDataBuffer(buffer: Buffer): void { + this.data = new this.entity(); + this.data.fromBuffer(buffer); + } +} \ No newline at end of file diff --git a/src/vdxf/classes/ordinals/UserDataRequestOrdinalVDXFObject.ts b/src/vdxf/classes/ordinals/UserDataRequestOrdinalVDXFObject.ts new file mode 100644 index 00000000..e13db17f --- /dev/null +++ b/src/vdxf/classes/ordinals/UserDataRequestOrdinalVDXFObject.ts @@ -0,0 +1,29 @@ +import { VDXF_ORDINAL_USER_DATA_REQUEST } from "../../../constants/ordinals/ordinals"; +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; +import { UserDataRequestDetails, UserDataRequestJson } from "../requestobjects/UserDataRequestDetails"; + +export class UserDataRequestOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: UserDataRequestDetails; + + constructor( + request: OrdinalVDXFObjectInterfaceTemplate = { + data: new UserDataRequestDetails() + } + ) { + super( + { + type: VDXF_ORDINAL_USER_DATA_REQUEST, + data: request.data + }, + UserDataRequestDetails + ); + } + + static fromJson(details: OrdinalVDXFObjectJsonTemplate): UserDataRequestOrdinalVDXFObject { + return new UserDataRequestOrdinalVDXFObject({ + data: UserDataRequestDetails.fromJson(details.data) + }) + } +} diff --git a/src/vdxf/classes/ordinals/UserSpecificDataPacketDetailsOrdinalVDXFObject.ts b/src/vdxf/classes/ordinals/UserSpecificDataPacketDetailsOrdinalVDXFObject.ts new file mode 100644 index 00000000..b80db96c --- /dev/null +++ b/src/vdxf/classes/ordinals/UserSpecificDataPacketDetailsOrdinalVDXFObject.ts @@ -0,0 +1,29 @@ +import { VDXF_ORDINAL_USER_SPECIFIC_DATA_PACKET } from "../../../constants/ordinals/ordinals"; +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; +import { UserSpecificDataPacketDetails, UserSpecificDataPacketDetailsJson } from "../requestobjects/UserSpecificDataPacketDetails"; + +export class UserSpecificDataPacketDetailsOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: UserSpecificDataPacketDetails; + + constructor( + request: OrdinalVDXFObjectInterfaceTemplate = { + data: new UserSpecificDataPacketDetails() + } + ) { + super( + { + type: VDXF_ORDINAL_USER_SPECIFIC_DATA_PACKET, + data: request.data + }, + UserSpecificDataPacketDetails + ); + } + + static fromJson(details: OrdinalVDXFObjectJsonTemplate): UserSpecificDataPacketDetailsOrdinalVDXFObject { + return new UserSpecificDataPacketDetailsOrdinalVDXFObject({ + data: UserSpecificDataPacketDetails.fromJson(details.data) + }) + } +} diff --git a/src/vdxf/classes/ordinals/VerusPayInvoiceOrdinalVDXFObject.ts b/src/vdxf/classes/ordinals/VerusPayInvoiceOrdinalVDXFObject.ts new file mode 100644 index 00000000..3b050895 --- /dev/null +++ b/src/vdxf/classes/ordinals/VerusPayInvoiceOrdinalVDXFObject.ts @@ -0,0 +1,29 @@ +import { VDXF_ORDINAL_VERUSPAY_INVOICE } from "../../../constants/ordinals/ordinals"; +import { SerializableDataEntity } from "../../../utils/types/SerializableEntity"; +import { VerusPayInvoiceDetails, VerusPayInvoiceDetailsJson } from "../payment/VerusPayInvoiceDetails"; +import { OrdinalVDXFObjectInterfaceTemplate, OrdinalVDXFObjectJsonTemplate } from "./OrdinalVDXFObject"; +import { SerializableEntityOrdinalVDXFObject } from "./SerializableEntityOrdinalVDXFObject"; + +export class VerusPayInvoiceOrdinalVDXFObject extends SerializableEntityOrdinalVDXFObject implements SerializableDataEntity { + data: VerusPayInvoiceDetails; + + constructor( + request: OrdinalVDXFObjectInterfaceTemplate = { + data: new VerusPayInvoiceDetails() + } + ) { + super( + { + type: VDXF_ORDINAL_VERUSPAY_INVOICE, + data: request.data + }, + VerusPayInvoiceDetails + ); + } + + static fromJson(details: OrdinalVDXFObjectJsonTemplate): VerusPayInvoiceOrdinalVDXFObject { + return new VerusPayInvoiceOrdinalVDXFObject({ + data: VerusPayInvoiceDetails.fromJson(details.data) + }) + } +} \ No newline at end of file diff --git a/src/vdxf/classes/ordinals/index.ts b/src/vdxf/classes/ordinals/index.ts new file mode 100644 index 00000000..d3f17d3a --- /dev/null +++ b/src/vdxf/classes/ordinals/index.ts @@ -0,0 +1,19 @@ +import { registerOrdinals } from '../../../constants/ordinals/register' + +export * from './DataDescriptorOrdinalVDXFObject' +export * from './IdentityUpdateRequestOrdinalVDXFObject' +export * from './IdentityUpdateResponseOrdinalVDXFObject' +export * from './OrdinalVDXFObject' +export * from './OrdinalVDXFObjectOrdinalMap' +export * from './SerializableEntityOrdinalVDXFObject' +export * from './VerusPayInvoiceOrdinalVDXFObject' +export * from './AuthenticationRequestOrdinalVDXFObject' +export * from './AuthenticationResponseOrdinalVDXFObject' +export * from './AppEncryptionRequestOrdinalVDXFObject' +export * from './AppEncryptionResponseOrdinalVDXFObject' +export * from './ProvisionIdentityDetailsOrdinalVDXFObject' +export * from './DataPacketResponseOrdinalVDXFObject' +export * from './UserDataRequestOrdinalVDXFObject' +export * from './UserSpecificDataPacketDetailsOrdinalVDXFObject' + +registerOrdinals(); \ No newline at end of file diff --git a/src/vdxf/classes/payment/VerusPayInvoice.ts b/src/vdxf/classes/payment/VerusPayInvoice.ts index bbe553ba..0739127c 100644 --- a/src/vdxf/classes/payment/VerusPayInvoice.ts +++ b/src/vdxf/classes/payment/VerusPayInvoice.ts @@ -17,12 +17,13 @@ import base64url from "base64url"; import { VerusPayInvoiceDetails, VerusPayInvoiceDetailsJson } from "./VerusPayInvoiceDetails"; import { BN } from 'bn.js'; import { BigNumber } from "../../../utils/types/BigNumber"; - -export const VERUSPAY_VERSION_CURRENT = new BN(3, 10) -export const VERUSPAY_VERSION_FIRSTVALID = new BN(3, 10) -export const VERUSPAY_VERSION_LASTVALID = new BN(3, 10) -export const VERUSPAY_VERSION_SIGNED = new BN('80000000', 16) -export const VERUSPAY_VERSION_MASK = VERUSPAY_VERSION_SIGNED; +import { + VERUSPAY_VERSION_CURRENT, + VERUSPAY_VERSION_FIRSTVALID, + VERUSPAY_VERSION_LASTVALID, + VERUSPAY_VERSION_MASK, + VERUSPAY_VERSION_SIGNED +} from "../../../constants/vdxf/veruspay"; export interface VerusPayInvoiceInterface { details: VerusPayInvoiceDetails; @@ -63,10 +64,11 @@ export class VerusPayInvoice extends VDXFObject { false ) : undefined; - this.details = new VerusPayInvoiceDetails(request.details); if (request.version) this.version = request.version; else this.version = VERUSPAY_VERSION_CURRENT; + + this.details = new VerusPayInvoiceDetails(request.details, this.getVersionNoFlags()); } getVersionNoFlags(): BigNumber { @@ -82,7 +84,7 @@ export class VerusPayInvoice extends VDXFObject { } setSigned() { - this.version = this.version.xor(VERUSPAY_VERSION_SIGNED); + this.version = this.version.or(VERUSPAY_VERSION_SIGNED); } getDetailsHash(signedBlockheight: number, signatureVersion: number = 2) { @@ -197,7 +199,7 @@ export class VerusPayInvoice extends VDXFObject { } const _details = new VerusPayInvoiceDetails(); - reader.offset = _details.fromBuffer(reader.buffer, reader.offset); + reader.offset = _details.fromBuffer(reader.buffer, reader.offset, this.getVersionNoFlags()); this.details = _details; } @@ -235,7 +237,7 @@ export class VerusPayInvoice extends VDXFObject { static fromJson(data: VerusPayInvoiceJson): VerusPayInvoice { return new VerusPayInvoice({ - details: VerusPayInvoiceDetails.fromJson(data.details), + details: VerusPayInvoiceDetails.fromJson(data.details, data.version ? new BN(data.version) : VERUSPAY_VERSION_CURRENT), signature: data.signature != null ? VerusIDSignature.fromJson(data.signature) : undefined, signing_id: data.signing_id, system_id: data.system_id, diff --git a/src/vdxf/classes/payment/VerusPayInvoiceDetails.ts b/src/vdxf/classes/payment/VerusPayInvoiceDetails.ts index 1cf4d131..42308a83 100644 --- a/src/vdxf/classes/payment/VerusPayInvoiceDetails.ts +++ b/src/vdxf/classes/payment/VerusPayInvoiceDetails.ts @@ -5,48 +5,63 @@ import { BN } from 'bn.js'; import { BigNumber } from '../../../utils/types/BigNumber'; import { TransferDestination, TransferDestinationJson } from '../../../pbaas/TransferDestination'; import { fromBase58Check, toBase58Check } from '../../../utils/address'; -import { I_ADDR_VERSION } from '../../../constants/vdxf'; +import { I_ADDR_VERSION, HASH160_BYTE_LENGTH } from '../../../constants/vdxf'; import createHash = require('create-hash'); +import { SerializableEntity } from '../../../utils/types/SerializableEntity'; +import { VERUSPAY_VERSION_4, VERUSPAY_VERSION_CURRENT } from '../../../constants/vdxf/veruspay'; +import { SaplingPaymentAddress } from '../../../pbaas'; +import { CompactAddressObject, CompactAddressObjectJson, CompactXAddressObject } from '../CompactAddressObject'; const { BufferReader, BufferWriter } = bufferutils; +// Added in V3 export const VERUSPAY_INVALID = new BN(0, 10) export const VERUSPAY_VALID = new BN(1, 10) export const VERUSPAY_ACCEPTS_CONVERSION = new BN(2, 10) export const VERUSPAY_ACCEPTS_NON_VERUS_SYSTEMS = new BN(4, 10) export const VERUSPAY_EXPIRES = new BN(8, 10) -export const VERUSPAY_ACCEPTS_ANY_DESTINATION = new BN(16, 0) -export const VERUSPAY_ACCEPTS_ANY_AMOUNT = new BN(32, 0) -export const VERUSPAY_EXCLUDES_VERUS_BLOCKCHAIN = new BN(64, 0) -export const VERUSPAY_IS_TESTNET = new BN(128, 0) +export const VERUSPAY_ACCEPTS_ANY_DESTINATION = new BN(16, 10) +export const VERUSPAY_ACCEPTS_ANY_AMOUNT = new BN(32, 10) +export const VERUSPAY_EXCLUDES_VERUS_BLOCKCHAIN = new BN(64, 10) +export const VERUSPAY_IS_TESTNET = new BN(128, 10) + +// Added in V4 +export const VERUSPAY_IS_PRECONVERT = new BN(256, 10) +export const VERUSPAY_DESTINATION_IS_SAPLING_PAYMENT_ADDRESS = new BN(512, 10) +export const VERUSPAY_IS_TAGGED = new BN(1024, 10) export type VerusPayInvoiceDetailsJson = { flags?: string, amount?: string, - destination?: TransferDestinationJson, + destination?: TransferDestinationJson | string, requestedcurrencyid: string, expiryheight?: string, maxestimatedslippage?: string, acceptedsystems?: Array, + tag?: CompactAddressObjectJson } -export class VerusPayInvoiceDetails { +export class VerusPayInvoiceDetails implements SerializableEntity { + verusPayVersion: BigNumber; + flags: BigNumber; amount: BigNumber; - destination: TransferDestination; + destination: TransferDestination | SaplingPaymentAddress; requestedcurrencyid: string; expiryheight: BigNumber; maxestimatedslippage: BigNumber; acceptedsystems: Array; + tag: CompactXAddressObject; constructor (data?: { flags?: BigNumber, amount?: BigNumber, - destination?: TransferDestination, + destination?: TransferDestination | SaplingPaymentAddress, requestedcurrencyid: string, expiryheight?: BigNumber, maxestimatedslippage?: BigNumber, acceptedsystems?: Array, - }) { + tag?: CompactXAddressObject + }, verusPayVersion: BigNumber = VERUSPAY_VERSION_CURRENT) { this.flags = VERUSPAY_VALID; this.amount = null; this.destination = null; @@ -54,6 +69,8 @@ export class VerusPayInvoiceDetails { this.expiryheight = null; this.maxestimatedslippage = null; this.acceptedsystems = null; + this.verusPayVersion = verusPayVersion; + this.tag = null; if (data != null) { if (data.flags != null) this.flags = data.flags @@ -63,6 +80,7 @@ export class VerusPayInvoiceDetails { if (data.expiryheight != null) this.expiryheight = data.expiryheight if (data.maxestimatedslippage != null) this.maxestimatedslippage = data.maxestimatedslippage if (data.acceptedsystems != null) this.acceptedsystems = data.acceptedsystems + if (data.tag != null) this.tag = data.tag } } @@ -73,15 +91,24 @@ export class VerusPayInvoiceDetails { acceptsAnyAmount?: boolean, acceptsAnyDestination?: boolean, excludesVerusBlockchain?: boolean, - isTestnet?: boolean + isTestnet?: boolean, + isPreconvert?: boolean, + destinationIsSaplingPaymentAddress?: boolean, + isTagged?: boolean }) { - if (flags.acceptsConversion) this.flags = this.flags.xor(VERUSPAY_ACCEPTS_CONVERSION); - if (flags.acceptsNonVerusSystems) this.flags = this.flags.xor(VERUSPAY_ACCEPTS_NON_VERUS_SYSTEMS); - if (flags.expires) this.flags = this.flags.xor(VERUSPAY_EXPIRES); - if (flags.acceptsAnyAmount) this.flags = this.flags.xor(VERUSPAY_ACCEPTS_ANY_AMOUNT); - if (flags.acceptsAnyDestination) this.flags = this.flags.xor(VERUSPAY_ACCEPTS_ANY_DESTINATION); - if (flags.excludesVerusBlockchain) this.flags = this.flags.xor(VERUSPAY_EXCLUDES_VERUS_BLOCKCHAIN); - if (flags.isTestnet) this.flags = this.flags.xor(VERUSPAY_IS_TESTNET); + if (flags.acceptsConversion) this.flags = this.flags.or(VERUSPAY_ACCEPTS_CONVERSION); + if (flags.acceptsNonVerusSystems) this.flags = this.flags.or(VERUSPAY_ACCEPTS_NON_VERUS_SYSTEMS); + if (flags.expires) this.flags = this.flags.or(VERUSPAY_EXPIRES); + if (flags.acceptsAnyAmount) this.flags = this.flags.or(VERUSPAY_ACCEPTS_ANY_AMOUNT); + if (flags.acceptsAnyDestination) this.flags = this.flags.or(VERUSPAY_ACCEPTS_ANY_DESTINATION); + if (flags.excludesVerusBlockchain) this.flags = this.flags.or(VERUSPAY_EXCLUDES_VERUS_BLOCKCHAIN); + if (flags.isTestnet) this.flags = this.flags.or(VERUSPAY_IS_TESTNET); + + if (this.isGTEV4()) { + if (flags.isPreconvert) this.flags = this.flags.or(VERUSPAY_IS_PRECONVERT); + if (flags.destinationIsSaplingPaymentAddress) this.flags = this.flags.or(VERUSPAY_DESTINATION_IS_SAPLING_PAYMENT_ADDRESS); + if (flags.isTagged) this.flags = this.flags.or(VERUSPAY_IS_TAGGED); + } } getFlagsJson(): { [key: string]: boolean } { @@ -92,7 +119,10 @@ export class VerusPayInvoiceDetails { acceptsAnyAmount: this.acceptsAnyAmount(), acceptsAnyDestination: this.acceptsAnyDestination(), excludesVerusBlockchain: this.excludesVerusBlockchain(), - isTestnet: this.isTestnet() + isTestnet: this.isTestnet(), + isPreconvert: this.isPreconvert(), + destinationIsSaplingPaymentAddress: this.destinationIsSaplingPaymentAddress(), + isTagged: this.isTagged() } } @@ -128,19 +158,56 @@ export class VerusPayInvoiceDetails { return !!(this.flags.and(VERUSPAY_IS_TESTNET).toNumber()) } + isPreconvert() { + return this.isGTEV4() && !!(this.flags.and(VERUSPAY_IS_PRECONVERT).toNumber()) + } + + destinationIsSaplingPaymentAddress() { + return this.isGTEV4() && !!(this.flags.and(VERUSPAY_DESTINATION_IS_SAPLING_PAYMENT_ADDRESS).toNumber()) + } + + isTagged() { + return this.isGTEV4() && !!(this.flags.and(VERUSPAY_IS_TAGGED).toNumber()) + } + isValid () { return ( !!(this.flags.and(VERUSPAY_VALID).toNumber()) ) } + isGTEV4() { + return (this.verusPayVersion.gte(VERUSPAY_VERSION_4)) + } + + // Functions to deal with change in v4 + private getVarUIntEncodingLength(uint: BigNumber): number { + return this.isGTEV4() ? varuint.encodingLength(uint.toNumber()) : varint.encodingLength(uint); + } + + private writeVarUInt(writer = new BufferWriter(Buffer.alloc(0)), uint: BigNumber): void { + if (this.isGTEV4()) { + return writer.writeCompactSize(uint.toNumber()); + } else { + return writer.writeVarInt(uint); + } + } + + private readVarUInt(reader = new BufferReader(Buffer.alloc(0))): BigNumber { + if (this.isGTEV4()) { + return new BN(reader.readCompactSize()); + } else { + return reader.readVarInt(); + } + } + getByteLength(): number { let length = 0; - length += varint.encodingLength(this.flags); + length += this.getVarUIntEncodingLength(this.flags); if (!this.acceptsAnyAmount()) { - length += varint.encodingLength(this.amount); + length += this.getVarUIntEncodingLength(this.amount); } if (!this.acceptsAnyDestination()) { @@ -150,69 +217,82 @@ export class VerusPayInvoiceDetails { length += fromBase58Check(this.requestedcurrencyid).hash.length; if (this.expires()) { - length += varint.encodingLength(this.expiryheight); + length += this.getVarUIntEncodingLength(this.expiryheight); } if (this.acceptsConversion()) { - length += varint.encodingLength(this.maxestimatedslippage); + length += this.getVarUIntEncodingLength(this.maxestimatedslippage); } if (this.acceptsNonVerusSystems()) { length += varuint.encodingLength(this.acceptedsystems.length); this.acceptedsystems.forEach(() => { - length += 20 + length += HASH160_BYTE_LENGTH }) } + if (this.isTagged()) { + length += this.tag.getByteLength(); + } + return length; } toBuffer () { const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); - writer.writeVarInt(this.flags); + this.writeVarUInt(writer, this.flags); - if (!this.acceptsAnyAmount()) writer.writeVarInt(this.amount); + if (!this.acceptsAnyAmount()) this.writeVarUInt(writer, this.amount); if (!this.acceptsAnyDestination()) writer.writeSlice(this.destination.toBuffer()); writer.writeSlice(fromBase58Check(this.requestedcurrencyid).hash); if (this.expires()) { - writer.writeVarInt(this.expiryheight); + this.writeVarUInt(writer, this.expiryheight); } if (this.acceptsConversion()) { - writer.writeVarInt(this.maxestimatedslippage); + this.writeVarUInt(writer, this.maxestimatedslippage); } if (this.acceptsNonVerusSystems()) { writer.writeArray(this.acceptedsystems.map(x => fromBase58Check(x).hash)); } + if (this.isTagged()) { + writer.writeSlice(this.tag.toBuffer()); + } + return writer.buffer; } - fromBuffer (buffer: Buffer, offset: number = 0) { + fromBuffer (buffer: Buffer, offset: number = 0, verusPayVersion: BigNumber = VERUSPAY_VERSION_CURRENT) { const reader = new BufferReader(buffer, offset); - this.flags = reader.readVarInt(); + this.verusPayVersion = verusPayVersion; + + this.flags = this.readVarUInt(reader); - if (!this.acceptsAnyAmount()) this.amount = reader.readVarInt(); + if (!this.acceptsAnyAmount()) this.amount = this.readVarUInt(reader); if (!this.acceptsAnyDestination()) { - this.destination = new TransferDestination(); - reader.offset = this.destination.fromBuffer(buffer, reader.offset); + if (this.destinationIsSaplingPaymentAddress()) { + this.destination = new SaplingPaymentAddress(); + } else this.destination = new TransferDestination(); + + reader.offset = this.destination.fromBuffer(reader.buffer, reader.offset); } this.requestedcurrencyid = toBase58Check(reader.readSlice(20), I_ADDR_VERSION); if (this.expires()) { - this.expiryheight = reader.readVarInt(); + this.expiryheight = this.readVarUInt(reader); } if (this.acceptsConversion()) { - this.maxestimatedslippage = reader.readVarInt(); + this.maxestimatedslippage = this.readVarUInt(reader); } if (this.acceptsNonVerusSystems()) { @@ -221,30 +301,38 @@ export class VerusPayInvoiceDetails { this.acceptedsystems = acceptedSystemsBuffers.map(x => toBase58Check(x, I_ADDR_VERSION)); } + if (this.isTagged()) { + this.tag = new CompactXAddressObject(); + + reader.offset = this.tag.fromBuffer(reader.buffer, reader.offset); + } + return reader.offset; } - static fromJson(data: VerusPayInvoiceDetailsJson): VerusPayInvoiceDetails { + static fromJson(data: VerusPayInvoiceDetailsJson, verusPayVersion: BigNumber = VERUSPAY_VERSION_CURRENT): VerusPayInvoiceDetails { return new VerusPayInvoiceDetails({ flags: new BN(data.flags), amount: data.amount != null ? new BN(data.amount) : undefined, - destination: data.destination != null ? TransferDestination.fromJson(data.destination) : undefined, + destination: data.destination != null ? typeof data.destination === 'string' ? SaplingPaymentAddress.fromAddressString(data.destination) : TransferDestination.fromJson(data.destination) : undefined, requestedcurrencyid: data.requestedcurrencyid, expiryheight: data.expiryheight != null ? new BN(data.expiryheight) : undefined, maxestimatedslippage: data.maxestimatedslippage != null ? new BN(data.maxestimatedslippage) : undefined, - acceptedsystems: data.acceptedsystems - }) + acceptedsystems: data.acceptedsystems, + tag: data.tag ? CompactAddressObject.fromJson(data.tag) as CompactXAddressObject : undefined + }, verusPayVersion) } toJson(): VerusPayInvoiceDetailsJson { return { flags: this.flags.toString(), amount: this.acceptsAnyAmount() ? undefined : this.amount.toString(), - destination: this.acceptsAnyDestination() ? undefined : this.destination.toJson(), + destination: this.acceptsAnyDestination() ? undefined : this.destinationIsSaplingPaymentAddress() ? (this.destination as SaplingPaymentAddress).toAddressString() : (this.destination as TransferDestination).toJson(), requestedcurrencyid: this.requestedcurrencyid, expiryheight: this.expires() ? this.expiryheight.toString() : undefined, maxestimatedslippage: this.acceptsConversion() ? this.maxestimatedslippage.toString() : undefined, acceptedsystems: this.acceptsNonVerusSystems() ? this.acceptedsystems : undefined, + tag: this.isTagged() ? this.tag.toJson() : undefined } } } \ No newline at end of file diff --git a/src/vdxf/classes/request/GenericRequest.ts b/src/vdxf/classes/request/GenericRequest.ts new file mode 100644 index 00000000..40936d95 --- /dev/null +++ b/src/vdxf/classes/request/GenericRequest.ts @@ -0,0 +1,192 @@ +import { BN } from 'bn.js'; +import { SerializableEntity } from "../../../utils/types/SerializableEntity"; +import { GenericEnvelope, GenericEnvelopeInterface, GenericEnvelopeJson } from "../envelope/GenericEnvelope"; +import { SaplingPaymentAddress } from '../../../pbaas/SaplingPaymentAddress'; +import bufferutils from '../../../utils/bufferutils'; +import base64url from 'base64url'; +import { DEEPLINK_PROTOCOL_URL_CURRENT_VERSION, DEEPLINK_PROTOCOL_URL_STRING } from '../../../constants/deeplink'; +import { ResponseURI, ResponseURIJson } from '../ResponseURI'; +import varuint from '../../../utils/varuint'; + +export type GenericRequestJson = GenericEnvelopeJson & { + responseuris?: Array; + encryptresponsetoaddress?: string; +}; + +export type GenericRequestInterface = GenericEnvelopeInterface & { + responseURIs?: Array; + encryptResponseToAddress?: SaplingPaymentAddress; +} + +export class GenericRequest extends GenericEnvelope implements SerializableEntity { + responseURIs?: Array; + encryptResponseToAddress?: SaplingPaymentAddress; + + static VERSION_CURRENT = new BN(1, 10); + static VERSION_FIRSTVALID = new BN(1, 10); + static VERSION_LASTVALID = new BN(1, 10); + + static BASE_FLAGS = GenericEnvelope.BASE_FLAGS; + static FLAG_SIGNED = GenericEnvelope.FLAG_SIGNED; + static FLAG_HAS_CREATED_AT = GenericEnvelope.FLAG_HAS_CREATED_AT; + static FLAG_MULTI_DETAILS = GenericEnvelope.FLAG_MULTI_DETAILS; + static FLAG_IS_TESTNET = GenericEnvelope.FLAG_IS_TESTNET; + static FLAG_HAS_SALT = GenericEnvelope.FLAG_HAS_SALT; + static FLAG_HAS_APP_OR_DELEGATED_ID = GenericEnvelope.FLAG_HAS_APP_OR_DELEGATED_ID; + + static FLAG_HAS_RESPONSE_URIS = new BN(128, 10); + static FLAG_HAS_ENCRYPT_RESPONSE_TO_ADDRESS = new BN(256, 10); + + constructor( + envelope: GenericRequestInterface = { + details: [], + flags: GenericRequest.BASE_FLAGS + } + ) { + super(envelope) + + this.responseURIs = envelope?.responseURIs; + this.encryptResponseToAddress = envelope?.encryptResponseToAddress; + + this.setFlags(); + } + + hasResponseURIs() { + return !!(this.flags.and(GenericRequest.FLAG_HAS_RESPONSE_URIS).toNumber()); + } + + hasEncryptResponseToAddress() { + return !!(this.flags.and(GenericRequest.FLAG_HAS_ENCRYPT_RESPONSE_TO_ADDRESS).toNumber()); + } + + setHasResponseURIs() { + this.flags = this.flags.or(GenericRequest.FLAG_HAS_RESPONSE_URIS); + } + + setHasEncryptResponseToAddress() { + this.flags = this.flags.or(GenericRequest.FLAG_HAS_ENCRYPT_RESPONSE_TO_ADDRESS); + } + + setFlags() { + super.setFlags(); + + if (this.responseURIs) this.setHasResponseURIs(); + if (this.encryptResponseToAddress) this.setHasEncryptResponseToAddress(); + } + + getByteLengthOptionalSig(includeSig = true): number { + let length = super.getByteLengthOptionalSig(includeSig); + + if (this.hasResponseURIs()) { + length += varuint.encodingLength(this.responseURIs.length); + + for (let i = 0; i < this.responseURIs.length; i++) { + length += this.responseURIs[i].getByteLength(); + } + } + + if (this.hasEncryptResponseToAddress()) { + length += this.encryptResponseToAddress.getByteLength(); + } + + return length; + } + + toBufferOptionalSig(includeSig = true) { + const writer = new bufferutils.BufferWriter( + Buffer.alloc(this.getByteLengthOptionalSig(includeSig)) + ); + + const superBuf = super.toBufferOptionalSig(includeSig); + + writer.writeSlice(superBuf); + + if (this.hasResponseURIs()) { + writer.writeCompactSize(this.responseURIs.length); + + for (let i = 0; i < this.responseURIs.length; i++) { + writer.writeSlice(this.responseURIs[i].toBuffer()); + } + } + + if (this.hasEncryptResponseToAddress()) { + writer.writeSlice(this.encryptResponseToAddress.toBuffer()); + } + + return writer.buffer; + } + + fromBuffer(buffer: Buffer, offset?: number): number { + if (buffer.length == 0) throw new Error("Cannot create request from empty buffer"); + + const reader = new bufferutils.BufferReader(buffer, offset); + + reader.offset = super.fromBuffer(reader.buffer, reader.offset); + + if (this.hasResponseURIs()) { + this.responseURIs = []; + const callbackURIsLength = reader.readCompactSize(); + + for (let i = 0; i < callbackURIsLength; i++) { + const newURI = new ResponseURI(); + reader.offset = newURI.fromBuffer(reader.buffer, reader.offset); + this.responseURIs.push(newURI); + } + } + + if (this.hasEncryptResponseToAddress()) { + this.encryptResponseToAddress = new SaplingPaymentAddress(); + + reader.offset = this.encryptResponseToAddress.fromBuffer(reader.buffer, reader.offset); + } + + return reader.offset; + } + + toJson(): GenericRequestJson { + const parentJson = super.toJson(); + + if (this.hasResponseURIs()) { + parentJson["responseuris"] = this.responseURIs.map(x => x.toJson()) + } + + if (this.hasEncryptResponseToAddress()) { + parentJson["encryptresponsetoaddress"] = this.encryptResponseToAddress.toAddressString(); + } + + return parentJson; + } + + static fromWalletDeeplinkUri(uri: string): GenericRequest { + const urlProtocol = `${DEEPLINK_PROTOCOL_URL_STRING}:`; + + const split = uri.split(`/`); + + if (split.length !== 4 || split.some(x => x == null)) throw new Error("Unrecognized URL format"); + + if (split[0] !== urlProtocol) throw new Error("Unrecognized URL protocol"); + else if (isNaN(Number(split[2])) || !(new BN(split[2], 10).eq(DEEPLINK_PROTOCOL_URL_CURRENT_VERSION))) { + throw new Error("Unrecognized or incompatible generic request protocol version") + } + + const inv = new GenericRequest(); + inv.fromBuffer(base64url.toBuffer(split[3]), 0); + + return inv; + } + + static fromQrString(qrstring: string): GenericRequest { + const inv = new GenericRequest(); + inv.fromBuffer(base64url.toBuffer(qrstring), 0); + + return inv; + } + + toWalletDeeplinkUri(): string { + return `${DEEPLINK_PROTOCOL_URL_STRING}://${DEEPLINK_PROTOCOL_URL_CURRENT_VERSION.toString()}/${this.toString()}`; + } + + toQrString(): string { + return this.toString(); + } +} \ No newline at end of file diff --git a/src/vdxf/classes/requestobjects/ProvisionIdentityDetails.ts b/src/vdxf/classes/requestobjects/ProvisionIdentityDetails.ts new file mode 100644 index 00000000..2705485a --- /dev/null +++ b/src/vdxf/classes/requestobjects/ProvisionIdentityDetails.ts @@ -0,0 +1,208 @@ +/** + * ProvisioningIdentity - Class for handling identity provisioning requests + * + * This class is used when an application is requesting the provisioning or creation of a new identity + * within the Verus blockchain ecosystem. The request includes: + * - System ID (e.g., VRSC@) defining the blockchain system + * - Parent ID (e.g., Token@) defining the parent namespace + * - Identity ID (e.g., john.VRSC@) defining the full identity to be provisioned + * - Flags indicating which components are present and required + * + * The user's wallet can use these parameters to understand the complete identity hierarchy + * and present a clear provisioning request to the user, showing the system context, + * parent namespace, and the specific identity being created. This enables secure, + * user-controlled identity provisioning with proper namespace management. + */ + +import bufferutils from "../../../utils/bufferutils"; +import { BigNumber } from "../../../utils/types/BigNumber"; +import { BN } from "bn.js"; +import { SerializableEntity } from "../../../utils/types/SerializableEntity"; +import { CompactIAddressObject, CompactAddressObjectJson } from "../CompactAddressObject"; +import varuint from "../../../utils/varuint"; + +export interface ProvisionIdentityDetailsInterface { + version?: BigNumber; + flags: BigNumber; + systemID?: CompactIAddressObject; // system e.g. VRSC@ + parentID?: CompactIAddressObject; // parent e.g. Token@ + identityID?: CompactIAddressObject; // Full identity e.g. john.VRSC@ +} + +export interface ProvisionIdentityDetailsJson { + version?: number; + flags: number; + systemid?: CompactAddressObjectJson; + parentid?: CompactAddressObjectJson; + identityid?: CompactAddressObjectJson; +} + +export class ProvisionIdentityDetails implements SerializableEntity { + version: BigNumber; + flags: BigNumber; + systemID?: CompactIAddressObject; // system e.g. VRSC@ + parentID?: CompactIAddressObject; // parent e.g. Token@ + identityID?: CompactIAddressObject; // Full identity e.g. john.VRSC@ + + // Version + static DEFAULT_VERSION = new BN(1, 10) + static VERSION_FIRSTVALID = new BN(1, 10) + static VERSION_LASTVALID = new BN(1, 10) + + // flags include params // parent same as signer + static FLAG_HAS_SYSTEMID = new BN(1, 10); + static FLAG_HAS_PARENTID = new BN(2, 10); + static FLAG_IS_A_DEFINED_NAME_TO_PROVISION = new BN(4, 10); + + constructor(data?: ProvisionIdentityDetailsInterface) { + this.version = data?.version || ProvisionIdentityDetails.DEFAULT_VERSION; + this.flags = data?.flags || new BN(0, 10); + this.systemID = data?.systemID; + this.parentID = data?.parentID; + this.identityID = data?.identityID; + + this.setFlags(); + } + + hasSystemId(): boolean { + return this.flags.and(ProvisionIdentityDetails.FLAG_HAS_SYSTEMID).eq(ProvisionIdentityDetails.FLAG_HAS_SYSTEMID); + } + + hasParentId(): boolean { + return this.flags.and(ProvisionIdentityDetails.FLAG_HAS_PARENTID).eq(ProvisionIdentityDetails.FLAG_HAS_PARENTID); + } + + hasIdentityId(): boolean { + return this.flags.and(ProvisionIdentityDetails.FLAG_IS_A_DEFINED_NAME_TO_PROVISION).eq(ProvisionIdentityDetails.FLAG_IS_A_DEFINED_NAME_TO_PROVISION); + } + + getByteLength(): number { + let length = 0; + + length += varuint.encodingLength(this.flags.toNumber()); + if (this.hasSystemId()) { + length += this.systemID.getByteLength(); + } + + if (this.hasParentId()) { + length += this.parentID.getByteLength(); + } + + if (this.hasIdentityId()) { + length += this.identityID.getByteLength(); + } + + return length; + } + + toBuffer(): Buffer { + const writer = new bufferutils.BufferWriter(Buffer.alloc(this.getByteLength())) + + writer.writeCompactSize(this.flags.toNumber()); + + if (this.hasSystemId()) { + writer.writeSlice(this.systemID.toBuffer()); + } + + if (this.hasParentId()) { + writer.writeSlice(this.parentID.toBuffer()); + } + + if (this.hasIdentityId()) { + writer.writeSlice(this.identityID.toBuffer()); + } + + return writer.buffer; + } + + fromBuffer(buffer: Buffer, offset?: number): number { + const reader = new bufferutils.BufferReader(buffer, offset); + if (buffer.length == 0) throw new Error("Cannot create provision identity from empty buffer"); + + this.flags = new BN(reader.readCompactSize()); + + if (this.hasSystemId()) { + const systemID = new CompactIAddressObject(); + reader.offset = systemID.fromBuffer(reader.buffer, reader.offset); + this.systemID = systemID; + } + + if (this.hasParentId()) { + const parentID = new CompactIAddressObject(); + reader.offset = parentID.fromBuffer(reader.buffer, reader.offset); + this.parentID = parentID; + } + + if (this.hasIdentityId()) { + const identityID = new CompactIAddressObject(); + reader.offset = identityID.fromBuffer(reader.buffer, reader.offset); + this.identityID = identityID; + } + + return reader.offset; + } + + toJson(): ProvisionIdentityDetailsJson { + const flags = this.calcFlags(); + return { + version: this.version.toNumber(), + flags: flags.toNumber(), + systemid: this.systemID ? this.systemID.toJson() : null, + parentid: this.parentID ? this.parentID.toJson() : null, + identityid: this.identityID ? this.identityID.toJson() : null, + }; + } + + static fromJson(data: any): ProvisionIdentityDetails { + + const provision = new ProvisionIdentityDetails(); + provision.version = new BN(data?.version || 0); + provision.flags = new BN(data?.flags || 0); + + if (provision.hasSystemId()) { + provision.systemID = CompactIAddressObject.fromCompactAddressObjectJson(data.systemid); + } + + if (provision.hasParentId()) { + provision.parentID = CompactIAddressObject.fromCompactAddressObjectJson(data.parentid); + } + + if (provision.hasIdentityId()) { + provision.identityID = CompactIAddressObject.fromCompactAddressObjectJson(data.identityid); + } + + return provision; + } + + calcFlags(): BigNumber { + let flags = new BN(0, 10); + + if (this.systemID) { + flags = flags.or(ProvisionIdentityDetails.FLAG_HAS_SYSTEMID); + } + + if (this.parentID) { + flags = flags.or(ProvisionIdentityDetails.FLAG_HAS_PARENTID); + } + + if (this.identityID) { + flags = flags.or(ProvisionIdentityDetails.FLAG_IS_A_DEFINED_NAME_TO_PROVISION); + } + + return flags; + } + + setFlags() { + this.flags = this.calcFlags(); + } + + + isValid(): boolean { + let valid = this.flags != null && this.flags.gte(new BN(0)); + + valid &&= this.version != null; + + return valid; + } + +} \ No newline at end of file diff --git a/src/vdxf/classes/requestobjects/UserDataRequestDetails.ts b/src/vdxf/classes/requestobjects/UserDataRequestDetails.ts new file mode 100644 index 00000000..0a82fa5e --- /dev/null +++ b/src/vdxf/classes/requestobjects/UserDataRequestDetails.ts @@ -0,0 +1,285 @@ + +/** + * InformationRequest - Class for handling application requests for specific user information/data + * + * This class is used when an application is requesting specific information or data from the user's + * identity or data stores. The request includes: + * - Search data keys (VDXF keys) to identify the specific data being requested + * - Optional specific keys within the data object for partial data requests + * - Signer information to identify wanted signer of the data + * - Optional statement for boundhashes in the signature + * + * The user's wallet can use these parameters to locate the signed object information and present + * it to the user for approval before sharing with the requesting application. This enables + * selective disclosure of personal information while maintaining user privacy and control. + * + * Flags determine the type and scope of the request: + * - FULL_DATA vs PARTIAL_DATA: Whether complete objects or specific fields are requested + * - COLLECTION: Whether multiple data objects are being requested + * - HAS_STATEMENT: Whether the request includes an attestation statement + * - ATTESTATION/CLAIM/CREDENTIAL: Type of verification being requested + */ + +import { BigNumber } from '../../../utils/types/BigNumber'; +import { BN } from 'bn.js'; +import varuint from '../../../utils/varuint'; +import bufferutils from '../../../utils/bufferutils'; +const { BufferReader, BufferWriter } = bufferutils; +import { SerializableEntity } from '../../../utils/types/SerializableEntity'; +import { CompactIAddressObject, CompactAddressObjectJson } from '../CompactAddressObject'; +import { fromBase58Check, toBase58Check } from '../../../utils/address'; +import { I_ADDR_VERSION, HASH160_BYTE_LENGTH } from '../../../constants/vdxf'; + +export interface UserDataRequestInterface { + version?: BigNumber; + flags: BigNumber; + searchDataKey: Array<{[key: string]: string}>; + signer?: CompactIAddressObject; + requestedKeys?: string[]; + requestID?: string; +} + +export interface UserDataRequestJson { + version: number; + flags: number; + searchdatakey: Array<{[key: string]: string}>; // ID object of the specific information requested + signer?: CompactAddressObjectJson; + requestedkeys?: string[]; // Specific keys within the data object being requested + requestid?: string; +} + +export class UserDataRequestDetails implements SerializableEntity { + static VERSION_INVALID = new BN(0); + static FIRST_VERSION = new BN(1); + static LAST_VERSION = new BN(1); + static DEFAULT_VERSION = new BN(1); + + static FULL_DATA = new BN(1); + static PARTIAL_DATA = new BN(2); + static COLLECTION = new BN(4); + + static ATTESTATION = new BN(8); + static CLAIM = new BN(16); + static CREDENTIAL = new BN(32); + + static HAS_SIGNER = new BN(64); + static HAS_REQUESTED_KEYS = new BN(128); + static HAS_REQUEST_ID = new BN(256); + + version: BigNumber; + flags: BigNumber; + searchDataKey: Array<{[key: string]: string}>; + signer?: CompactIAddressObject; + requestedKeys?: string[]; + requestID?: string; + + constructor(data?: UserDataRequestInterface) { + this.version = data?.version || UserDataRequestDetails.DEFAULT_VERSION; + this.flags = data?.flags || new BN(0); + this.searchDataKey = data?.searchDataKey || []; + this.signer = data?.signer; + this.requestedKeys = data?.requestedKeys; + this.requestID = data?.requestID; + + this.setFlags(); + } + + calcFlags(): BigNumber { + let flags = new BN(0); + if (this.requestedKeys && this.requestedKeys.length > 0) { + flags = flags.or(UserDataRequestDetails.HAS_REQUESTED_KEYS); + } + if (this.signer) { + flags = flags.or(UserDataRequestDetails.HAS_SIGNER); + } + if (this.requestID) { + flags = flags.or(UserDataRequestDetails.HAS_REQUEST_ID); + } + + return flags; + } + + setFlags(): void { + this.flags = this.calcFlags(); + } + + hasSigner(): boolean { + return this.flags.and(UserDataRequestDetails.HAS_SIGNER).eq(UserDataRequestDetails.HAS_SIGNER); + } + + hasRequestedKeys(): boolean { + return this.flags.and(UserDataRequestDetails.HAS_REQUESTED_KEYS).eq(UserDataRequestDetails.HAS_REQUESTED_KEYS); + } + + hasRequestID(): boolean { + return this.flags.and(UserDataRequestDetails.HAS_REQUEST_ID).eq(UserDataRequestDetails.HAS_REQUEST_ID); + } + + /** + * Checks if exactly one data type flag is set (FULL_DATA, PARTIAL_DATA, or COLLECTION) + * @returns True if exactly one data type flag is set + */ + hasDataTypeSet(): boolean { + const dataTypeFlags = UserDataRequestDetails.FULL_DATA.or(UserDataRequestDetails.PARTIAL_DATA).or(UserDataRequestDetails.COLLECTION); + const setDataFlags = this.flags.and(dataTypeFlags); + + // Check if exactly one flag is set by verifying it's a power of 2 + return !setDataFlags.isZero() && setDataFlags.and(setDataFlags.sub(new BN(1))).isZero(); + } + + /** + * Checks if exactly one request type flag is set (ATTESTATION, CLAIM, or CREDENTIAL) + * @returns True if exactly one request type flag is set + */ + hasRequestTypeSet(): boolean { + const requestTypeFlags = UserDataRequestDetails.ATTESTATION.or(UserDataRequestDetails.CLAIM).or(UserDataRequestDetails.CREDENTIAL); + const setRequestFlags = this.flags.and(requestTypeFlags); + + // Check if exactly one flag is set by verifying it's a power of 2 + return !setRequestFlags.isZero() && setRequestFlags.and(setRequestFlags.sub(new BN(1))).isZero(); + } + + isValid(): boolean { + let valid = this.version.gte(UserDataRequestDetails.FIRST_VERSION) && this.version.lte(UserDataRequestDetails.LAST_VERSION); + + // Check that exactly one data type flag is set + valid &&= this.hasDataTypeSet(); + + // Check that exactly one request type flag is set + valid &&= this.hasRequestTypeSet(); + + // Check that searchDataKey is present + valid &&= Object.keys(this.searchDataKey).length > 0; + + return valid; + } + + getByteLength(): number { + let length = 0; + + length += varuint.encodingLength(this.flags.toNumber()); + length += varuint.encodingLength(this.searchDataKey.length); + + for (const item of this.searchDataKey) { + const key = Object.keys(item)[0]; + const value = item[key]; + length += HASH160_BYTE_LENGTH; + length += varuint.encodingLength(Buffer.byteLength(value, 'utf8')); + length += Buffer.byteLength(value, 'utf8'); + } + + if (this.hasSigner()) { + length += this.signer.getByteLength(); + } + + if (this.hasRequestedKeys()) { + length += varuint.encodingLength(this.requestedKeys ? this.requestedKeys.length : 0); + if (this.requestedKeys) { + for (const key of this.requestedKeys) { + length += HASH160_BYTE_LENGTH; + } + } + } + + if (this.hasRequestID()) { + length += HASH160_BYTE_LENGTH; + } + + return length; + } + + toBuffer(): Buffer { + const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); + writer.writeCompactSize(this.flags.toNumber()); + + writer.writeCompactSize(this.searchDataKey.length); + + for (const item of this.searchDataKey) { + const key = Object.keys(item)[0]; + const value = item[key]; + writer.writeSlice(fromBase58Check(key).hash); // 20-byte VDXF key + writer.writeVarSlice(Buffer.from(value, 'utf8')); + } + + if (this.hasSigner()) { + writer.writeSlice(this.signer.toBuffer()); + } + + if(this.hasRequestedKeys()) { + writer.writeCompactSize(this.requestedKeys.length); + for (const key of this.requestedKeys) { + writer.writeSlice(fromBase58Check(key).hash); // 20-byte VDXF key + } + } + + if (this.hasRequestID()) { + writer.writeSlice(fromBase58Check(this.requestID).hash); + } + + return writer.buffer; + } + + fromBuffer(buffer: Buffer, offset?: number): number { + const reader = new BufferReader(buffer, offset); + this.flags = new BN(reader.readCompactSize()); + + const searchDataKeyLength = reader.readCompactSize(); + this.searchDataKey = []; + + for (let i = 0; i < searchDataKeyLength; i++) { + const keyHash = reader.readSlice(HASH160_BYTE_LENGTH); // 20-byte VDXF key + const valueBuffer = reader.readVarSlice(); + const value = valueBuffer.toString('utf8'); + const key = toBase58Check(keyHash, I_ADDR_VERSION); + this.searchDataKey.push({ [key]: value }); + } + + if (this.hasSigner()) { + const signer = new CompactIAddressObject(); + + reader.offset = signer.fromBuffer(reader.buffer, reader.offset); + this.signer = signer; + } + + if (this.hasRequestedKeys()) { + const requestedKeysLength = reader.readCompactSize(); + this.requestedKeys = []; + for (let i = 0; i < requestedKeysLength; i++) { + const keyHash = reader.readSlice(20); // 20-byte VDXF key + const key = toBase58Check(keyHash, I_ADDR_VERSION); + this.requestedKeys.push(key); + } + } + + if (this.hasRequestID()) { + this.requestID = toBase58Check(reader.readSlice(20), I_ADDR_VERSION); + } + + return reader.offset; + } + + toJson(): UserDataRequestJson { + const flags = this.calcFlags(); + + return { + version: this.version.toNumber(), + flags: flags.toNumber(), + searchdatakey: this.searchDataKey, + signer: this.signer?.toJson(), + requestedkeys: this.requestedKeys, + requestid: this.requestID + }; + } + + static fromJson(json: UserDataRequestJson) { + const requestData = new UserDataRequestDetails(); + requestData.version = new BN(json.version); + requestData.flags = new BN(json.flags); + requestData.searchDataKey = json.searchdatakey; + requestData.signer = json.signer ? CompactIAddressObject.fromCompactAddressObjectJson(json.signer) : undefined; + requestData.requestedKeys = json.requestedkeys; + requestData.requestID = json.requestid; + + return requestData; + } +} diff --git a/src/vdxf/classes/requestobjects/UserSpecificDataPacketDetails.ts b/src/vdxf/classes/requestobjects/UserSpecificDataPacketDetails.ts new file mode 100644 index 00000000..2d6b8038 --- /dev/null +++ b/src/vdxf/classes/requestobjects/UserSpecificDataPacketDetails.ts @@ -0,0 +1,267 @@ +/** + * UserSpecificDataPacketDetails - Class for sending personal data to user or requesting the user + * signature on personal data + * + * This class is used when an application is requesting to transfer or receive personal + * user data. The request includes: + * - Data objects as DataDescriptor instances containing the user's personal data + * - Optional statements array for additional context or transfer conditions + * - Optional signature data for verification of the transfer + * - Flags indicating transfer direction and optional components + * + * The user's wallet can use these parameters to present the data transfer request + * to the user, showing what personal data is being transferred, any associated + * statements or conditions, and whether it's for the user's signature or being + * transmitted to/from the user. This enables secure, user-controlled personal + * data sharing with clear visibility into what data is being transferred. + * + + */ + +import { BigNumber } from '../../../utils/types/BigNumber'; +import { BN } from 'bn.js'; +import varuint from '../../../utils/varuint'; +import bufferutils from '../../../utils/bufferutils'; +const { BufferReader, BufferWriter } = bufferutils; +import { SerializableEntity } from '../../../utils/types/SerializableEntity'; +import { DataDescriptor, DataDescriptorJson } from '../../../pbaas'; +import { VerifiableSignatureData, VerifiableSignatureDataJson } from '../VerifiableSignatureData'; +import { fromBase58Check, toBase58Check } from '../../../utils/address'; +import { I_ADDR_VERSION, HASH160_BYTE_LENGTH } from '../../../constants/vdxf'; + +export interface UserSpecificDataPacketDetailsInterface { + version?: BigNumber; + flags: BigNumber; + signableObjects: Array; + statements?: Array; + signature?: VerifiableSignatureData; + detailsID?: string; +} + +export interface UserSpecificDataPacketDetailsJson { + version: number; + flags: number; + signableobjects: Array; // Array of signable data objects + statements?: Array; + signature?: VerifiableSignatureDataJson; + detailsid?: string; +} + + +// User_specific_data_packet +export class UserSpecificDataPacketDetails implements SerializableEntity { + static VERSION_INVALID = new BN(0); + static FIRST_VERSION = new BN(1); + static LAST_VERSION = new BN(1); + static DEFAULT_VERSION = new BN(1); + + // types of data to sign + static HAS_STATEMENTS = new BN(1); + static HAS_SIGNATURE = new BN(2); + static FOR_USERS_SIGNATURE = new BN(4); + static FOR_TRANSMITTAL_TO_USER = new BN(8); + static HAS_URL_FOR_DOWNLOAD = new BN(16); + static HAS_DETAILS_ID = new BN(32); + + version: BigNumber; + flags: BigNumber; + signableObjects: Array; + statements?: Array; + signature?: VerifiableSignatureData; + detailsID?: string; + + constructor(data?: UserSpecificDataPacketDetailsInterface) { + this.version = data?.version || UserSpecificDataPacketDetails.DEFAULT_VERSION; + this.flags = data?.flags || new BN(0); + this.signableObjects = data?.signableObjects || []; + this.statements = data?.statements || []; + this.signature = data?.signature || undefined; + this.detailsID = data?.detailsID; + + this.setFlags(); + } + + setFlags(): void { + this.flags = this.calcFlags(); + } + + calcFlags(): BigNumber { + let flags = new BN(0); + + if (this.statements && this.statements.length > 0) { + flags = flags.or(UserSpecificDataPacketDetails.HAS_STATEMENTS); + } + + if (this.signature ) { + flags = flags.or(UserSpecificDataPacketDetails.HAS_SIGNATURE); + } + + if (this.detailsID) { + flags = flags.or(UserSpecificDataPacketDetails.HAS_DETAILS_ID); + } + + return flags; + } + + hasStatements(): boolean { + return this.flags.and(UserSpecificDataPacketDetails.HAS_STATEMENTS).eq(UserSpecificDataPacketDetails.HAS_STATEMENTS); + } + + hasSignature(): boolean { + return this.flags.and(UserSpecificDataPacketDetails.HAS_SIGNATURE).eq(UserSpecificDataPacketDetails.HAS_SIGNATURE); + } + + hasDetailsID(): boolean { + return this.flags.and(UserSpecificDataPacketDetails.HAS_DETAILS_ID).eq(UserSpecificDataPacketDetails.HAS_DETAILS_ID); + } + + isValid(): boolean { + let valid = this.version.gte(UserSpecificDataPacketDetails.FIRST_VERSION) && + this.version.lte(UserSpecificDataPacketDetails.LAST_VERSION); + + // Check that we have signable objects + valid &&= this.signableObjects.length > 0; + if (this.hasStatements()) { + valid &&= this.statements !== undefined && this.statements.length > 0; + } + + if (this.hasSignature()) { + valid &&= this.signature !== undefined; // TODO: && this.signature.isValid(); + } + + return valid; + } + + getByteLength(): number { + let length = 0; + + length += varuint.encodingLength(this.flags.toNumber()); + + // Add length for signableObjects array + length += varuint.encodingLength(this.signableObjects.length); + + for (const obj of this.signableObjects) { + + length += obj.getByteLength(); + } + + // Add signer length if present + if (this.hasStatements()) { + length += varuint.encodingLength(this.statements.length); + for (const stmt of this.statements) { + length += varuint.encodingLength(Buffer.byteLength(stmt, 'utf8')); + length += Buffer.byteLength(stmt, 'utf8'); + } + } + if (this.hasSignature() && this.signature) { + length += this.signature.getByteLength(); + } + + if (this.hasDetailsID()) { + length += HASH160_BYTE_LENGTH; + } + + return length; + } + + toBuffer(): Buffer { + const writer = new BufferWriter(Buffer.alloc(this.getByteLength())); + + writer.writeCompactSize(this.flags.toNumber()); + + // Write signableObjects array + writer.writeCompactSize(this.signableObjects.length); + + for (const obj of this.signableObjects) { + writer.writeSlice(obj.toBuffer()); + } + + // Write statements if present + if (this.hasStatements()) { + writer.writeCompactSize(this.statements.length); + for (const stmt of this.statements) { + writer.writeVarSlice(Buffer.from(stmt, 'utf8')); + } + } + + if (this.hasSignature() && this.signature) { + writer.writeSlice(this.signature.toBuffer()); + } + + if (this.hasDetailsID()) { + writer.writeSlice(fromBase58Check(this.detailsID).hash); + } + + return writer.buffer; + } + + fromBuffer(buffer: Buffer, offset?: number): number { + const reader = new BufferReader(buffer, offset); + + this.flags = new BN(reader.readCompactSize()); + + // Read signableObjects array + const objectCount = reader.readCompactSize(); + this.signableObjects = []; + + for (let i = 0; i < objectCount; i++) { + const obj = new DataDescriptor(); + reader.offset = obj.fromBuffer(reader.buffer, reader.offset); + this.signableObjects.push(obj); + } + + // Read statements if flag is set + if (this.hasStatements()) { + this.statements = []; + const statementCount = reader.readCompactSize(); + for (let i = 0; i < statementCount; i++) { + const stmt = reader.readVarSlice().toString('utf8'); + this.statements.push(stmt); + } + } + + if (this.hasSignature()) { + const signature = new VerifiableSignatureData(); + reader.offset = signature.fromBuffer(reader.buffer, reader.offset); + this.signature = signature; + } + + if (this.hasDetailsID()) { + this.detailsID = toBase58Check(reader.readSlice(20), I_ADDR_VERSION); + } + + return reader.offset; + } + + toJson(): UserSpecificDataPacketDetailsJson { + const flags = this.calcFlags(); + + return { + version: this.version.toNumber(), + flags: flags.toNumber(), + signableobjects: this.signableObjects.map(obj => obj.toJson()), + statements: this.statements, + signature: this.signature ? this.signature.toJson() : undefined, + detailsid: this.detailsID + }; + } + + static fromJson(json: UserSpecificDataPacketDetailsJson): UserSpecificDataPacketDetails { + const instance = new UserSpecificDataPacketDetails(); + instance.version = new BN(json.version); + instance.flags = new BN(json.flags); + + const dataDescriptorObjects: Array = []; + + for (const objJson of json.signableobjects) { + const dataDescriptor = DataDescriptor.fromJson(objJson); + dataDescriptorObjects.push(dataDescriptor); + } + + instance.signableObjects = dataDescriptorObjects; + instance.statements = json.statements || []; + instance.signature = json.signature ? VerifiableSignatureData.fromJson(json.signature) : undefined; + instance.detailsID = json.detailsid; + return instance; + } +} \ No newline at end of file diff --git a/src/vdxf/classes/response/GenericResponse.ts b/src/vdxf/classes/response/GenericResponse.ts new file mode 100644 index 00000000..b6025667 --- /dev/null +++ b/src/vdxf/classes/response/GenericResponse.ts @@ -0,0 +1,126 @@ +import { BN } from 'bn.js'; +import { SerializableEntity } from "../../../utils/types/SerializableEntity"; +import { GenericEnvelope, GenericEnvelopeInterface, GenericEnvelopeJson } from "../envelope/GenericEnvelope"; +import bufferutils from '../../../utils/bufferutils'; +import { BigNumber } from '../../../utils/types/BigNumber'; +import { EHashTypes } from '../../../pbaas/DataDescriptor'; +import varuint from '../../../utils/varuint'; + +export type GenericResponseJson = GenericEnvelopeJson & { + requesthash?: string, + requesthashtype?: number +} + +export type GenericResponseInterface = GenericEnvelopeInterface & { + requestHash?: Buffer, + requestHashType?: BigNumber +} + +export class GenericResponse extends GenericEnvelope implements SerializableEntity { + requestHash?: Buffer; + requestHashType?: BigNumber; + + static VERSION_CURRENT = new BN(1, 10); + static VERSION_FIRSTVALID = new BN(1, 10); + static VERSION_LASTVALID = new BN(1, 10); + + static BASE_FLAGS = GenericEnvelope.BASE_FLAGS; + static FLAG_SIGNED = GenericEnvelope.FLAG_SIGNED; + static FLAG_HAS_CREATED_AT = GenericEnvelope.FLAG_HAS_CREATED_AT; + static FLAG_MULTI_DETAILS = GenericEnvelope.FLAG_MULTI_DETAILS; + static FLAG_IS_TESTNET = GenericEnvelope.FLAG_IS_TESTNET; + static FLAG_HAS_SALT = GenericEnvelope.FLAG_HAS_SALT; + static FLAG_HAS_APP_OR_DELEGATED_ID = GenericEnvelope.FLAG_HAS_APP_OR_DELEGATED_ID; + static FLAG_HAS_REQUEST_HASH = new BN(128, 10); + + constructor( + envelope: GenericResponseInterface = { + details: [], + flags: GenericResponse.BASE_FLAGS + } + ) { + super(envelope) + + this.requestHash = envelope.requestHash; + + this.setFlags(); + + this.requestHashType = envelope.requestHashType; + + if (this.requestHashType == null && this.hasRequestHash()) { + this.requestHashType = new BN(EHashTypes.HASH_SHA256) + } + } + + hasRequestHash() { + return !!(this.flags.and(GenericResponse.FLAG_HAS_REQUEST_HASH).toNumber()); + } + + setHasRequestHash() { + this.flags = this.flags.or(GenericResponse.FLAG_HAS_REQUEST_HASH); + } + + setFlags() { + super.setFlags(); + + if (this.requestHash) this.setHasRequestHash(); + } + + getByteLengthOptionalSig(includeSig = true): number { + let length = super.getByteLengthOptionalSig(includeSig); + + if (this.hasRequestHash()) { + const hashLen = this.requestHash.length; + + length += varuint.encodingLength(this.requestHashType.toNumber()); + + length += varuint.encodingLength(this.requestHash.length); + length += hashLen; + } + + return length; + } + + protected toBufferOptionalSig(includeSig = true) { + const writer = new bufferutils.BufferWriter( + Buffer.alloc(this.getByteLengthOptionalSig(includeSig)) + ); + + const superBuf = super.toBufferOptionalSig(includeSig); + + writer.writeSlice(superBuf); + + if (this.hasRequestHash()) { + writer.writeCompactSize(this.requestHashType.toNumber()); + writer.writeVarSlice(this.requestHash); + } + + return writer.buffer; + } + + fromBuffer(buffer: Buffer, offset?: number): number { + if (buffer.length == 0) throw new Error("Cannot create response from empty buffer"); + + const reader = new bufferutils.BufferReader(buffer, offset); + + reader.offset = super.fromBuffer(reader.buffer, reader.offset); + + if (this.hasRequestHash()) { + this.requestHashType = new BN(reader.readCompactSize()); + this.requestHash = reader.readVarSlice(); + } + + return reader.offset; + } + + toJson(): GenericResponseJson { + const parentJson = super.toJson(); + + if (this.hasRequestHash()) { + parentJson["requesthash"] = this.requestHash.toString('hex'); + parentJson["requesthashtype"] = this.requestHashType.toNumber(); + } + + return parentJson; + } +} \ No newline at end of file diff --git a/src/vdxf/index.ts b/src/vdxf/index.ts index f21c4be3..326da8e0 100644 --- a/src/vdxf/index.ts +++ b/src/vdxf/index.ts @@ -167,6 +167,13 @@ export class BufferDataVdxfObject extends VDXFObject { vdxfkey: this.vdxfkey, }; } + + static fromJson(json: { data: string; vdxfkey: string }) { + return new BufferDataVdxfObject( + json.data, + json.vdxfkey, + ); + } } export class VDXFData extends VDXFObject { diff --git a/src/vdxf/keys.ts b/src/vdxf/keys.ts index 5b2e9954..70529e12 100644 --- a/src/vdxf/keys.ts +++ b/src/vdxf/keys.ts @@ -13,6 +13,7 @@ export interface VDXFKeyInterface { export const VERUSPAY_INVOICE_VDXF_KEY: VDXFKeyInterface = { hash160result: "628efc28c2e2d40050e1a9de7a93e7ddf2aa0076", + indexid: "xK4aRumetZg2ecW4Z45qdDBH769xxnaiEH", qualifiedname: { name: "veruspay.vrsc::invoice", namespace: "iAisVse7piEiE2VsixZx4SARyHzSpxYxgq" @@ -20,6 +21,46 @@ export const VERUSPAY_INVOICE_VDXF_KEY: VDXFKeyInterface = { vdxfid: "iEETy7La3FTN2Sd2hNRgepek5S8x8eeUeQ" } +export const VERUSPAY_INVOICE_DETAILS_VDXF_KEY: VDXFKeyInterface = { + "hash160result": "743a23f19531686d70b26a2e220b50a9c70d78a3", + "indexid": "xPCyrdbnb89NftNSuPaVFENwzGDmAukVbS", + "qualifiedname": { + "name": "veruspay.vrsc::invoice.details", + "namespace": "iAisVse7piEiE2VsixZx4SARyHzSpxYxgq" + }, + "vdxfid": "iJNsPqAhjovi3iVR3hvLGqrQxcCkHq9n9H" +} + +export const GENERIC_ENVELOPE_DEEPLINK_VDXF_KEY: VDXFKeyInterface = { + "hash160result": "bc05c4263031cc791296fa8bd15553ccef3de4ba", + "indexid": "xRLq15vpenCUGVpmZgqEtoygZW2b32oVgX", + "qualifiedname": { + "name": "vrsc::envelope.generic", + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV" + }, + "vdxfid": "iLWiYHVjoTyoeKwji1B5vRT9Xr1aA9yyvX" +} + +export const GENERIC_REQUEST_DEEPLINK_VDXF_KEY: VDXFKeyInterface = { + "hash160result": "bc05c4263031cc791296fa8bd15553ccef3de4ba", + "indexid": "xRLq15vpenCUGVpmZgqEtoygZW2b32oVgX", + "qualifiedname": { + "name": "vrsc::request.generic", + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV" + }, + "vdxfid": "iLWiYHVjoTyoeKwji1B5vRT9Xr1aA9yyvX" +} + +export const GENERIC_RESPONSE_DEEPLINK_VDXF_KEY: VDXFKeyInterface = { + "hash160result": "4eb641e76ca30947a0782a7c9b5d79e934300340", + "indexid": "xE96xgWEcUhxTuVAMr4TvW7mGpR5c2SFy4", + "qualifiedname": { + "name": "vrsc::response.generic", + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV" + }, + "vdxfid": "i9JzVt59mAVHqjc8WAQJx7bEFAQ4ffuhrC" +} + export const IDENTITY_UPDATE_REQUEST_VDXF_KEY: VDXFKeyInterface = { "hash160result": "0bcef8b06c211828d16dc038e4d34d097aeb64e4", "indexid": "xV8GreW8nt1Py99r8KPsLxDyy6UYJQvXja", @@ -34,8 +75,8 @@ export const IDENTITY_UPDATE_RESPONSE_VDXF_KEY: VDXFKeyInterface = { "hash160result": "667802c74fbf3dd3a9693bb9aec9bef1250b2b14", "indexid": "xA9GyS1bt1WGERamNVqVrhuGvGJeYuWyNk", "qualifiedname": { - "name": "vrsc::identity.update.response", - "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV" + "name": "vrsc::identity.update.response", + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV" }, "vdxfid": "i5KAWdaX2hHbcFhjWpBLtKNjtcHdeQFjuX" }; @@ -101,6 +142,7 @@ export const WALLET_VDXF_KEY: VDXFKeyInterface = { namespace: "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV", name: "vrsc::applications.wallet", }, + indexid: "xA91QPpBrHZto92NCU5KEjCqRveS4dAPrf" }; export const LOGIN_CONSENT_REDIRECT_VDXF_KEY: VDXFKeyInterface = { @@ -130,7 +172,7 @@ export const LOGIN_CONSENT_ATTESTATION_WEBHOOK_VDXF_KEY: VDXFKeyInterface = { }, }; -export const LOGIN_CONSENT_PERSONALINFO_WEBHOOK_VDXF_KEY: VDXFKeyInterface ={ +export const LOGIN_CONSENT_PERSONALINFO_WEBHOOK_VDXF_KEY: VDXFKeyInterface = { vdxfid: "i8RW9fcZHh1oaAqR2fWWLCB99mfNW6Q2mQ", indexid: "xDFccU3e91EUCLiStMAfJahgBRgPHfYq74", hash160result: "fe40712687cd6f9f288e535ced75b653624f4636", @@ -375,11 +417,11 @@ export const SIGNED_SESSION_OBJECT: VDXFKeyInterface = { }; export const CURRENCY_ADDRESS: VDXFKeyInterface = { - "vdxfid":"iBy2s9cQL9RadMVPjog6bbSV5ityBxTuNR", - "hash160result":"4fb4c86b8ce18e596e28f62bc9a78f43d738255d", + "vdxfid": "iBy2s9cQL9RadMVPjog6bbSV5ityBxTuNR", + "hash160result": "4fb4c86b8ce18e596e28f62bc9a78f43d738255d", "qualifiedname": { - "namespace":"i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV", - "name":"vrsc::currency.address" + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV", + "name": "vrsc::currency.address" } } @@ -522,12 +564,12 @@ export const IDENTITY_SIGNDATA_REQUEST: VDXFKeyInterface = { // DATA TYPES export const DATA_TYPE_STRING: VDXFKeyInterface = { - "vdxfid": "iK7a5JNJnbeuYWVHCDRpJosj3irGJ5Qa8c", - "hash160result": "e5c061641228a399169211e666de18448b7b8bab", - "qualifiedname": { - "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV", - "name": "vrsc::data.type.string" - }, + "vdxfid": "iK7a5JNJnbeuYWVHCDRpJosj3irGJ5Qa8c", + "hash160result": "e5c061641228a399169211e666de18448b7b8bab", + "qualifiedname": { + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV", + "name": "vrsc::data.type.string" + }, }; export const DATA_TYPE_DEFINEDKEY: VDXFKeyInterface = { @@ -647,4 +689,94 @@ export const PROOFS_CONTROLLER_BLUESKY: VDXFKeyInterface = { namespace: "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV", name: "vrsc::system.proofs.controller.bluesky" } -}; \ No newline at end of file +}; + +export const ATTESTATION_VIEW_REQUEST_MULTIPLEATTESTATIONS: VDXFKeyInterface = { + "vdxfid": "i4BWC5Lr7gAT7KzyDx82Ye5DeFQD8ckcXe", + "indexid": "x91cesmvxzP7jVt15dnBX2bkfuRDya9TPq", + "hash160result": "3c520f0bde6be181461ebbff11bce396a604c007", + "qualifiedname": { + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV", + "name": "vrsc::attestation.view.request.multipleattestations" + } +} + +export const AUTHENTICATION_REQUEST_VDXF_KEY: VDXFKeyInterface = { + "hash160result": "d989dfa450a2bcd597fff2409a62c00640644cba", + "indexid": "xRHh6LdgnyNjv5vhoUYbdPaDE5b1Asnykb", + "qualifiedname": { + "name": "vrsc::identity.authentication.request", + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV" + }, + "vdxfid": "iLTadYCbwfA5Hv3fwntSf13gCRZzF8Qedv" +} + +export const AUTHENTICATION_RESPONSE_VDXF_KEY: VDXFKeyInterface = { + "hash160result": "70db17c46d4aebbf0023ac0e23dd3d85c196eee8", + "indexid": "xVYGUq1veNvX7bQMPkysn77RwfXbLcjhnJ", + "qualifiedname": { + "name": "vrsc::identity.authentication.response", + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV" + }, + "vdxfid": "iQiA22aqo4hrVRXKY5Kioiatv1WaSL2EEw" +} + +export const PROVISION_IDENTITY_DETAILS_VDXF_KEY: VDXFKeyInterface = { + "hash160result": "1ed843dce0f4d9a2bbb839994e3927807eb1878c", + "indexid": "xM7h3sXBovFXuwGQ3wvK2ibtUmMHn3mYkM", + "qualifiedname": { + "name": "vrsc::identity.provision.details", + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV" + }, + "vdxfid": "iGHab566xc2sHmPNCGGA4L5MT7LGoJzmCa" +} + +export const APP_ENCRYPTION_REQUEST_VDXF_KEY: VDXFKeyInterface = { + "vdxfid": "iL5nfPuV8Ekiz1EeW5KE3pXHuUTfQf6QC9", + "indexid": "xQuu8CLZyYyPcB7gMkyP2D3pw8UgHevmcM", + "hash160result": "5f398b165b8ea8c547b5f473f951178fc5482db6", + "qualifiedname": { + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV", + "name": "application.encryption.request" + } +} + +export const DATA_RESPONSE_VDXF_KEY: VDXFKeyInterface = { + "vdxfid": "i5L8SNcCqY68X3KZEPgJEjGxY2zvMPzutN", + "indexid": "xAAEuB3HgrJo9DCb65LTD7oVZh1wAjCfTC", + "hash160result": "47ecd4c56c93486380a1ec0d06e186ae8cba5914", + "qualifiedname": { + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV", + "name": "vrsc::generic.data.packet.response" + } +} + +export const USER_DATA_REQUEST_VDXF_KEY: VDXFKeyInterface = { + "vdxfid": "iC7kqU8mfKtqe2gcE2qpuyN4CEcPFTxKGL", + "indexid": "xGwsJGZrWe7WGCZe5iVytMtbDtdQCPvmno", + "hash160result": "d1fba3d9bf18a5293ff912374fc64725db95cb5e", + "qualifiedname": { + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV", + "name": "user.data.request" + } +} + +export const USER_SPECIFIC_DATA_PACKET_VDXF_KEY: VDXFKeyInterface = { + "vdxfid": "i6JYTdVNLz4Sb6515B73BSX6C1Xba63tNQ", + "indexid": "xB8evRvTCJH7DFx2vrmC9q3dDfYcXW1F15", + "hash160result": "34dfdf234ec37a8451790a19538dbd162913051f", + "qualifiedname": { + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV", + "name": "user.data.packet.details" + } +} + +export const APP_ENCRYPTION_RESPONSE_VDXF_KEY: VDXFKeyInterface = { + "vdxfid": "iLgnRLninDtMa7f7EbH7zsDqHRknC4CUpB", + "indexid": "xRWtt9DodY72CHY96GwGyFkNK5mo1n7Jxe", + "hash160result": "0d3c42aec1d154f1678e0585e557e75202a4cbbc", + "qualifiedname": { + "namespace": "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV", + "name": "application.encryption.response" + } +} \ No newline at end of file