@superfluid-finance/sdk-core
Version:
SDK Core for building with Superfluid Protocol
306 lines • 14.1 kB
JavaScript
var _a;
import { ethers } from "ethers";
import BatchCall from "./BatchCall";
import ConstantFlowAgreementV1 from "./ConstantFlowAgreementV1";
import GeneralDistributionAgreementV1 from "./GeneralDistributionAgreementV1";
import Governance from "./Governance";
import Host from "./Host";
import InstantDistributionAgreementV1 from "./InstantDistributionAgreementV1";
import Operation from "./Operation";
import Query from "./Query";
import { SFError } from "./SFError";
import SuperToken from "./SuperToken";
import { chainIdToResolverDataMap, networkNameToChainIdMap } from "./constants";
import { getNetworkName, getSubgraphQueriesEndpoint, validateFrameworkConstructorOptions, } from "./frameworkHelpers";
import { Resolver__factory, Superfluid__factory, SuperfluidLoader__factory, } from "./typechain-types";
import { isEthersProvider, isInjectedWeb3 } from "./utils";
const V1 = "v1";
/**
* Superfluid Framework Class
* @description The entrypoint for the SDK-core, `create` an instance of this for full functionality.
*/
class Framework {
constructor(options, settings) {
/**
* Create a signer which can be used to sign transactions.
* @param options.web3Provider a Web3Provider object (e.g. client side - metamask, web3modal)
* @param options.provider an ethers Provider object (e.g. via Hardhat ethers)
* @param options.privateKey a test account private key
* @param options.signer a signer object (e.g. ethers.Wallet instance)
* @returns `ethers.Signer` object
*/
this.createSigner = (options) => {
if (!options.privateKey &&
!options.provider &&
!options.signer &&
!options.web3Provider) {
throw new SFError({
type: "CREATE_SIGNER",
message: "You must pass in a private key, provider or signer.",
});
}
/* istanbul ignore else */
if (options.privateKey) {
if (!options.provider) {
throw new SFError({
type: "CREATE_SIGNER",
message: "You must pass in a provider with your private key.",
});
}
return new ethers.Wallet(options.privateKey, options.provider);
}
else if (options.signer) {
return options.signer;
}
// NOTE: tested by sdk-redux already
else if (options.web3Provider) {
return options.web3Provider.getSigner();
}
/* istanbul ignore next */
throw new SFError({
type: "CREATE_SIGNER",
message: "Something went wrong, this should never occur.",
});
};
/**
* Create a `BatchCall` class from the `Framework`.
* @param operations the list of operations to execute
* @returns `BatchCall` class
*/
this.batchCall = (operations) => {
return new BatchCall({
operations,
hostAddress: this.settings.config.hostAddress,
});
};
/**
* Create an `Operation` class from the `Framework`.
* @param txn the populated transaction to execute
* @param type the operation type
* @returns `Operation` class
*/
this.operation = (txn, type) => {
return new Operation(txn, type);
};
/**
* Loads `NativeAssetSuperToken` class from the `Framework`. Will throw if token is not NativeAssetSuperToken.
* @param tokenAddressOrSymbol
* @returns `NativeAssetSuperToken` class
*/
this.loadNativeAssetSuperToken = async (tokenAddressOrSymbol) => {
const superToken = await this.loadSuperToken(tokenAddressOrSymbol);
// The NativeAssetSuperToken class should have the nativeTokenSymbol property
const isNativeAssetSuperToken = !!superToken.nativeTokenSymbol;
if (!isNativeAssetSuperToken) {
throw new SFError({
type: "SUPERTOKEN_INITIALIZATION",
message: "The token is not a native asset supertoken.",
});
}
return superToken;
};
/**
* Loads `PureSuperToken` class from the `Framework`. Will throw if token is not PureSuperToken.
* @param tokenAddressOrSymbol
* @returns `PureSuperToken` class
*/
this.loadPureSuperToken = async (tokenAddressOrSymbol) => {
const superToken = await this.loadSuperToken(tokenAddressOrSymbol);
// The PureSuperToken class should not have the downgrade (and upgrade) function
// we can just check if downgrade doesn't exist
const isPureSuperToken = !!superToken.downgrade === false;
if (!isPureSuperToken) {
throw new SFError({
type: "SUPERTOKEN_INITIALIZATION",
message: "The token is not a pure supertoken.",
});
}
return superToken;
};
/**
* Loads `WrapperSuperToken` class from the `Framework`. Will throw if token is not WrapperSuperToken.
* @param tokenAddressOrSymbol
* @returns `WrapperSuperToken` class
*/
this.loadWrapperSuperToken = async (tokenAddressOrSymbol) => {
const superToken = await this.loadSuperToken(tokenAddressOrSymbol);
// The WrapperSuperToken class should have the underlyingToken property
const isWrapperSuperToken = !!superToken.underlyingToken;
if (!isWrapperSuperToken) {
throw new SFError({
type: "SUPERTOKEN_INITIALIZATION",
message: "The token is not a wrapper supertoken.",
});
}
return superToken;
};
/**
* Loads `SuperToken` class from the `Framework`. Use this when you're unsure of the token type.
* @param tokenAddressOrSymbol the `SuperToken` address or symbol (if symbol, it must be on the resolver)
* @returns `SuperToken` class
*/
this.loadSuperToken = async (tokenAddressOrSymbol) => {
const address = await this._tryGetTokenAddress(tokenAddressOrSymbol);
return await SuperToken.create({
...this.settings,
address,
});
};
/**
* Try to get the token address given an address (returns if valid) or the token symbol via the resolver.
* @param tokenAddressOrSymbol
* @returns token address
*/
this._tryGetTokenAddress = async (tokenAddressOrSymbol) => {
const isInputValidAddress = ethers.utils.isAddress(tokenAddressOrSymbol);
if (isInputValidAddress) {
return tokenAddressOrSymbol;
}
else {
try {
const superTokenKey = "supertokens." +
this.settings.protocolReleaseVersion +
"." +
tokenAddressOrSymbol;
const resolver = Resolver__factory.connect(this.settings.config.resolverAddress, this.settings.provider);
return await resolver.get(superTokenKey);
}
catch (err) {
throw new SFError({
type: "SUPERTOKEN_INITIALIZATION",
message: "There was an error with loading the SuperToken with symbol: " +
tokenAddressOrSymbol +
" with the resolver.",
cause: err,
});
}
}
};
this.userInputOptions = options;
this.settings = settings;
this.cfaV1 = new ConstantFlowAgreementV1(settings.config.hostAddress, settings.config.cfaV1Address, settings.config.cfaV1ForwarderAddress);
this.governance = new Governance(settings.config.hostAddress, settings.config.governanceAddress);
this.host = new Host(settings.config.hostAddress);
this.idaV1 = new InstantDistributionAgreementV1(settings.config.hostAddress, settings.config.idaV1Address);
this.gdaV1 = new GeneralDistributionAgreementV1(settings.config.hostAddress, settings.config.gdaV1Address, settings.config.gdaV1ForwarderAddress);
this.query = new Query(settings);
const resolver = new ethers.Contract(settings.config.resolverAddress, Resolver__factory.abi);
this.contracts = {
cfaV1: this.cfaV1.contract,
governance: this.governance.contract,
host: this.host.contract,
idaV1: this.idaV1.contract,
gdaV1: this.gdaV1.contract,
resolver,
};
}
}
_a = Framework;
/**
* Creates the Framework object based on user provided `options`.
* @param options.chainId the chainId of your desired network (e.g. 137 = matic)
* @param options.customSubgraphQueriesEndpoint your custom subgraph endpoint
* @param options.resolverAddress a custom resolver address (advanced use for testing)
* @param options.protocolReleaseVersion a custom release version (advanced use for testing)
* @param options.provider a provider object (injected web3, injected ethers, ethers provider) necessary for initializing the framework
* @returns `Framework` class
*/
Framework.create = async (options) => {
validateFrameworkConstructorOptions({
...options,
protocolReleaseVersion: options.protocolReleaseVersion || V1,
});
const networkName = getNetworkName(options);
const chainId = options.chainId || networkNameToChainIdMap.get(networkName);
const releaseVersion = options.protocolReleaseVersion || V1;
const customSubgraphQueriesEndpoint = options.customSubgraphQueriesEndpoint ||
getSubgraphQueriesEndpoint(options);
const provider = isEthersProvider(options.provider)
? options.provider
: isInjectedWeb3(options.provider)
? // must explicitly cast web3 provider type because
// ethers.providers.Web3Provider doesn't like
// the type passed.
new ethers.providers.Web3Provider(options.provider.currentProvider)
: options.provider.provider;
const network = await provider.getNetwork();
if (network.chainId !== chainId && chainId != null) {
throw new SFError({
type: "NETWORK_MISMATCH",
message: "Your provider network chainId is: " +
network.chainId +
" whereas your desired chainId is: " +
chainId,
});
}
try {
const networkData = chainIdToResolverDataMap.get(chainId);
const resolverAddress = options.resolverAddress
? options.resolverAddress
: networkData
? networkData.addresses.resolver
: ethers.constants.AddressZero;
const resolver = Resolver__factory.connect(resolverAddress, provider);
const baseSettings = {
chainId,
customSubgraphQueriesEndpoint,
protocolReleaseVersion: options.protocolReleaseVersion || V1,
provider,
networkName,
};
// supported networks scenario
if (networkData && baseSettings.protocolReleaseVersion === V1) {
const governanceAddress = networkData.addresses.governance
? networkData.addresses.governance
: await Superfluid__factory.connect(networkData.addresses.host, provider).getGovernance();
const settings = {
...baseSettings,
config: {
resolverAddress,
hostAddress: networkData.addresses.host,
cfaV1Address: networkData.addresses.cfaV1,
idaV1Address: networkData.addresses.idaV1,
gdaV1Address: networkData.addresses.gdaV1 ||
ethers.constants.AddressZero,
gdaV1ForwarderAddress: networkData.addresses.gdaV1Forwarder ||
ethers.constants.AddressZero,
governanceAddress,
cfaV1ForwarderAddress: networkData.addresses.cfaV1Forwarder,
},
};
return new _a(options, settings);
}
else {
// unsupported networks scenario (e.g. local testing)
const superfluidLoaderAddress = await resolver.get("SuperfluidLoader-v1");
const cfaV1ForwarderAddress = await resolver.get("CFAv1Forwarder");
const gdaV1ForwarderAddress = await resolver.get("GDAv1Forwarder");
const superfluidLoader = SuperfluidLoader__factory.connect(superfluidLoaderAddress, provider);
const framework = await superfluidLoader.loadFramework(releaseVersion);
const governanceAddress = await Superfluid__factory.connect(framework.superfluid, provider).getGovernance();
const settings = {
...baseSettings,
config: {
resolverAddress,
hostAddress: framework.superfluid,
cfaV1Address: framework.agreementCFAv1,
idaV1Address: framework.agreementIDAv1,
gdaV1Address: framework.agreementGDAv1,
governanceAddress,
cfaV1ForwarderAddress,
gdaV1ForwarderAddress,
},
};
return new _a(options, settings);
}
}
catch (err) {
throw new SFError({
type: "FRAMEWORK_INITIALIZATION",
message: "There was an error initializing the framework",
cause: err,
});
}
};
export default Framework;
//# sourceMappingURL=Framework.js.map