@test-org122/hypernet-core
Version:
Hypernet Core. Represents the SDK for running the Hypernet Protocol.
254 lines (246 loc) • 10.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AccountsRepository = void 0;
const objects_1 = require("@interfaces/objects");
const ethers_1 = require("ethers");
const neverthrow_1 = require("neverthrow");
const utils_1 = require("@test-org122/utils");
class AssetInfo {
constructor(assetId, name, symbol, decimals) {
this.assetId = assetId;
this.name = name;
this.symbol = symbol;
this.decimals = decimals;
}
}
/**
* Contains methods for getting Ethereum accounts, public identifiers,
* balances for accounts, and depositing & withdrawing assets.
*/
class AccountsRepository {
constructor(blockchainProvider, vectorUtils, browserNodeProvider, logUtils, blockchainUtils) {
this.blockchainProvider = blockchainProvider;
this.vectorUtils = vectorUtils;
this.browserNodeProvider = browserNodeProvider;
this.logUtils = logUtils;
this.blockchainUtils = blockchainUtils;
// We will cache the info about each asset type, so we only have to look it up once.
this.assetInfo = new Map();
// Add a default entry for Ethereum, it's not an ERC20, it's special and it's also universal.
this.assetInfo.set(ethers_1.constants.AddressZero, new AssetInfo(ethers_1.constants.AddressZero, "Ethereum", "ETH", 18));
}
/**
* Get the current public identifier for this instance.
*/
getPublicIdentifier() {
return this.browserNodeProvider.getBrowserNode().map((browserNode) => {
return browserNode.publicIdentifier;
});
}
/**
* Get the Ethereum accounts associated with this instance.
*/
getAccounts() {
return this.blockchainProvider.getProvider().andThen((provider) => {
return objects_1.ResultAsync.fromPromise(provider.listAccounts(), (e) => {
return e;
});
});
}
/**
* Get all balances associated with this instance.
*/
getBalances() {
return this.vectorUtils.getRouterChannelAddress().andThen((channelAddress) => {
return this.browserNodeProvider
.getBrowserNode()
.andThen((browserNode) => {
return browserNode.getStateChannel(channelAddress);
})
.andThen((channelState) => {
const assetBalanceResults = new Array();
if (channelState == null) {
return neverthrow_1.combine(assetBalanceResults);
}
for (let i = 0; i < channelState.assetIds.length; i++) {
const assetBalanceResult = this._getAssetBalance(i, channelState);
assetBalanceResults.push(assetBalanceResult);
}
return neverthrow_1.combine(assetBalanceResults);
})
.map((assetBalances) => {
return new objects_1.Balances(assetBalances);
});
});
}
/**
* Get balance for a particular asset for this instance
* @param assetAddress the (Ethereum) address of the token to get the balance of
*/
getBalanceByAsset(assetAddress) {
return this.getBalances().andThen((balances) => {
for (const assetBalance of balances.assets) {
if (assetBalance.assetAddresss === assetAddress) {
// The user has a balance of the selected asset type, so we have an asset balance
// to give back.
return neverthrow_1.okAsync(assetBalance);
}
}
// The user does not have a balance in the existing asset. The only problem here
// is that we still would like to return a proper name for the asset.
return this._getAssetInfo(assetAddress).map((assetInfo) => {
return new objects_1.AssetBalance(assetAddress, assetInfo.name, assetInfo.symbol, assetInfo.decimals, objects_1.BigNumber.from(0), objects_1.BigNumber.from(0), objects_1.BigNumber.from(0));
});
});
}
/**
* Deposit funds into this instance of Hypernet Core
* @param assetAddress the (Ethereum) token address to deposit
* @param amount the amount of the token to deposit
*/
depositFunds(assetAddress, amount) {
let signer;
let channelAddress;
let browserNode;
return utils_1.ResultUtils.combine([
this.blockchainProvider.getSigner(),
this.vectorUtils.getRouterChannelAddress(),
this.browserNodeProvider.getBrowserNode(),
])
.andThen((vals) => {
[signer, channelAddress, browserNode] = vals;
let tx;
if (assetAddress === "0x0000000000000000000000000000000000000000") {
this.logUtils.log("Transferring ETH.");
// send eth
tx = objects_1.ResultAsync.fromPromise(signer.sendTransaction({ to: channelAddress, value: amount }), (err) => {
return err;
});
}
else {
this.logUtils.log("Transferring an ERC20 asset.");
// send an actual erc20 token
return this.blockchainUtils.erc20Transfer(assetAddress, channelAddress, amount);
}
return tx;
})
.andThen((tx) => {
// TODO: Wait on this, break it up, this could take a while
return objects_1.ResultAsync.fromPromise(tx.wait(), (e) => e);
})
.andThen(() => {
if (browserNode == null || channelAddress == null) {
return neverthrow_1.errAsync(new Error("Really screwed up!"));
}
return browserNode.reconcileDeposit(assetAddress, channelAddress);
})
.andThen((depositRes) => {
// I can not for the life of me figure out why depositRes is coming back
// as "unknown"
const depositChannelAddress = depositRes;
// Sanity check, the deposit was for the channel we tried to deposit into.
if (depositChannelAddress !== channelAddress) {
return neverthrow_1.errAsync(new Error("Something has gone horribly wrong!"));
}
return neverthrow_1.okAsync(null);
});
}
/**
* Withdraw funds from this instance of Hypernet Core to a specified (Ethereum) destination
* @param assetAddress the token address to withdraw
* @param amount the amount of the token to withdraw
* @param destinationAddress the destination (Ethereum) address to withdraw to
*/
withdrawFunds(assetAddress, amount, destinationAddress) {
const prerequisites = utils_1.ResultUtils.combine([
this.browserNodeProvider.getBrowserNode(),
this.vectorUtils.getRouterChannelAddress(),
]);
return prerequisites
.andThen((vals) => {
const [browserNode, channelAddress] = vals;
return browserNode.withdraw(channelAddress, amount.toString(), assetAddress, destinationAddress, "0");
})
.map(() => {
return;
});
}
/**
* Mint the test token to the provided address
* @param amount the amount of the test token to mint
* @param to the (Ethereum) address to mint the test token to
*/
mintTestToken(amount, to) {
const resp = this.blockchainUtils.mintToken(amount, to);
return resp
.andThen((mintTx) => {
return objects_1.ResultAsync.fromPromise(mintTx.wait(), (e) => {
return e;
});
})
.map(() => {
return;
});
}
_getAssetBalance(i, channelState) {
const assetAddress = channelState.assetIds[i];
return this._getAssetInfo(assetAddress).map((assetInfo) => {
const amount = objects_1.BigNumber.from(channelState.balances[i].amount[1]);
// Return the asset balance
const assetBalance = new objects_1.AssetBalance(assetAddress, assetInfo.name, assetInfo.symbol, assetInfo.decimals, amount, objects_1.BigNumber.from(0), // @todo figure out how to grab the locked amount
amount);
return assetBalance;
});
}
// TODO: fix it, tokenContract.name() not working
_getAssetInfo(assetAddress) {
/* let name: string;
let symbol: string;
let tokenContract: Contract;
// First, check if we have already cached the info about this asset.
const cachedAssetInfo = this.assetInfo.get(assetAddress);
if (cachedAssetInfo == null) {
// No cached info, we'll have to get it
return this.blockchainProvider
.getSigner()
.andThen((signer) => {
tokenContract = new Contract(assetAddress, this.erc20Abi, signer);
return ResultAsync.fromPromise<string | null, BlockchainUnavailableError>(tokenContract.name(), (err) => {
return err as BlockchainUnavailableError;
});
})
.andThen((myName) => {
if (myName == null || myName == "") {
name = `Unknown Token (${assetAddress})`;
} else {
name = myName;
}
return ResultAsync.fromPromise<string | null, BlockchainUnavailableError>(tokenContract.symbol(), (err) => {
return err as BlockchainUnavailableError;
});
})
.andThen((mySymbol) => {
if (mySymbol == null || mySymbol == "") {
symbol = "Unk";
} else {
symbol = mySymbol;
}
return ResultAsync.fromPromise<number | null, BlockchainUnavailableError>(tokenContract.decimals(), (err) => {
return err as BlockchainUnavailableError;
});
})
.map((myDecimals) => {
const decimals = myDecimals ?? 0;
const assetInfo = new AssetInfo(assetAddress, name, symbol, decimals);
// Store the cached info
this.assetInfo.set(assetAddress, assetInfo);
return assetInfo;
});
}
// We have cached info
return okAsync(cachedAssetInfo);*/
return neverthrow_1.okAsync(new AssetInfo(assetAddress, "", "", 0));
}
}
exports.AccountsRepository = AccountsRepository;
//# sourceMappingURL=AccountsRepository.js.map