raiden-ts
Version:
Raiden Light Client Typescript/Javascript SDK
73 lines • 5.11 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.channelOpenEpic = void 0;
const constants_1 = require("@ethersproject/constants");
const constant_1 = __importDefault(require("lodash/constant"));
const isEqual_1 = __importDefault(require("lodash/isEqual"));
const rxjs_1 = require("rxjs");
const operators_1 = require("rxjs/operators");
const config_1 = require("../../config");
const actions_1 = require("../../utils/actions");
const error_1 = require("../../utils/error");
const ethers_1 = require("../../utils/ethers");
const rx_1 = require("../../utils/rx");
const actions_2 = require("../actions");
const utils_1 = require("../utils");
// check if contract supports `openChannelWithDeposit`, emit actions and catch error if needed
function openChannel$(action$, request, deps) {
const { address, getTokenNetworkContract, log, config$ } = deps;
const tokenNetworkContract = getTokenNetworkContract(request.meta.tokenNetwork);
return (0, ethers_1.checkContractHasMethod$)(tokenNetworkContract, 'openChannelWithDeposit').pipe((0, operators_1.catchError)((0, constant_1.default)((0, rxjs_1.of)(false))), (0, operators_1.mergeMap)((hasWithDepositMethod) => {
let open$;
if (request.payload.deposit?.gt(0) && hasWithDepositMethod) {
// if contract supports `openChannelWithDeposit`; ensureApprovedBalance$ is performed by
// parallel channelDeposit.request
open$ = (0, utils_1.transact)(tokenNetworkContract, 'openChannelWithDeposit', [address, request.meta.partner, request.payload.deposit], deps, { subkey: null, error: error_1.ErrorCodes.CNL_OPENCHANNEL_FAILED });
}
else {
// if contract doesn't support `openChannelWithDeposit` or deposit isn't needed
open$ = (0, utils_1.transact)(tokenNetworkContract, 'openChannel', [address, request.meta.partner], deps, { subkey: null, error: error_1.ErrorCodes.CNL_OPENCHANNEL_FAILED });
}
return open$.pipe((0, rx_1.retryWhile)((0, config_1.intervalFromConfig)(config$), {
onErrors: error_1.commonAndFailTxErrors,
log: log.info,
}),
// if channel gets opened while retrying (e.g. by partner), give up retry
(0, operators_1.takeUntil)(action$.pipe((0, operators_1.filter)(actions_2.channelOpen.success.is), (0, operators_1.filter)((a) => (0, isEqual_1.default)(a.meta, request.meta)))), (0, operators_1.concatWith)(action$.pipe((0, operators_1.first)((0, actions_1.isConfirmationResponseOf)(actions_2.channelOpen, request.meta)))), (0, operators_1.ignoreElements)(), (0, operators_1.catchError)((error) => (0, rxjs_1.of)(actions_2.channelOpen.failure(error, request.meta))));
}));
}
/**
* A channelOpen action requested by user
* Needs to be called on a previously monitored tokenNetwork. Calls TokenNetwork.openChannel
* with given parameters. If tx goes through successfuly, stop as channelOpen.success action
* will instead be detected and fired by channelEventsEpic. If anything detectable goes wrong,
* fires a channelOpen.failure action instead
*
* @param action$ - Observable of channelOpen actions
* @param state$ - Observable of RaidenStates
* @param deps - RaidenEpicDeps members
* @returns Observable of channelOpen.failure actions
*/
function channelOpenEpic(action$, state$, deps) {
return action$.pipe((0, operators_1.filter)(actions_2.channelOpen.request.is), (0, operators_1.withLatestFrom)(deps.config$),
// if minimumAllowance is default=big, we can relax the serialization to be per channel,
// instead of per token, as parallel deposits in different channels won't conflict on allowance
(0, operators_1.groupBy)(([{ meta }, { minimumAllowance }]) => minimumAllowance.eq(constants_1.MaxUint256) ? (0, utils_1.channelKey)(meta) : meta.tokenNetwork), (0, operators_1.mergeMap)((grouped$) => grouped$.pipe((0, operators_1.pluck)(0), (0, operators_1.withLatestFrom)(state$), (0, operators_1.mergeMap)(([action, state]) => {
const channelState = state.channels[(0, utils_1.channelKey)(action.meta)]?.state;
// fails if channel already exist
if (channelState)
return (0, rxjs_1.of)(actions_2.channelOpen.failure(new error_1.RaidenError(error_1.ErrorCodes.CNL_INVALID_STATE, { state: channelState }), action.meta));
let deposit$ = rxjs_1.EMPTY;
if (action.payload.deposit?.gt(0))
// we request deposit regardless of method used; if openWithDeposit,
// channelDeposit.request will ensureApprovedBalance$, and give up on the actual
// deposit once the WithDeposit is detected
deposit$ = (0, rxjs_1.of)(actions_2.channelDeposit.request({ totalDeposit: action.payload.deposit, waitOpen: true }, action.meta));
return (0, rxjs_1.merge)(deposit$, openChannel$(action$, action, deps));
}))));
}
exports.channelOpenEpic = channelOpenEpic;
//# sourceMappingURL=open.js.map