UNPKG

@test-org122/hypernet-core

Version:

Hypernet Core. Represents the SDK for running the Hypernet Protocol.

361 lines 17.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.VectorUtils = void 0; const vector_types_1 = require("@connext/vector-types"); const objects_1 = require("@interfaces/objects"); const types_1 = require("@interfaces/types"); require("reflect-metadata"); const class_transformer_1 = require("class-transformer"); const identifiers_1 = require("@connext/vector-utils/dist/identifiers"); const utils_1 = require("ethers/lib/utils"); const errors_1 = require("@interfaces/objects/errors"); const neverthrow_1 = require("neverthrow"); const utils_2 = require("@test-org122/utils"); const EMessageTransferType_1 = require("@interfaces/types/EMessageTransferType"); /** * VectorUtils contains methods for interacting directly with the core Vector stuff - * creating transfers, resolving them, & dealing the with router channel. */ class VectorUtils { constructor(configProvider, contextProvider, browserNodeProvider, blockchainProvider, paymentIdUtils, logUtils, timeUtils) { this.configProvider = configProvider; this.contextProvider = contextProvider; this.browserNodeProvider = browserNodeProvider; this.blockchainProvider = blockchainProvider; this.paymentIdUtils = paymentIdUtils; this.logUtils = logUtils; this.timeUtils = timeUtils; this.getRouterChannelAddressSetup = null; } /** * Resolves a message/offer/null transfer with Vector. * @param transferId the ID of the transfer to resolve */ resolveMessageTransfer(transferId) { let channelAddress; let browserNode; return utils_2.ResultUtils.combine([this.browserNodeProvider.getBrowserNode(), this.getRouterChannelAddress()]).andThen(() => { return browserNode.resolveTransfer(channelAddress, transferId, { message: "" }); }); } /** * Resolves a parameterized payment transfer with Vector. * @param transferId the ID of the transfer to resolve */ resolvePaymentTransfer(transferId, paymentId, amount) { const resolverData = { UUID: paymentId, paymentAmountTaken: amount, }; let channelAddress; let browserNode; return utils_2.ResultUtils.combine([this.browserNodeProvider.getBrowserNode(), this.getRouterChannelAddress()]) .andThen((vals) => { const [browserNodeVal, channelAddressVal] = vals; browserNode = browserNodeVal; channelAddress = channelAddressVal; const resolverDataEncoding = ["tuple(bytes32 UUID, uint256 paymentAmountTaken)"]; const encodedResolverData = utils_1.defaultAbiCoder.encode(resolverDataEncoding, [resolverData]); const hashedResolverData = utils_1.keccak256(encodedResolverData); return browserNode.signUtilityMessage(hashedResolverData); }) .andThen((signature) => { const resolver = { data: resolverData, payeeSignature: signature, }; return browserNode.resolveTransfer(channelAddress, transferId, resolver); }); } /** * Resolves an insurance transfer with Vector. * @param transferId the ID of the tarnsfer to resolve */ resolveInsuranceTransfer(transferId, paymentId, mediatorSignature, amount) { // If you do not provide an actual amount, then it resolves for nothing if (amount == null) { amount = objects_1.BigNumber.from(0); } const resolverData = { amount: amount.toString(), UUID: paymentId, }; let channelAddress; let browserNode; return utils_2.ResultUtils.combine([this.browserNodeProvider.getBrowserNode(), this.getRouterChannelAddress()]) .andThen((vals) => { const [browserNodeVal, channelAddressVal] = vals; browserNode = browserNodeVal; channelAddress = channelAddressVal; if (mediatorSignature == null) { const resolverDataEncoding = ["tuple(uint256 amount, bytes32 UUID)"]; const encodedResolverData = utils_1.defaultAbiCoder.encode(resolverDataEncoding, [resolverData]); const hashedResolverData = utils_1.keccak256(encodedResolverData); return browserNode.signUtilityMessage(hashedResolverData); } return neverthrow_1.okAsync(mediatorSignature); }) .andThen((signature) => { const resolver = { data: resolverData, signature: signature, }; return browserNode.resolveTransfer(channelAddress, transferId, resolver); }); } /** * Creates a "Message" transfer with Vector, to notify the other party of a pull payment * @param toAddress the public identifier (not eth address!) of the intended recipient * @param message the message to send as IHypernetOfferDetails */ createPullNotificationTransfer(toAddress, message) { // The message type has to be PULLPAYMENT message.messageType = EMessageTransferType_1.EMessageTransferType.PULLPAYMENT; // Sanity check - make sure the paymentId is valid: const validPayment = this.paymentIdUtils.isValidPaymentId(message.paymentId); if (validPayment.isErr()) { return neverthrow_1.errAsync(validPayment.error); } else { if (!validPayment.value) { return neverthrow_1.errAsync(new errors_1.InvalidParametersError(`CreatePullNotificationTransfer: Invalid paymentId: '${message.paymentId}'`)); } } const prerequisites = utils_2.ResultUtils.combine([ this.configProvider.getConfig(), this.getRouterChannelAddress(), this.browserNodeProvider.getBrowserNode(), ]); return prerequisites.andThen((vals) => { const [config, channelAddress, browserNode] = vals; const initialState = { message: class_transformer_1.serialize(message), }; return browserNode.conditionalTransfer(channelAddress, "0", config.hypertokenAddress, "MessageTransfer", initialState, toAddress, undefined, // CRITICAL- must be undefined undefined, undefined, message); }); } /** * Creates a "Message" transfer with Vector, to notify the other party of a payment creation * @param toAddress the public identifier (not eth address!) of the intended recipient * @param message the message to send as IHypernetOfferDetails */ createOfferTransfer(toAddress, message) { // The message type has to be OFFER message.messageType = EMessageTransferType_1.EMessageTransferType.OFFER; // Sanity check - make sure the paymentId is valid: const validPayment = this.paymentIdUtils.isValidPaymentId(message.paymentId); if (validPayment.isErr()) { return neverthrow_1.errAsync(validPayment.error); } else { if (!validPayment.value) { return neverthrow_1.errAsync(new errors_1.InvalidParametersError(`CreateOfferTransfer: Invalid paymentId: '${message.paymentId}'`)); } } return utils_2.ResultUtils.combine([this.getRouterChannelAddress(), this.browserNodeProvider.getBrowserNode()]).andThen((vals) => { const [channelAddress, browserNode] = vals; const initialState = { message: class_transformer_1.serialize(message), }; return browserNode.conditionalTransfer(channelAddress, "0", message.paymentToken, // The offer is always for 0, so we will make the asset ID in the payment token type, because why not? "MessageTransfer", initialState, toAddress, undefined, // CRITICAL- must be undefined undefined, undefined, message); }); } /** * Creates a "Parameterized" transfer with Vector. * @param type "PUSH" or "PULL" * @param toAddress the public identifier of the intended recipient of this transfer * @param amount the amount of tokens to commit to this transfer * @param assetAddress the address of the ERC20-token to transfer; zero-address for ETH * @param paymentId length-64 hexadecimal string; this becomes the UUID component of the InsuranceState * @param start the start time of this transfer (UNIX timestamp) * @param expiration the expiration time of this transfer (UNIX timestamp) * @param rate the maximum allowed rate of this transfer (deltaAmount/deltaTime) */ createPaymentTransfer(type, toAddress, amount, assetAddress, paymentId, start, expiration, deltaTime, deltaAmount) { // Sanity check if (type === types_1.EPaymentType.Pull && deltaTime === undefined) { this.logUtils.error("Must provide deltaTime for Pull payments"); return neverthrow_1.errAsync(new errors_1.InvalidParametersError("Must provide deltaTime for Pull payments")); } if (type === types_1.EPaymentType.Pull && deltaAmount === undefined) { this.logUtils.error("Must provide deltaAmount for Pull payments"); return neverthrow_1.errAsync(new errors_1.InvalidParametersError("Must provide deltaAmount for Pull payments")); } if (amount.isZero()) { this.logUtils.error("Amount cannot be zero."); return neverthrow_1.errAsync(new errors_1.InvalidParametersError("Amount cannot be zero.")); } // Make sure the paymentId is valid: const validPayment = this.paymentIdUtils.isValidPaymentId(paymentId); if (validPayment.isErr()) { this.logUtils.error(validPayment.error); return neverthrow_1.errAsync(validPayment.error); } else { if (!validPayment.value) { this.logUtils.error(`CreatePaymentTransfer: Invalid paymentId: '${paymentId}'`); return neverthrow_1.errAsync(new errors_1.InvalidParametersError(`CreatePaymentTransfer: Invalid paymentId: '${paymentId}'`)); } } const prerequisites = utils_2.ResultUtils.combine([ this.getRouterChannelAddress(), this.browserNodeProvider.getBrowserNode(), ]); return prerequisites.andThen((vals) => { const [channelAddress, browserNode] = vals; const toEthAddress = identifiers_1.getSignerAddressFromPublicIdentifier(toAddress); // @todo toEthAddress isn't really an eth address, it's the internal signing key // therefore we need to actually do the signing of the payment transfer (on resolve) // with this internal key! const infiniteRate = { deltaAmount: amount.toString(), deltaTime: "1", }; let ourRate; // Have to throw this error, or the ourRate object below will complain that one // of the params is possibly undefined. if (type == types_1.EPaymentType.Pull) { if (deltaTime == null || deltaAmount == null) { this.logUtils.error("Somehow, deltaTime or deltaAmount were not set!"); return neverthrow_1.errAsync(new errors_1.InvalidParametersError("Somehow, deltaTime or deltaAmount were not set!")); } if (deltaTime == 0 || deltaAmount == "0") { this.logUtils.error("deltatime & deltaAmount cannot be zero!"); return neverthrow_1.errAsync(new errors_1.InvalidParametersError("deltatime & deltaAmount cannot be zero!")); } ourRate = { deltaTime: deltaTime === null || deltaTime === void 0 ? void 0 : deltaTime.toString(), deltaAmount: deltaAmount === null || deltaAmount === void 0 ? void 0 : deltaAmount.toString(), }; } else { ourRate = infiniteRate; } const initialState = { receiver: toEthAddress, start: start.toString(), expiration: expiration.toString(), UUID: paymentId, rate: ourRate, }; return browserNode.conditionalTransfer(channelAddress, amount.toString(), assetAddress, "Parameterized", initialState, toAddress, undefined, undefined, undefined, {}); }); } /** * Creates the actual Insurance transfer with Vector * @param toAddress the publicIdentifier of the person to send the transfer to * @param mediatorAddress the Ethereum address of the mediator * @param amount the amount of the token to commit into the InsuranceTransfer * @param expiration the expiration date of this InsuranceTransfer * @param paymentId a length-64 hexadecimal string; this becomes the UUID component of the InsuranceState */ createInsuranceTransfer(toAddress, mediatorPublicKey, amount, expiration, paymentId) { // Sanity check - make sure the paymentId is valid: const validPayment = this.paymentIdUtils.isValidPaymentId(paymentId); if (validPayment.isErr()) { return neverthrow_1.errAsync(validPayment.error); } else { if (!validPayment.value) { return neverthrow_1.errAsync(new errors_1.InvalidParametersError(`CreateInsuranceTransfer: Invalid paymentId: '${paymentId}'`)); } } const prerequisites = utils_2.ResultUtils.combine([ this.configProvider.getConfig(), this.getRouterChannelAddress(), this.browserNodeProvider.getBrowserNode(), ]); return prerequisites.andThen((vals) => { const [config, channelAddress, browserNode] = vals; const toEthAddress = identifiers_1.getSignerAddressFromPublicIdentifier(toAddress); const initialState = { receiver: toEthAddress, mediator: mediatorPublicKey, collateral: amount.toString(), expiration: expiration.toString(), UUID: paymentId, }; return browserNode.conditionalTransfer(channelAddress, amount.toString(), config.hypertokenAddress, "Insurance", initialState, toAddress, undefined, undefined, undefined, {}); }); } /** * Returns the address of the channel with the router, if exists. * Otherwise, attempts to create a channel with the router & return the address. */ getRouterChannelAddress() { // If we already have the address, no need to do the rest if (this.getRouterChannelAddressSetup != null) { return this.getRouterChannelAddressSetup; } let config; let context; let browserNode; this.getRouterChannelAddressSetup = utils_2.ResultUtils.combine([ this.configProvider.getConfig(), this.contextProvider.getInitializedContext(), this.browserNodeProvider.getBrowserNode(), ]) .andThen((vals) => { [config, context, browserNode] = vals; this.logUtils.log(`Core publicIdentifier: ${context.publicIdentifier}`); this.logUtils.log(`Router publicIdentifier: ${config.routerPublicIdentifier}`); return browserNode.getStateChannels(); }) .andThen((channelAddresses) => { const channelResults = new Array(); for (const channelAddress of channelAddresses) { channelResults.push(this._getStateChannel(channelAddress, browserNode)); } return utils_2.ResultUtils.combine(channelResults); }) .andThen((channels) => { for (const channel of channels) { if (!channel) { continue; } if (channel.aliceIdentifier !== config.routerPublicIdentifier) { continue; } return neverthrow_1.okAsync(channel.channelAddress); } // If a channel does not exist with the router, we need to create it. return this._createRouterStateChannel(browserNode, config).map((routerChannel) => { return routerChannel.channelAddress; }); }); return this.getRouterChannelAddressSetup; } getTimestampFromTransfer(transfer) { if (transfer.meta == null) { // We need to figure out the transfer type, I think; but for now we'll just say // that the transfer is right now return this.timeUtils.getUnixNow(); } return transfer.meta.creationDate; } getTransferStateFromTransfer(transfer) { // if (transfer.inDispute) { // return ETransferState.Challenged; // } if (transfer.transferResolver != null) { return types_1.ETransferState.Resolved; } return types_1.ETransferState.Active; } _createRouterStateChannel(browserNode, config) { return browserNode.setup(config.routerPublicIdentifier, config.chainId, vector_types_1.DEFAULT_CHANNEL_TIMEOUT.toString()); } _getStateChannel(channelAddress, browserNode) { return browserNode.getStateChannel(channelAddress).andThen((channel) => { if (channel == null) { return neverthrow_1.errAsync(new errors_1.RouterChannelUnknownError()); } return neverthrow_1.okAsync(channel); }); } } exports.VectorUtils = VectorUtils; //# sourceMappingURL=VectorUtils.js.map