/* Copyright 2022 Set Labs Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ 'use strict'; import { ContractTransaction, BigNumberish, BytesLike, utils as EthersUtils } from 'ethers'; import { Provider } from '@ethersproject/providers'; import { Address } from '@setprotocol/set-protocol-v2/utils/types'; import { TransactionOverrides } from '@setprotocol/set-protocol-v2/dist/typechain'; import { TradeExtension__factory } from '@setprotocol/set-v2-strategies/dist/typechain/factories/TradeExtension__factory'; import TradeExtensionWrapper from '../../wrappers/set-v2-strategies/TradeExtensionWrapper'; import Assertions from '../../assertions'; /** * @title TradeExtensionAPI * @author Set Protocol * * The TradeExtensionAPI exposes methods to trade SetToken components using the TradeModule for SetTokens using * the DelegatedManager system. The API also provides some helper methods to generate bytecode data packets * that encode module and extension initialization method calls. */ export default class TradeExtensionAPI { private tradeExtensionWrapper: TradeExtensionWrapper; private assert: Assertions; public constructor( provider: Provider, TradeExtensionAddress: Address, assertions?: Assertions) { this.tradeExtensionWrapper = new TradeExtensionWrapper(provider, TradeExtensionAddress); this.assert = assertions || new Assertions(); } /** * Executes a trade on a supported DEX. Must be called an address authorized for the `operator` role * on the TradeExtension * * NOTE: Although the SetToken units are passed in for the send and receive quantities, the total quantity * sent and received is the quantity of SetToken units multiplied by the SetToken totalSupply. * * @param setTokenAddress Address of the deployed SetToken to trade on behalf of * @param exchangeName Human readable name of the exchange in the integrations registry * @param sendToken Address of the token to be sent to the exchange * @param sendQuantity Units of token in SetToken sent to the exchange * @param receiveToken Address of the token that will be received from the exchange * @param minReceiveQuantity Min units of token in SetToken to be received from the exchange * @param data Arbitrary bytes to be used to construct trade call data * @param callerAddress Address of caller (optional) * @param txOpts Overrides for transaction (optional) */ public async tradeWithOperatorAsync( setTokenAddress: Address, exchangeName: Address, sendToken: Address, sendQuantity: BigNumberish, receiveToken: Address, minReceiveQuantity: BigNumberish, data: BytesLike, callerAddress: Address = undefined, txOpts: TransactionOverrides = {} ): Promise<ContractTransaction> { this.assert.schema.isValidAddress('setTokenAddress', setTokenAddress); this.assert.schema.isValidString('exchangeName', exchangeName); this.assert.schema.isValidAddress('sendToken', sendToken); this.assert.schema.isValidNumber('sendQuantity', sendQuantity); this.assert.schema.isValidAddress('receiveToken', receiveToken); this.assert.schema.isValidNumber('minReceiveQuantity', minReceiveQuantity); this.assert.schema.isValidBytes('data', data); return await this.tradeExtensionWrapper.tradeWithOperator( setTokenAddress, exchangeName, sendToken, sendQuantity, receiveToken, minReceiveQuantity, data, callerAddress, txOpts ); } /** * Generates TradeExtension initialize call bytecode to be passed as an element in the `initializeBytecode` * array for the DelegatedManagerFactory's `initializeAsync` method. * * @param delegatedManagerAddress Instance of deployed DelegatedManager to initialize the TradeExtension for * * @return Initialization bytecode */ public getTradeExtensionInitializationBytecode( delegatedManagerAddress: Address ): BytesLike { this.assert.schema.isValidAddress('delegatedManagerAddress', delegatedManagerAddress); const extensionInterface = new EthersUtils.Interface(TradeExtension__factory.abi); return extensionInterface.encodeFunctionData('initializeExtension', [ delegatedManagerAddress ]); } /** * Generates `moduleAndExtensionInitialization` bytecode to be passed as an element in the `initializeBytecode` * array for the `initializeAsync` method. * * @param setTokenAddress Instance of deployed setToken to initialize the TradeModule for * * @return Initialization bytecode */ public getTradeModuleAndExtensionInitializationBytecode(delegatedManagerAddress: Address): BytesLike { this.assert.schema.isValidAddress('delegatedManagerAddress', delegatedManagerAddress); const extensionInterface = new EthersUtils.Interface(TradeExtension__factory.abi); return extensionInterface.encodeFunctionData('initializeModuleAndExtension', [ delegatedManagerAddress ]); } }