@superfluid-finance/sdk-core
Version:
SDK Core for building with Superfluid Protocol
232 lines • 11.1 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.clipDepositNumber = exports.getFlowOperatorId = exports.typeGuard = exports.isInjectedEthers = exports.isInjectedWeb3 = exports.isEthersProvider = exports.calculateAvailableBalance = exports.getSanitizedTimestamp = exports.getStringCurrentTimeInSeconds = exports.subscriptionTotalAmountClaimableSinceUpdatedAt = exports.subscriptionTotalAmountReceivedSinceUpdated = exports.subscriptionTotalAmountDistributedSinceUpdated = exports.flowedAmountSinceUpdatedAt = exports.getFlowAmountByPerSecondFlowRate = exports.getPerSecondFlowRateByDay = exports.getPerSecondFlowRateByWeek = exports.getPerSecondFlowRateByMonth = exports.getPerSecondFlowRateByYear = exports.getTransactionDescription = exports.removeSigHashFromCallData = exports.isNullOrEmpty = exports._removePermissions = exports._addPermissions = exports.isPermissionsClean = exports.normalizeAddress = void 0;
exports.toBN = toBN;
exports.tryGet = tryGet;
const ethers_1 = require("ethers");
const SFError_1 = require("./SFError");
const constants_1 = require("./constants");
const EMPTY = "0x";
/**
* Checks if address is a valid ethereum address and normalizes so it can be used by both subgraph and web3.
* @param address
* @returns The normalized address.
*/
const normalizeAddress = (address) => {
if (!address)
return "";
if (ethers_1.ethers.utils.isAddress(address) === false) {
throw new SFError_1.SFError({
type: "INVALID_ADDRESS",
message: "The address you have entered is not a valid ethereum address",
});
}
return address.toLowerCase();
};
exports.normalizeAddress = normalizeAddress;
const isPermissionsClean = (permissions) => {
return ((permissions &
~(constants_1.AUTHORIZE_FLOW_OPERATOR_CREATE |
constants_1.AUTHORIZE_FLOW_OPERATOR_UPDATE |
constants_1.AUTHORIZE_FLOW_OPERATOR_DELETE)) ===
0);
};
exports.isPermissionsClean = isPermissionsClean;
const _addPermissions = (oldPermissions, permissionsDelta) => {
return oldPermissions | permissionsDelta;
};
exports._addPermissions = _addPermissions;
const _removePermissions = (oldPermissions, permissionsDelta) => {
return oldPermissions & ~permissionsDelta;
};
exports._removePermissions = _removePermissions;
const isNullOrEmpty = (str) => {
return str == null || str === "";
};
exports.isNullOrEmpty = isNullOrEmpty;
function toBN(num) {
return ethers_1.ethers.BigNumber.from(num);
}
/**
* Removes the 8-character (4 byte) signature hash from `callData`.
* @param callData
* @returns function parameters
*/
const removeSigHashFromCallData = (callData) => EMPTY.concat(callData.slice(10));
exports.removeSigHashFromCallData = removeSigHashFromCallData;
/**
* A wrapper function for getting the ethers TransactionDescription object given fragments (e.g. ABI), callData and the value amount sent.
* @param fragments ABI
* @param data callData of a function
* @param value amount of ether sent
* @returns ethers.TransactionDescription object
*/
const getTransactionDescription = (fragments, data, value) => {
const iface = new ethers_1.ethers.utils.Interface(fragments);
const txnDescription = iface.parseTransaction({ data, value });
return txnDescription;
};
exports.getTransactionDescription = getTransactionDescription;
/**
* Gets the per second flow rate given an `amountPerYear` value.
* @param amountPerYear the amount you want to stream per year
* @returns flow rate per second
*/
const getPerSecondFlowRateByYear = (amountPerYear) => {
return Math.round((Number(amountPerYear) / constants_1.YEAR_IN_SECONDS) * constants_1.BASE_18).toString();
};
exports.getPerSecondFlowRateByYear = getPerSecondFlowRateByYear;
/**
* Gets the per second flow rate given an `amountPerMonth` value.
* @param amountPerMonth the amount you want to stream per month
* @returns flow rate per second
*/
const getPerSecondFlowRateByMonth = (amountPerMonth) => {
return Math.round((Number(amountPerMonth) / constants_1.MONTH_IN_SECONDS) * constants_1.BASE_18).toString();
};
exports.getPerSecondFlowRateByMonth = getPerSecondFlowRateByMonth;
/**
* Gets the per second flow rate given an `amountPerWeek` value.
* @param amountPerWeek the amount you want to stream per Week
* @returns flow rate per second
*/
const getPerSecondFlowRateByWeek = (amountPerWeek) => {
return Math.round((Number(amountPerWeek) / constants_1.WEEK_IN_SECONDS) * constants_1.BASE_18).toString();
};
exports.getPerSecondFlowRateByWeek = getPerSecondFlowRateByWeek;
/**
* Gets the per second flow rate given an `amountPerDay` value.
* @param amountPerDay the amount you want to stream per day
* @returns flow rate per second
*/
const getPerSecondFlowRateByDay = (amountPerDay) => {
return Math.round((Number(amountPerDay) / constants_1.DAY_IN_SECONDS) * constants_1.BASE_18).toString();
};
exports.getPerSecondFlowRateByDay = getPerSecondFlowRateByDay;
/**
* Gets daily, weekly, monthly and yearly flowed amounts given a per second flow rate.
* @param perSecondFlowRate
* @returns
*/
const getFlowAmountByPerSecondFlowRate = (perSecondFlowRate) => {
const decimalFlowRate = Number(perSecondFlowRate) / constants_1.BASE_18;
return {
daily: Math.round(decimalFlowRate * constants_1.DAY_IN_SECONDS).toString(),
weekly: Math.round(decimalFlowRate * constants_1.WEEK_IN_SECONDS).toString(),
monthly: Math.round(decimalFlowRate * constants_1.MONTH_IN_SECONDS).toString(),
yearly: Math.round(decimalFlowRate * constants_1.YEAR_IN_SECONDS).toString(),
};
};
exports.getFlowAmountByPerSecondFlowRate = getFlowAmountByPerSecondFlowRate;
/**
* The formula for calculating the flowed amount since updated using Subgraph data.
* @param netFlowRate the net flow rate of the user
* @param currentTimestamp the current timestamp
* @param updatedAtTimestamp the updated at timestamp of the `AccountTokenSnapshot` entity
* @returns the flowed amount since the updatedAt timestamp
*/
const flowedAmountSinceUpdatedAt = ({ netFlowRate, currentTimestamp, updatedAtTimestamp, }) => {
return toBN(currentTimestamp)
.sub(toBN(updatedAtTimestamp))
.mul(toBN(netFlowRate));
};
exports.flowedAmountSinceUpdatedAt = flowedAmountSinceUpdatedAt;
/**
* The formula for calculating the total amount distributed to the subscriber (pending or received).
* @param indexSubscriptions the index subscriptions of a single token from an account.
* @returns the total amount received since updated at (both pending and actually distributed)
*/
const subscriptionTotalAmountDistributedSinceUpdated = (indexSubscriptions) => {
return indexSubscriptions.reduce((x, y) => toBN(x)
.add(toBN(y.index.indexValue).sub(toBN(y.indexValueUntilUpdatedAt)))
.mul(toBN(y.units)), toBN(0));
};
exports.subscriptionTotalAmountDistributedSinceUpdated = subscriptionTotalAmountDistributedSinceUpdated;
/**
* The formula for calculating the total amount received (approved subscriptions).
* @param indexSubscriptions the index subscriptions of a single token from an account.
* @returns the total amount received since updated at (actually distributed into wallet)
*/
const subscriptionTotalAmountReceivedSinceUpdated = (indexSubscriptions) => {
return indexSubscriptions
.filter((x) => x.approved)
.reduce((x, y) => toBN(x)
.add(toBN(y.index.indexValue).sub(toBN(y.indexValueUntilUpdatedAt)))
.mul(toBN(y.units)), toBN(0));
};
exports.subscriptionTotalAmountReceivedSinceUpdated = subscriptionTotalAmountReceivedSinceUpdated;
/**
* The formula for calculating the total amount that is claimable.
* @param indexSubscriptions the index subscriptions of a single token from an account.
* @returns the total amount that can be claimed since updated at
*/
const subscriptionTotalAmountClaimableSinceUpdatedAt = (indexSubscriptions) => {
return (0, exports.subscriptionTotalAmountDistributedSinceUpdated)(indexSubscriptions).sub((0, exports.subscriptionTotalAmountReceivedSinceUpdated)(indexSubscriptions));
};
exports.subscriptionTotalAmountClaimableSinceUpdatedAt = subscriptionTotalAmountClaimableSinceUpdatedAt;
const getStringCurrentTimeInSeconds = () => Math.floor(new Date().getTime() / 1000);
exports.getStringCurrentTimeInSeconds = getStringCurrentTimeInSeconds;
const getSanitizedTimestamp = (timestamp) => new Date(Number(timestamp.toString()) * 1000);
exports.getSanitizedTimestamp = getSanitizedTimestamp;
/**
* The formula for calculating the balance until updated at of a user (claimable + received tokens from index)
* @param currentBalance the current balance until updated at from the `AccountTokenSnapshot` entity
* @param netFlowRate the net flow rate of the user
* @param currentTimestamp the current timestamp
* @param updatedAtTimestamp the updated at timestamp of the `AccountTokenSnapshot` entity
* @returns the balance since the updated at timestamp
*/
const calculateAvailableBalance = ({ currentBalance, netFlowRate, currentTimestamp, updatedAtTimestamp, indexSubscriptions, }) => {
return toBN(currentBalance)
.add((0, exports.flowedAmountSinceUpdatedAt)({
netFlowRate,
currentTimestamp,
updatedAtTimestamp,
}))
.add((0, exports.subscriptionTotalAmountReceivedSinceUpdated)(indexSubscriptions));
};
exports.calculateAvailableBalance = calculateAvailableBalance;
// NOTE: This is the only places we are allowed to use explicit any in the
// sdk-core otherwise this doesn't work properly.
const isEthersProvider = (provider) => !!provider.getNetwork;
exports.isEthersProvider = isEthersProvider;
const isInjectedWeb3 = (provider) => !!provider.currentProvider;
exports.isInjectedWeb3 = isInjectedWeb3;
const isInjectedEthers = (provider) => !!provider.provider;
exports.isInjectedEthers = isInjectedEthers;
/**
* Why? Because `return obj as T` and `return <T>obj` are not safe type casts.
*/
const typeGuard = (obj) => obj;
exports.typeGuard = typeGuard;
const getFlowOperatorId = (sender, flowOperator) => {
const encoder = ethers_1.ethers.utils.defaultAbiCoder;
const encodedData = encoder.encode(["string", "address", "address"], ["flowOperator", sender, flowOperator]);
return ethers_1.ethers.utils.keccak256(encodedData);
};
exports.getFlowOperatorId = getFlowOperatorId;
/**
* Applies clipping to deposit (based on contracts clipping logic)
* @param deposit the deposit to clip
* @param roundingDown whether to round up or down
* @returns clipped deposit
*/
const clipDepositNumber = (deposit, roundingDown = false) => {
// last 32 bits of the deposit (96 bits) is clipped off
const rounding = roundingDown
? 0
: deposit.and(toBN(0xffffffff)).isZero()
? 0
: 1;
return deposit.shr(32).add(toBN(rounding)).shl(32);
};
exports.clipDepositNumber = clipDepositNumber;
async function tryGet(somePromise, defaultReturnValue) {
try {
return await somePromise;
}
catch {
return defaultReturnValue;
}
}
//# sourceMappingURL=utils.js.map
;