UNPKG

@superfluid-finance/sdk-core

Version:
481 lines 25.8 kB
import { ethers } from "ethers"; import Host from "./Host"; import { SFError } from "./SFError"; import SuperfluidAgreement from "./SuperfluidAgreement"; import { CFAv1Forwarder__factory, IConstantFlowAgreementV1__factory, } from "./typechain-types"; import { getSanitizedTimestamp, isPermissionsClean, normalizeAddress, } from "./utils"; const cfaInterface = IConstantFlowAgreementV1__factory.createInterface(); /** * Constant Flow Agreement V1 Helper Class * @description A helper class to interact with the CFAV1 contract. */ export default class ConstantFlowAgreementV1 extends SuperfluidAgreement { constructor(hostAddress, cfaV1Address, cfaV1ForwarderAddress) { super(); /** ### CFA Read Functions ### */ /** * Get the details of a flow. * @param superToken the superToken of the agreement * @param sender the sender of the flow * @param receiver the receiver of the flow * @param providerOrSigner a provider or signer object * @returns {Promise<IWeb3FlowInfo>} Web3 Flow info object */ this.getFlow = async (params) => { const normalizedToken = normalizeAddress(params.superToken); const normalizedSender = normalizeAddress(params.sender); const normalizedReceiver = normalizeAddress(params.receiver); try { const flowData = await this.contract .connect(params.providerOrSigner) .getFlow(normalizedToken, normalizedSender, normalizedReceiver); return this._sanitizeFlowInfo(flowData); } catch (err) { throw new SFError({ type: "CFAV1_READ", message: "There was an error getting the flow", cause: err, }); } }; /** * Get the flow info of an account (net flow). * @param superToken the superToken of the agreement * @param account the account we're querying * @param providerOrSigner a provider or signer object * @returns {Promise<IWeb3FlowInfo>} Web3 Flow info object */ this.getAccountFlowInfo = async (params) => { const normalizedToken = normalizeAddress(params.superToken); const normalizedAccount = normalizeAddress(params.account); try { const flowData = await this.contract .connect(params.providerOrSigner) .getAccountFlowInfo(normalizedToken, normalizedAccount); return this._sanitizeFlowInfo(flowData); } catch (err) { throw new SFError({ type: "CFAV1_READ", message: "There was an error getting the account flow information", cause: err, }); } }; /** * Get the net flow of an account. * @param superToken the superToken of the agreement * @param account the account we're querying * @param providerOrSigner a provider or signer object * @returns {Promise<string>} Web3 Flow info object */ this.getNetFlow = async (params) => { const normalizedToken = normalizeAddress(params.superToken); const normalizedAccount = normalizeAddress(params.account); try { return (await this.contract .connect(params.providerOrSigner) .getNetFlow(normalizedToken, normalizedAccount)).toString(); } catch (err) { throw new SFError({ type: "CFAV1_READ", message: "There was an error getting net flow", cause: err, }); } }; /** * Get flow operator data. * @param superToken the superToken of the agreement * @param sender the sender * @param flowOperator the flowOperator * @param providerOrSigner a provider or signer object * @returns {Promise<IWeb3FlowOperatorData>} Web3 Flow info object */ this.getFlowOperatorData = async (params) => { const normalizedToken = normalizeAddress(params.superToken); const normalizedSender = normalizeAddress(params.sender); const normalizedFlowOperator = normalizeAddress(params.flowOperator); try { const flowOperatorData = await this.contract .connect(params.providerOrSigner) .getFlowOperatorData(normalizedToken, normalizedSender, normalizedFlowOperator); return this._sanitizeFlowOperatorData(flowOperatorData); } catch (err) { throw new SFError({ type: "CFAV1_READ", message: "There was an error getting flow operator data", cause: err, }); } }; /** * Get flow operator data using the flowOperatorId. * @param superToken the superToken of the agreement * @param flowOperatorId The keccak256 hash of encoded string "flowOperator", sender and flowOperator * @param providerOrSigner a provider or signer object * @returns {Promise<IWeb3FlowOperatorData>} Web3 Flow info object */ this.getFlowOperatorDataByID = async (params) => { const normalizedToken = normalizeAddress(params.superToken); try { const flowOperatorData = await this.contract .connect(params.providerOrSigner) .getFlowOperatorDataByID(normalizedToken, params.flowOperatorId); return this._sanitizeFlowOperatorData({ ...flowOperatorData, flowOperatorId: params.flowOperatorId, }); } catch (err) { throw new SFError({ type: "CFAV1_READ", message: "There was an error getting flow operator data", cause: err, }); } }; /** ### CFA Write Functions ### */ /** * Create a flow. * @param flowRate The specified flow rate. * @param sender The sender of the flow * @param receiver The receiver of the flow. * @param superToken The token to be flowed. * @param userData Extra user data provided. * @param overrides ethers overrides object for more control over the transaction sent. * @param shouldUseCallAgreement Whether to use callAgreement, or the CFAv1Forwarder * @returns {Operation} An instance of Operation which can be executed or batched. */ this.createFlow = (params) => { const normalizedToken = normalizeAddress(params.superToken); const normalizedReceiver = normalizeAddress(params.receiver); const normalizedSender = normalizeAddress(params.sender); const callData = cfaInterface.encodeFunctionData("createFlow", [ normalizedToken, normalizedReceiver, params.flowRate, "0x", ]); const callAgreementOperation = this.host.callAgreement(this.contract.address, callData, params.userData, params.overrides); const forwarderPopulatedTxnPromise = this.forwarder.populateTransaction.createFlow(normalizedToken, normalizedSender, normalizedReceiver, params.flowRate, params.userData || "0x", params.overrides || {}); return this._getCallAgreementOperation(callAgreementOperation, forwarderPopulatedTxnPromise, params.shouldUseCallAgreement || normalizedSender === ""); }; /** * Update a flow. * @param flowRate The specified flow rate. * @param sender The sender of the flow * @param receiver The receiver of the flow. * @param superToken The token to be flowed. * @param userData Extra user data provided. * @param overrides ethers overrides object for more control over the transaction sent. * @returns {Operation} An instance of Operation which can be executed or batched. */ this.updateFlow = (params) => { const normalizedToken = normalizeAddress(params.superToken); const normalizedReceiver = normalizeAddress(params.receiver); const normalizedSender = normalizeAddress(params.sender); const callData = cfaInterface.encodeFunctionData("updateFlow", [ normalizedToken, normalizedReceiver, params.flowRate, "0x", ]); const callAgreementOperation = this.host.callAgreement(this.contract.address, callData, params.userData, params.overrides); const forwarderPopulatedTxnPromise = this.forwarder.populateTransaction.updateFlow(normalizedToken, normalizedSender, normalizedReceiver, params.flowRate, params.userData || "0x", params.overrides || {}); return this._getCallAgreementOperation(callAgreementOperation, forwarderPopulatedTxnPromise, params.shouldUseCallAgreement || normalizedSender === ""); }; /** * Delete a flow. * @param superToken The token to be flowed. * @param sender The sender of the flow. * @param receiver The receiver of the flow. * @param userData Extra user data provided. * @param overrides ethers overrides object for more control over the transaction sent. * @returns {Operation} An instance of Operation which can be executed or batched. */ this.deleteFlow = (params) => { const normalizedToken = normalizeAddress(params.superToken); const normalizedSender = normalizeAddress(params.sender); const normalizedReceiver = normalizeAddress(params.receiver); const callData = cfaInterface.encodeFunctionData("deleteFlow", [ normalizedToken, normalizedSender, normalizedReceiver, "0x", ]); const callAgreementOperation = this.host.callAgreement(this.contract.address, callData, params.userData, params.overrides); const forwarderPopulatedTxnPromise = this.forwarder.populateTransaction.deleteFlow(normalizedToken, normalizedSender, normalizedReceiver, params.userData || "0x", params.overrides || {}); return this._getCallAgreementOperation(callAgreementOperation, forwarderPopulatedTxnPromise, params.shouldUseCallAgreement || normalizedSender === ""); }; /** * Create a flow as an operator * @param flowRate The specified flow rate. * @param sender The sender of the flow. * @param receiver The receiver of the flow. * @param superToken The token to be flowed. * @param userData Extra user data provided. * @param overrides ethers overrides object for more control over the transaction sent. * @returns {Operation} An instance of Operation which can be executed or batched. */ this.createFlowByOperator = (params) => { const normalizedToken = normalizeAddress(params.superToken); const normalizedReceiver = normalizeAddress(params.receiver); const normalizedSender = normalizeAddress(params.sender); const callData = cfaInterface.encodeFunctionData("createFlowByOperator", [ normalizedToken, normalizedSender, normalizedReceiver, params.flowRate, "0x", ]); const callAgreementOperation = this.host.callAgreement(this.contract.address, callData, params.userData, params.overrides); const createFlowOperation = this.createFlow(params); return this._getCallAgreementOperation(callAgreementOperation, createFlowOperation.forwarderPopulatedPromise, params.shouldUseCallAgreement || normalizedSender === ""); }; /** * Update a flow as an operator. * @param flowRate The specified flow rate. * @param sender The sender of the flow. * @param receiver The receiver of the flow. * @param superToken The token to be flowed. * @param userData Extra user data provided. * @param overrides ethers overrides object for more control over the transaction sent. * @returns {Operation} An instance of Operation which can be executed or batched. */ this.updateFlowByOperator = (params) => { const normalizedToken = normalizeAddress(params.superToken); const normalizedSender = normalizeAddress(params.sender); const normalizedReceiver = normalizeAddress(params.receiver); const callData = cfaInterface.encodeFunctionData("updateFlowByOperator", [ normalizedToken, normalizedSender, normalizedReceiver, params.flowRate, "0x", ]); const callAgreementOperation = this.host.callAgreement(this.contract.address, callData, params.userData, params.overrides); const updateFlowOperation = this.updateFlow(params); return this._getCallAgreementOperation(callAgreementOperation, updateFlowOperation.forwarderPopulatedPromise, params.shouldUseCallAgreement || normalizedSender === ""); }; /** * Delete a flow as an operator. * @param sender The sender of the flow. * @param receiver The receiver of the flow. * @param superToken The token to be flowed. * @param userData Extra user data provided. * @param overrides ethers overrides object for more control over the transaction sent. * @returns {Operation} An instance of Operation which can be executed or batched. */ this.deleteFlowByOperator = (params) => { const normalizedToken = normalizeAddress(params.superToken); const normalizedSender = normalizeAddress(params.sender); const normalizedReceiver = normalizeAddress(params.receiver); const callData = cfaInterface.encodeFunctionData("deleteFlowByOperator", [normalizedToken, normalizedSender, normalizedReceiver, "0x"]); const callAgreementOperation = this.host.callAgreement(this.contract.address, callData, params.userData, params.overrides); const deleteFlowOperation = this.deleteFlow(params); return this._getCallAgreementOperation(callAgreementOperation, deleteFlowOperation.forwarderPopulatedPromise, params.shouldUseCallAgreement || normalizedSender === ""); }; /** ### Internal Helper Functions ### */ /** * Sanitizes flow info, converting BigNumber to string. * @param timestamp last updated timestamp of flow * @param flowRate the current flow rate * @param deposit the deposit amount * @param owedDeposit any owed deposit * @returns {IWeb3FlowInfo} sanitized web3 flow info */ this._sanitizeFlowInfo = (params) => { return { timestamp: getSanitizedTimestamp(params.timestamp), flowRate: params.flowRate.toString(), deposit: params.deposit.toString(), owedDeposit: params.owedDeposit.toString(), }; }; /** * Sanitizes flow operator data, converting BigNumber to string. * @param flowOperatorId The keccak256 hash of encoded string "flowOperator", sender and flowOperator * @param permissions the permissions * @param flowRateAllowance the flow rate allowance granted to the flow operator * @returns {IWeb3FlowOperatorData} sanitized web3 flow info */ this._sanitizeFlowOperatorData = (params) => { return { flowOperatorId: params.flowOperatorId, permissions: params.permissions.toString(), flowRateAllowance: params.flowRateAllowance.toString(), }; }; this.host = new Host(hostAddress); this.contract = new ethers.Contract(cfaV1Address, IConstantFlowAgreementV1__factory.abi); this.forwarder = new ethers.Contract(cfaV1ForwarderAddress, CFAv1Forwarder__factory.abi); } /** ### CFA ACL Write Functions (byOperator) ### */ /** * Increase the flow rate allowance for an ACL operator. * @param superToken The token to be flowed. * @param flowOperator The operator of the flow. * @param flowRateAllowanceDelta The amount to increase the flow rate allowance by. * @param userData Extra user data provided. * @param overrides ethers overrides object for more control over the transaction sent. * @returns {Operation} An instance of Operation which can be executed or batched. */ increaseFlowRateAllowance(params) { const normalizedToken = normalizeAddress(params.superToken); const normalizedFlowOperator = normalizeAddress(params.flowOperator); const callData = cfaInterface.encodeFunctionData("increaseFlowRateAllowance", [ normalizedToken, normalizedFlowOperator, params.flowRateAllowanceDelta, "0x", ]); return this.host.callAgreement(this.contract.address, callData, params.userData, params.overrides); } /** * Decrease the flow rate allowance for an ACL operator. * @param superToken The token to be flowed. * @param flowOperator The operator of the flow. * @param flowRateAllowanceDelta The amount to decrease the flow rate allowance by. * @param userData Extra user data provided. * @param overrides ethers overrides object for more control over the transaction sent. * @returns {Operation} An instance of Operation which can be executed or batched. */ decreaseFlowRateAllowance(params) { const normalizedToken = normalizeAddress(params.superToken); const normalizedFlowOperator = normalizeAddress(params.flowOperator); const callData = cfaInterface.encodeFunctionData("decreaseFlowRateAllowance", [ normalizedToken, normalizedFlowOperator, params.flowRateAllowanceDelta, "0x", ]); return this.host.callAgreement(this.contract.address, callData, params.userData, params.overrides); } /** * Increase the flow rate allowance and sets permissions for an ACL operator. * @param superToken The token to be flowed. * @param flowOperator The operator of the flow. * @param permissionsDelta The permissions to be add for the operator. * @param flowRateAllowanceDelta The amount to increase the flow rate allowance by. * @param userData Extra user data provided. * @param overrides ethers overrides object for more control over the transaction sent. * @returns {Operation} An instance of Operation which can be executed or batched. */ increaseFlowRateAllowanceWithPermissions(params) { const normalizedToken = normalizeAddress(params.superToken); const normalizedFlowOperator = normalizeAddress(params.flowOperator); if (!isPermissionsClean(params.permissionsDelta)) { throw new SFError({ type: "UNCLEAN_PERMISSIONS", message: "The desired permissions are unclean", }); } const callData = cfaInterface.encodeFunctionData("increaseFlowRateAllowanceWithPermissions", [ normalizedToken, normalizedFlowOperator, params.permissionsDelta, params.flowRateAllowanceDelta, "0x", ]); return this.host.callAgreement(this.contract.address, callData, params.userData, params.overrides); } /** * Decrease the flow rate allowance and sets permissions for an ACL operator. * @param superToken The token to be flowed. * @param flowOperator The operator of the flow. * @param permissionsDelta The permissions to be remove from the operator. * @param flowRateAllowanceDelta The amount to decrease the flow rate allowance by. * @param userData Extra user data provided. * @param overrides ethers overrides object for more control over the transaction sent. * @returns {Operation} An instance of Operation which can be executed or batched. */ decreaseFlowRateAllowanceWithPermissions(params) { const normalizedToken = normalizeAddress(params.superToken); const normalizedFlowOperator = normalizeAddress(params.flowOperator); if (!isPermissionsClean(params.permissionsDelta)) { throw new SFError({ type: "UNCLEAN_PERMISSIONS", message: "The desired permissions are unclean", }); } const callData = cfaInterface.encodeFunctionData("decreaseFlowRateAllowanceWithPermissions", [ normalizedToken, normalizedFlowOperator, params.permissionsDelta, params.flowRateAllowanceDelta, "0x", ]); return this.host.callAgreement(this.contract.address, callData, params.userData, params.overrides); } /** * Update permissions for a flow operator as a sender. * @param superToken The token to be flowed. * @param flowOperator The permission grantee address * @param permission The permissions to set. * @param flowRateAllowance The flowRateAllowance granted to the flow operator. * @param userData Extra user data provided. * @param overrides ethers overrides object for more control over the transaction sent. * @returns {Operation} An instance of Operation which can be executed or batched. */ updateFlowOperatorPermissions(params) { const normalizedToken = normalizeAddress(params.superToken); const normalizedFlowOperator = normalizeAddress(params.flowOperator); if (!isPermissionsClean(params.permissions)) { throw new SFError({ type: "UNCLEAN_PERMISSIONS", message: "The desired permissions are unclean", }); } if (Number(params.flowRateAllowance) < 0) { throw new SFError({ type: "NEGATIVE_FLOW_ALLOWANCE", message: "No negative flow allowance allowed", }); } const callData = cfaInterface.encodeFunctionData("updateFlowOperatorPermissions", [ normalizedToken, normalizedFlowOperator, params.permissions, params.flowRateAllowance, "0x", ]); const callAgreementOperation = this.host.callAgreement(this.contract.address, callData, params.userData, params.overrides); const forwarderPopulatedTxnPromise = this.forwarder.populateTransaction.updateFlowOperatorPermissions(normalizedToken, normalizedFlowOperator, params.permissions, params.flowRateAllowance, params.overrides || {}); return this._getCallAgreementOperation(callAgreementOperation, forwarderPopulatedTxnPromise, params.shouldUseCallAgreement); } /** * Give flow operator full control - max flow rate and create/update/delete permissions. * @param superToken The token to be flowed. * @param flowOperator The permission grantee address * @param userData Extra user data provided. * @param overrides ethers overrides object for more control over the transaction sent. */ authorizeFlowOperatorWithFullControl(params) { const normalizedToken = normalizeAddress(params.superToken); const normalizedFlowOperator = normalizeAddress(params.flowOperator); const callData = cfaInterface.encodeFunctionData("authorizeFlowOperatorWithFullControl", [normalizedToken, normalizedFlowOperator, "0x"]); const callAgreementOperation = this.host.callAgreement(this.contract.address, callData, params.userData, params.overrides); const forwarderPopulatedTxnPromise = this.forwarder.populateTransaction.grantPermissions(normalizedToken, normalizedFlowOperator, params.overrides || {}); return this._getCallAgreementOperation(callAgreementOperation, forwarderPopulatedTxnPromise, params.shouldUseCallAgreement); } /** * Revoke flow operator control - set flow rate to 0 with no permissions. * @param superToken The token to be flowed. * @param flowOperator The permission grantee address * @param userData Extra user data provided. * @param overrides ethers overrides object for more control over the transaction sent. */ revokeFlowOperatorWithFullControl(params) { const normalizedToken = normalizeAddress(params.superToken); const normalizedFlowOperator = normalizeAddress(params.flowOperator); const callData = cfaInterface.encodeFunctionData("revokeFlowOperatorWithFullControl", [normalizedToken, normalizedFlowOperator, "0x"]); const callAgreementOperation = this.host.callAgreement(this.contract.address, callData, params.userData, params.overrides); const forwarderPopulatedTxnPromise = this.forwarder.populateTransaction.revokePermissions(normalizedToken, normalizedFlowOperator, params.overrides || {}); return this._getCallAgreementOperation(callAgreementOperation, forwarderPopulatedTxnPromise, params.shouldUseCallAgreement); } } //# sourceMappingURL=ConstantFlowAgreementV1.js.map