@test-org122/hypernet-core
Version:
Hypernet Core. Represents the SDK for running the Hypernet Protocol.
361 lines • 17.8 kB
JavaScript
"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