@superfluid-finance/sdk-core
Version:
SDK Core for building with Superfluid Protocol
103 lines • 4.66 kB
JavaScript
import { BigNumber } from "ethers";
import Host from "./Host";
import Operation from "./Operation";
import { SFError } from "./SFError";
import { getTransactionDescription } from "./utils";
export const batchOperationTypeStringToTypeMap = new Map([
["ERC20_APPROVE", 1],
["ERC20_TRANSFER_FROM", 2],
["ERC777_SEND", 3],
["ERC20_INCREASE_ALLOWANCE", 4],
["ERC20_DECREASE_ALLOWANCE", 5],
["SUPERTOKEN_UPGRADE", 101],
["SUPERTOKEN_DOWNGRADE", 102],
["SUPERFLUID_CALL_AGREEMENT", 201],
["CALL_APP_ACTION", 202],
["SIMPLE_FORWARD_CALL", 301],
["ERC2771_FORWARD_CALL", 302],
]);
/**
* Gets function arguments given an ABI and callData.
* @param abi the abi fragments of a contract/function
* @param callData call data of the function
* @returns {ethers.utils.Result} call agreement function arguments
*/
export const getCallDataFunctionArgs = (abi, callData) => getTransactionDescription(abi, callData).args;
/**
* BatchCall Helper Class
* @description A helper class to create `BatchCall` objects which can be executed.
*/
export default class BatchCall {
constructor(options) {
this.getCallDataFunctionArgs = getCallDataFunctionArgs;
/**
* Given an `Operation` object, gets the `OperationStruct` object.
* @param operation an `Operation` object
* @param index the index of the `Operation` in the batchCall
* @returns {Promise<OperationStruct>} OperationStruct object for batchCall
*/
this.getOperationStruct = async (operation, index) => operation.toOperationStruct(index);
/**
* Executes a batch call given the operations on this class.
* @param signer the signer of the transaction
* @param gasLimitMultiplier A multiplier to provide gasLimit buffer on top of the estimated gas limit (1.2x is the default)
* @returns {Promise<ethers.ContractTransaction>} ContractTransaction object
*/
this.exec = async (signer, gasLimitMultiplier = 1.2) => {
const operation = await this.toOperation();
return await operation.exec(signer, gasLimitMultiplier);
};
/* istanbul ignore next */
// TODO: user signs the transaction they'd like to execute and gives
// this data to the trusted forwarder to sign
/**
* Executes a forward batch call given the operations on this class.
* @param signer the signer of the transaction
* @returns {Promise<ethers.ContractTransaction>} ContractTransaction object
*/
this.execForward = async (signer) => {
if (this.getOperationStructArrayPromises.length === 0) {
throw new SFError({
type: "BATCH_CALL_ERROR",
message: "There are no operations to execute in the batch.",
});
}
const operationStructArray = await Promise.all(this.getOperationStructArrayPromises);
return await this.host.contract
.connect(signer)
.forwardBatchCall(operationStructArray);
};
this.options = options;
this.host = new Host(options.hostAddress);
}
/**
* Gets an array of `OperationStruct` objects to be passed to batchCall.
* @returns {Promise<OperationStruct>[]} array of operation struct promises
*/
get getOperationStructArrayPromises() {
return this.options.operations.map((x, i) => this.getOperationStruct(x, i));
}
async toOperation() {
if (this.getOperationStructArrayPromises.length === 0) {
throw new SFError({
type: "BATCH_CALL_ERROR",
message: "There are no operations to execute in the batch.",
});
}
const operationStructArray = await Promise.all(this.getOperationStructArrayPromises);
const values = operationStructArray
.filter((x) => { var _a; return (_a = x.value) === null || _a === void 0 ? void 0 : _a.gt(BigNumber.from(0)); })
.map((x) => x.value);
if (values.length > 1) {
throw new SFError({
type: "BATCH_CALL_ERROR",
message: "There are multiple values in the batch call. The value can only be forwarded to one receiving operation.",
});
}
const tx = this.host.contract.populateTransaction.batchCall(operationStructArray, {
value: (values === null || values === void 0 ? void 0 : values.length) > 0 ? values[0] : undefined,
});
return new Operation(tx, "UNSUPPORTED");
}
}
//# sourceMappingURL=BatchCall.js.map