Maker PSM integration [TKR-2] (#150)
* ADDS basic boilerplate for PSM bridge WIP * ADDS integrate the MakerPSM mixin and fix incorrect naming * fix: take into account PSM fee when buying USDC from PSM * feat: intial stab at a PSM sampler WIP * feat: integrate MakerPsm into AS WIP * refactor: get VAT contract address from PSM instead of passing it in * fix: hardcode PSM Gemtoken to USDC * fix: remove passing in authGem, get from PSM contract instead * fix: use constant modified to avoid using storage variables * fix: incorrect num decimals after multiplication in sampler * fix: PSM buy sampling * fix: use fillData to estimate gas schedule * Rebased on latest development * Guard and use latest Curve LiquidityProvider * `@0x/contract-addresses`: Redeploy FQT on mainnet and ropsten Co-authored-by: Jacob Evans <jacob@dekz.net> Co-authored-by: Lawrence Forman <lawrence@0xproject.com>
This commit is contained in:
parent
164a5d44d9
commit
3adfcdffa8
@ -30,6 +30,7 @@ import "./mixins/MixinCryptoCom.sol";
|
||||
import "./mixins/MixinDodo.sol";
|
||||
import "./mixins/MixinDodoV2.sol";
|
||||
import "./mixins/MixinKyber.sol";
|
||||
import "./mixins/MixinMakerPSM.sol";
|
||||
import "./mixins/MixinMooniswap.sol";
|
||||
import "./mixins/MixinMStable.sol";
|
||||
import "./mixins/MixinNerve.sol";
|
||||
@ -49,6 +50,7 @@ contract BridgeAdapter is
|
||||
MixinDodo,
|
||||
MixinDodoV2,
|
||||
MixinKyber,
|
||||
MixinMakerPSM,
|
||||
MixinMooniswap,
|
||||
MixinMStable,
|
||||
MixinNerve,
|
||||
@ -68,6 +70,7 @@ contract BridgeAdapter is
|
||||
MixinDodo()
|
||||
MixinDodoV2()
|
||||
MixinKyber(weth)
|
||||
MixinMakerPSM()
|
||||
MixinMooniswap(weth)
|
||||
MixinMStable()
|
||||
MixinNerve()
|
||||
@ -123,6 +126,13 @@ contract BridgeAdapter is
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.MAKERPSM) {
|
||||
boughtAmount = _tradeMakerPsm(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.MOONISWAP) {
|
||||
boughtAmount = _tradeMooniswap(
|
||||
sellToken,
|
||||
|
@ -43,4 +43,5 @@ library BridgeProtocols {
|
||||
uint128 internal constant BANCOR = 13;
|
||||
uint128 internal constant COFIX = 14;
|
||||
uint128 internal constant NERVE = 15;
|
||||
uint128 internal constant MAKERPSM = 16;
|
||||
}
|
||||
|
@ -0,0 +1,114 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 ZeroEx Intl.
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
|
||||
|
||||
interface IPSM {
|
||||
// @dev Get the fee for selling USDC to DAI in PSM
|
||||
// @return tin toll in [wad]
|
||||
function tin() external view returns (uint256);
|
||||
// @dev Get the fee for selling DAI to USDC in PSM
|
||||
// @return tout toll out [wad]
|
||||
function tout() external view returns (uint256);
|
||||
|
||||
// @dev Get the address of the PSM state Vat
|
||||
// @return address of the Vat
|
||||
function vat() external view returns (address);
|
||||
|
||||
// @dev Get the address of the underlying vault powering PSM
|
||||
// @return address of gemJoin contract
|
||||
function gemJoin() external view returns (address);
|
||||
|
||||
// @dev Sell USDC for DAI
|
||||
// @param usr The address of the account trading USDC for DAI.
|
||||
// @param gemAmt The amount of USDC to sell in USDC base units
|
||||
function sellGem(
|
||||
address usr,
|
||||
uint256 gemAmt
|
||||
) external;
|
||||
// @dev Buy USDC for DAI
|
||||
// @param usr The address of the account trading DAI for USDC
|
||||
// @param gemAmt The amount of USDC to buy in USDC base units
|
||||
function buyGem(
|
||||
address usr,
|
||||
uint256 gemAmt
|
||||
) external;
|
||||
}
|
||||
|
||||
contract MixinMakerPSM {
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
using LibSafeMathV06 for uint256;
|
||||
|
||||
struct MakerPsmBridgeData {
|
||||
address psmAddress;
|
||||
address gemTokenAddres;
|
||||
}
|
||||
|
||||
// Maker units
|
||||
// wad: fixed point decimal with 18 decimals (for basic quantities, e.g. balances)
|
||||
uint256 constant private WAD = 10 ** 18;
|
||||
// ray: fixed point decimal with 27 decimals (for precise quantites, e.g. ratios)
|
||||
uint256 constant private RAY = 10 ** 27;
|
||||
// rad: fixed point decimal with 45 decimals (result of integer multiplication with a wad and a ray)
|
||||
uint256 constant private RAD = 10 ** 45;
|
||||
// See https://github.com/makerdao/dss/blob/master/DEVELOPING.md
|
||||
|
||||
function _tradeMakerPsm(
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
// Decode the bridge data.
|
||||
MakerPsmBridgeData memory data = abi.decode(bridgeData, (MakerPsmBridgeData));
|
||||
uint256 beforeBalance = buyToken.balanceOf(address(this));
|
||||
|
||||
IPSM psm = IPSM(data.psmAddress);
|
||||
|
||||
if (address(sellToken) == data.gemTokenAddres) {
|
||||
sellToken.approveIfBelow(
|
||||
psm.gemJoin(),
|
||||
sellAmount
|
||||
);
|
||||
|
||||
psm.sellGem(address(this), sellAmount);
|
||||
} else if (address(buyToken) == data.gemTokenAddres) {
|
||||
uint256 feeDivisor = WAD.safeAdd(psm.tout()); // eg. 1.001 * 10 ** 18 with 0.1% fee [tout is in wad];
|
||||
uint256 buyTokenBaseUnit = uint256(10) ** uint256(buyToken.decimals());
|
||||
uint256 gemAmount = sellAmount.safeMul(buyTokenBaseUnit).safeDiv(feeDivisor);
|
||||
|
||||
sellToken.approveIfBelow(
|
||||
data.psmAddress,
|
||||
sellAmount
|
||||
);
|
||||
psm.buyGem(address(this), gemAmount);
|
||||
}
|
||||
|
||||
return buyToken.balanceOf(address(this)).safeSub(beforeBalance);
|
||||
}
|
||||
}
|
@ -43,7 +43,7 @@
|
||||
"config": {
|
||||
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,PositiveSlippageFeeTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,AffiliateFeeTransformer,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector,CurveLiquidityProvider,BatchFillNativeOrdersFeature,IBatchFillNativeOrdersFeature,MultiplexFeature,IMultiplexFeature",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeAdapter|BridgeProtocols|CurveLiquidityProvider|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IFeature|IFlashWallet|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOwnableFeature|IPancakeSwapFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinBalancer|MixinBancor|MixinCoFiX|MixinCryptoCom|MixinCurve|MixinDodo|MixinDodoV2|MixinKyber|MixinMStable|MixinMooniswap|MixinNerve|MixinOasis|MixinShell|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestMooniswap|TestNativeOrdersFeature|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx|ZeroExOptimized).json"
|
||||
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeAdapter|BridgeProtocols|CurveLiquidityProvider|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IFeature|IFlashWallet|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOwnableFeature|IPancakeSwapFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinBalancer|MixinBancor|MixinCoFiX|MixinCryptoCom|MixinCurve|MixinDodo|MixinDodoV2|MixinKyber|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinOasis|MixinShell|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestMooniswap|TestNativeOrdersFeature|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx|ZeroExOptimized).json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -13,7 +13,6 @@ import * as FeeCollector from '../generated-artifacts/FeeCollector.json';
|
||||
import * as FeeCollectorController from '../generated-artifacts/FeeCollectorController.json';
|
||||
import * as FillQuoteTransformer from '../generated-artifacts/FillQuoteTransformer.json';
|
||||
import * as FullMigration from '../generated-artifacts/FullMigration.json';
|
||||
import * as IAllowanceTarget from '../generated-artifacts/IAllowanceTarget.json';
|
||||
import * as IBatchFillNativeOrdersFeature from '../generated-artifacts/IBatchFillNativeOrdersFeature.json';
|
||||
import * as IERC20Transformer from '../generated-artifacts/IERC20Transformer.json';
|
||||
import * as IFlashWallet from '../generated-artifacts/IFlashWallet.json';
|
||||
@ -43,7 +42,6 @@ export const artifacts = {
|
||||
FullMigration: FullMigration as ContractArtifact,
|
||||
InitialMigration: InitialMigration as ContractArtifact,
|
||||
IFlashWallet: IFlashWallet as ContractArtifact,
|
||||
IAllowanceTarget: IAllowanceTarget as ContractArtifact,
|
||||
IERC20Transformer: IERC20Transformer as ContractArtifact,
|
||||
IOwnableFeature: IOwnableFeature as ContractArtifact,
|
||||
ISimpleFunctionRegistryFeature: ISimpleFunctionRegistryFeature as ContractArtifact,
|
||||
|
@ -11,7 +11,6 @@ export * from '../generated-wrappers/fee_collector';
|
||||
export * from '../generated-wrappers/fee_collector_controller';
|
||||
export * from '../generated-wrappers/fill_quote_transformer';
|
||||
export * from '../generated-wrappers/full_migration';
|
||||
export * from '../generated-wrappers/i_allowance_target';
|
||||
export * from '../generated-wrappers/i_batch_fill_native_orders_feature';
|
||||
export * from '../generated-wrappers/i_erc20_transformer';
|
||||
export * from '../generated-wrappers/i_flash_wallet';
|
||||
|
@ -83,6 +83,7 @@ import * as MixinCurve from '../test/generated-artifacts/MixinCurve.json';
|
||||
import * as MixinDodo from '../test/generated-artifacts/MixinDodo.json';
|
||||
import * as MixinDodoV2 from '../test/generated-artifacts/MixinDodoV2.json';
|
||||
import * as MixinKyber from '../test/generated-artifacts/MixinKyber.json';
|
||||
import * as MixinMakerPSM from '../test/generated-artifacts/MixinMakerPSM.json';
|
||||
import * as MixinMooniswap from '../test/generated-artifacts/MixinMooniswap.json';
|
||||
import * as MixinMStable from '../test/generated-artifacts/MixinMStable.json';
|
||||
import * as MixinNerve from '../test/generated-artifacts/MixinNerve.json';
|
||||
@ -241,6 +242,7 @@ export const artifacts = {
|
||||
MixinDodoV2: MixinDodoV2 as ContractArtifact,
|
||||
MixinKyber: MixinKyber as ContractArtifact,
|
||||
MixinMStable: MixinMStable as ContractArtifact,
|
||||
MixinMakerPSM: MixinMakerPSM as ContractArtifact,
|
||||
MixinMooniswap: MixinMooniswap as ContractArtifact,
|
||||
MixinNerve: MixinNerve as ContractArtifact,
|
||||
MixinOasis: MixinOasis as ContractArtifact,
|
||||
|
@ -82,6 +82,7 @@ export * from '../test/generated-wrappers/mixin_dodo';
|
||||
export * from '../test/generated-wrappers/mixin_dodo_v2';
|
||||
export * from '../test/generated-wrappers/mixin_kyber';
|
||||
export * from '../test/generated-wrappers/mixin_m_stable';
|
||||
export * from '../test/generated-wrappers/mixin_maker_p_s_m';
|
||||
export * from '../test/generated-wrappers/mixin_mooniswap';
|
||||
export * from '../test/generated-wrappers/mixin_nerve';
|
||||
export * from '../test/generated-wrappers/mixin_oasis';
|
||||
|
@ -11,7 +11,6 @@
|
||||
"generated-artifacts/FeeCollectorController.json",
|
||||
"generated-artifacts/FillQuoteTransformer.json",
|
||||
"generated-artifacts/FullMigration.json",
|
||||
"generated-artifacts/IAllowanceTarget.json",
|
||||
"generated-artifacts/IBatchFillNativeOrdersFeature.json",
|
||||
"generated-artifacts/IERC20Transformer.json",
|
||||
"generated-artifacts/IFlashWallet.json",
|
||||
@ -114,6 +113,7 @@
|
||||
"test/generated-artifacts/MixinDodoV2.json",
|
||||
"test/generated-artifacts/MixinKyber.json",
|
||||
"test/generated-artifacts/MixinMStable.json",
|
||||
"test/generated-artifacts/MixinMakerPSM.json",
|
||||
"test/generated-artifacts/MixinMooniswap.json",
|
||||
"test/generated-artifacts/MixinNerve.json",
|
||||
"test/generated-artifacts/MixinOasis.json",
|
||||
|
@ -28,6 +28,7 @@ import "./DODOV2Sampler.sol";
|
||||
import "./Eth2DaiSampler.sol";
|
||||
import "./KyberSampler.sol";
|
||||
import "./LiquidityProviderSampler.sol";
|
||||
import "./MakerPSMSampler.sol";
|
||||
import "./MultiBridgeSampler.sol";
|
||||
import "./MStableSampler.sol";
|
||||
import "./MooniswapSampler.sol";
|
||||
@ -48,6 +49,7 @@ contract ERC20BridgeSampler is
|
||||
Eth2DaiSampler,
|
||||
KyberSampler,
|
||||
LiquidityProviderSampler,
|
||||
MakerPSMSampler,
|
||||
MStableSampler,
|
||||
MooniswapSampler,
|
||||
MultiBridgeSampler,
|
||||
|
267
packages/asset-swapper/contracts/src/MakerPSMSampler.sol
Normal file
267
packages/asset-swapper/contracts/src/MakerPSMSampler.sol
Normal file
@ -0,0 +1,267 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 ZeroEx Intl.
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./SamplerUtils.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol";
|
||||
|
||||
interface IPSM {
|
||||
// @dev Get the fee for selling USDC to DAI in PSM
|
||||
// @return tin toll in [wad]
|
||||
function tin() external view returns (uint256);
|
||||
// @dev Get the fee for selling DAI to USDC in PSM
|
||||
// @return tout toll out [wad]
|
||||
function tout() external view returns (uint256);
|
||||
|
||||
// @dev Get the address of the PSM state Vat
|
||||
// @return address of the Vat
|
||||
function vat() external view returns (address);
|
||||
|
||||
// @dev Get the address of the underlying vault powering PSM
|
||||
// @return address of gemJoin contract
|
||||
function gemJoin() external view returns (address);
|
||||
|
||||
// @dev Get the address of DAI
|
||||
// @return address of DAI contract
|
||||
function dai() external view returns (address);
|
||||
|
||||
// @dev Sell USDC for DAI
|
||||
// @param usr The address of the account trading USDC for DAI.
|
||||
// @param gemAmt The amount of USDC to sell in USDC base units
|
||||
function sellGem(
|
||||
address usr,
|
||||
uint256 gemAmt
|
||||
) external;
|
||||
// @dev Buy USDC for DAI
|
||||
// @param usr The address of the account trading DAI for USDC
|
||||
// @param gemAmt The amount of USDC to buy in USDC base units
|
||||
function buyGem(
|
||||
address usr,
|
||||
uint256 gemAmt
|
||||
) external;
|
||||
}
|
||||
|
||||
interface IVAT {
|
||||
// @dev Get a collateral type by identifier
|
||||
// @param ilkIdentifier bytes32 identifier. Example: ethers.utils.formatBytes32String("PSM-USDC-A")
|
||||
// @return ilk
|
||||
// @return ilk.Art Total Normalised Debt in wad
|
||||
// @return ilk.rate Accumulated Rates in ray
|
||||
// @return ilk.spot Price with Safety Margin in ray
|
||||
// @return ilk.line Debt Ceiling in rad
|
||||
// @return ilk.dust Urn Debt Floor in rad
|
||||
function ilks(
|
||||
bytes32 ilkIdentifier
|
||||
) external view returns (
|
||||
uint256 Art,
|
||||
uint256 rate,
|
||||
uint256 spot,
|
||||
uint256 line,
|
||||
uint256 dust
|
||||
);
|
||||
}
|
||||
|
||||
contract MakerPSMSampler is
|
||||
SamplerUtils
|
||||
{
|
||||
using LibSafeMathV06 for uint256;
|
||||
|
||||
/// @dev Information about which PSM module to use
|
||||
struct MakerPsmInfo {
|
||||
address psmAddress;
|
||||
bytes32 ilkIdentifier;
|
||||
address gemTokenAddress;
|
||||
}
|
||||
|
||||
/// @dev Gas limit for MakerPsm calls.
|
||||
uint256 constant private MAKER_PSM_CALL_GAS = 300e3; // 300k
|
||||
|
||||
|
||||
// Maker units
|
||||
// wad: fixed point decimal with 18 decimals (for basic quantities, e.g. balances)
|
||||
uint256 constant private WAD = 10 ** 18;
|
||||
// ray: fixed point decimal with 27 decimals (for precise quantites, e.g. ratios)
|
||||
uint256 constant private RAY = 10 ** 27;
|
||||
// rad: fixed point decimal with 45 decimals (result of integer multiplication with a wad and a ray)
|
||||
uint256 constant private RAD = 10 ** 45;
|
||||
// See https://github.com/makerdao/dss/blob/master/DEVELOPING.m
|
||||
|
||||
/// @dev Sample sell quotes from Maker PSM
|
||||
function sampleSellsFromMakerPsm(
|
||||
MakerPsmInfo memory psmInfo,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
IPSM psm = IPSM(psmInfo.psmAddress);
|
||||
IVAT vat = IVAT(psm.vat());
|
||||
|
||||
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
if (makerToken != psm.dai() && takerToken != psm.dai()) {
|
||||
return makerTokenAmounts;
|
||||
}
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
uint256 buyAmount = _samplePSMSell(psmInfo, makerToken, takerToken, takerTokenAmounts[i], psm, vat);
|
||||
|
||||
if (buyAmount == 0) {
|
||||
break;
|
||||
}
|
||||
makerTokenAmounts[i] = buyAmount;
|
||||
}
|
||||
}
|
||||
|
||||
function sampleBuysFromMakerPsm(
|
||||
MakerPsmInfo memory psmInfo,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
IPSM psm = IPSM(psmInfo.psmAddress);
|
||||
IVAT vat = IVAT(psm.vat());
|
||||
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
if (makerToken != psm.dai() && takerToken != psm.dai()) {
|
||||
return takerTokenAmounts;
|
||||
}
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
uint256 sellAmount = _samplePSMBuy(psmInfo, makerToken, takerToken, makerTokenAmounts[i], psm, vat);
|
||||
|
||||
if (sellAmount == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
takerTokenAmounts[i] = sellAmount;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function _samplePSMSell(MakerPsmInfo memory psmInfo, address makerToken, address takerToken, uint256 takerTokenAmount, IPSM psm, IVAT vat)
|
||||
private
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
(uint256 totalDebtInWad,,, uint256 debtCeilingInRad, uint256 debtFloorInRad) = vat.ilks(psmInfo.ilkIdentifier);
|
||||
uint256 gemTokenBaseUnit = uint256(1e6);
|
||||
|
||||
if (takerToken == psmInfo.gemTokenAddress) {
|
||||
// Simulate sellGem
|
||||
// Selling USDC to the PSM, increasing the total debt
|
||||
// Convert USDC 6 decimals to 18 decimals [wad]
|
||||
uint256 takerTokenAmountInWad = takerTokenAmount.safeMul(1e12);
|
||||
|
||||
uint256 newTotalDebtInRad = totalDebtInWad.safeAdd(takerTokenAmountInWad).safeMul(RAY);
|
||||
|
||||
// PSM is too full to fit
|
||||
if (newTotalDebtInRad >= debtCeilingInRad) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint256 feeInWad = takerTokenAmountInWad.safeMul(psm.tin()).safeDiv(WAD);
|
||||
uint256 makerTokenAmountInWad = takerTokenAmountInWad.safeSub(feeInWad);
|
||||
|
||||
return makerTokenAmountInWad;
|
||||
} else if (makerToken == psmInfo.gemTokenAddress) {
|
||||
// Simulate buyGem
|
||||
// Buying USDC from the PSM, decreasing the total debt
|
||||
// Selling DAI for USDC, already in 18 decimals [wad]
|
||||
uint256 takerTokenAmountInWad = takerTokenAmount;
|
||||
if (takerTokenAmountInWad > totalDebtInWad) {
|
||||
return 0;
|
||||
}
|
||||
uint256 newTotalDebtInRad = totalDebtInWad.safeSub(takerTokenAmountInWad).safeMul(RAY);
|
||||
|
||||
// PSM is empty, not enough USDC to buy from it
|
||||
if (newTotalDebtInRad <= debtFloorInRad) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint256 feeDivisorInWad = WAD.safeAdd(psm.tout()); // eg. 1.001 * 10 ** 18 with 0.1% tout;
|
||||
uint256 makerTokenAmountInGemTokenBaseUnits = takerTokenAmountInWad.safeMul(gemTokenBaseUnit).safeDiv(feeDivisorInWad);
|
||||
|
||||
return makerTokenAmountInGemTokenBaseUnits;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function _samplePSMBuy(MakerPsmInfo memory psmInfo, address makerToken, address takerToken, uint256 makerTokenAmount, IPSM psm, IVAT vat)
|
||||
private
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
(uint256 totalDebtInWad,,, uint256 debtCeilingInRad, uint256 debtFloorInRad) = vat.ilks(psmInfo.ilkIdentifier);
|
||||
|
||||
if (takerToken == psmInfo.gemTokenAddress) {
|
||||
// Simulate sellGem
|
||||
// Selling USDC to the PSM, increasing the total debt
|
||||
uint256 makerTokenAmountInWad = makerTokenAmount;
|
||||
uint256 feeDivisorInWad = WAD.safeSub(psm.tin()); // eg. 0.999 * 10 ** 18 with 0.1% tin;
|
||||
uint256 takerTokenAmountInWad = makerTokenAmountInWad.safeMul(WAD).safeDiv(feeDivisorInWad);
|
||||
uint256 newTotalDebtInRad = totalDebtInWad.safeAdd(takerTokenAmountInWad).safeMul(RAY);
|
||||
|
||||
// PSM is too full to fit
|
||||
if (newTotalDebtInRad >= debtCeilingInRad) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint256 takerTokenAmountInGemInGemBaseUnits = (takerTokenAmountInWad.safeDiv(1e12)).safeAdd(1); // Add 1 to deal with cut off decimals converting to lower decimals
|
||||
|
||||
return takerTokenAmountInGemInGemBaseUnits;
|
||||
} else if (makerToken == psmInfo.gemTokenAddress) {
|
||||
// Simulate buyGem
|
||||
// Buying USDC from the PSM, decreasing the total debt
|
||||
uint256 makerTokenAmountInWad = makerTokenAmount.safeMul(1e12);
|
||||
uint256 feeMultiplierInWad = WAD.safeAdd(psm.tout()); // eg. 1.001 * 10 ** 18 with 0.1% tout;
|
||||
uint256 takerTokenAmountInWad = makerTokenAmountInWad.safeMul(feeMultiplierInWad).safeDiv(WAD);
|
||||
if (takerTokenAmountInWad > totalDebtInWad) {
|
||||
return 0;
|
||||
}
|
||||
uint256 newTotalDebtInRad = totalDebtInWad.safeSub(takerTokenAmountInWad).safeMul(RAY);
|
||||
|
||||
// PSM is empty, not enough USDC to buy
|
||||
if (newTotalDebtInRad <= debtFloorInRad) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return takerTokenAmountInWad;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
@ -38,7 +38,7 @@
|
||||
"config": {
|
||||
"publicInterfaceContracts": "ERC20BridgeSampler,BalanceChecker,FakeTaker",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BancorSampler|CurveSampler|DODOSampler|DODOV2Sampler|DummyLiquidityProvider|ERC20BridgeSampler|Eth2DaiSampler|FakeTaker|IBalancer|IBancor|ICurve|IEth2Dai|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UtilitySampler).json",
|
||||
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BancorSampler|CurveSampler|DODOSampler|DODOV2Sampler|DummyLiquidityProvider|ERC20BridgeSampler|Eth2DaiSampler|FakeTaker|IBalancer|IBancor|ICurve|IEth2Dai|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MakerPSMSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UtilitySampler).json",
|
||||
"postpublish": {
|
||||
"assets": []
|
||||
}
|
||||
@ -77,6 +77,7 @@
|
||||
"@ethersproject/address": "^5.0.1",
|
||||
"@ethersproject/contracts": "^5.0.1",
|
||||
"@ethersproject/providers": "^5.0.4",
|
||||
"@ethersproject/strings": "^5.0.10",
|
||||
"axios": "^0.21.1",
|
||||
"axios-mock-adapter": "^1.19.0",
|
||||
"cream-sor": "^0.3.3",
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { ChainId } from '@0x/contract-addresses';
|
||||
import { FillQuoteTransformerOrderType } from '@0x/protocol-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { formatBytes32String } from '@ethersproject/strings';
|
||||
|
||||
import { TokenAdjacencyGraphBuilder } from '../token_adjacency_graph_builder';
|
||||
|
||||
@ -18,7 +19,9 @@ import {
|
||||
KyberSamplerOpts,
|
||||
LiquidityProviderFillData,
|
||||
LiquidityProviderRegistry,
|
||||
MakerPsmFillData,
|
||||
MultiHopFillData,
|
||||
PsmInfo,
|
||||
TokenAdjacencyGraph,
|
||||
UniswapV2FillData,
|
||||
} from './types';
|
||||
@ -78,6 +81,7 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
|
||||
ERC20BridgeSource.LiquidityProvider,
|
||||
ERC20BridgeSource.CryptoCom,
|
||||
ERC20BridgeSource.Linkswap,
|
||||
ERC20BridgeSource.MakerPsm,
|
||||
]),
|
||||
[ChainId.Ropsten]: new SourceFilters([ERC20BridgeSource.Native]),
|
||||
[ChainId.Rinkeby]: new SourceFilters([ERC20BridgeSource.Native]),
|
||||
@ -127,6 +131,7 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
|
||||
ERC20BridgeSource.LiquidityProvider,
|
||||
ERC20BridgeSource.CryptoCom,
|
||||
ERC20BridgeSource.Linkswap,
|
||||
ERC20BridgeSource.MakerPsm,
|
||||
]),
|
||||
[ChainId.Ropsten]: new SourceFilters([ERC20BridgeSource.Native]),
|
||||
[ChainId.Rinkeby]: new SourceFilters([ERC20BridgeSource.Native]),
|
||||
@ -698,12 +703,28 @@ export const MAX_DODOV2_POOLS_QUERIED = 3;
|
||||
|
||||
export const CURVE_LIQUIDITY_PROVIDER_BY_CHAIN_ID = valueByChainId<string>(
|
||||
{
|
||||
[ChainId.Mainnet]: '0x7a6F6a048fE2Dc1397ABa0bf7879d3eacF371C53',
|
||||
[ChainId.Ropsten]: '0xAa213dcDFbF104e08cbAeC3d1628eD197553AfCc',
|
||||
[ChainId.Mainnet]: '0x561b94454b65614ae3db0897b74303f4acf7cc75',
|
||||
[ChainId.Ropsten]: '0xae241c6fc7f28f6dc0cb58b4112ba7f63fcaf5e2',
|
||||
},
|
||||
NULL_ADDRESS,
|
||||
);
|
||||
|
||||
export const MAKER_PSM_INFO_BY_CHAIN_ID = valueByChainId<PsmInfo>(
|
||||
{
|
||||
[ChainId.Mainnet]: {
|
||||
// Currently only USDC is supported
|
||||
gemTokenAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
||||
ilkIdentifier: formatBytes32String('PSM-USDC-A'),
|
||||
psmAddress: '0x89b78cfa322f6c5de0abceecab66aee45393cc5a',
|
||||
},
|
||||
},
|
||||
{
|
||||
gemTokenAddress: NULL_ADDRESS,
|
||||
ilkIdentifier: NULL_BYTES,
|
||||
psmAddress: NULL_ADDRESS,
|
||||
},
|
||||
);
|
||||
|
||||
export const MOONISWAP_LIQUIDITY_PROVIDER_BY_CHAIN_ID = valueByChainId<string>(
|
||||
{
|
||||
[ChainId.Mainnet]: '0xa2033d6ba88756ce6a87584d69dc87bda9a4f889',
|
||||
@ -776,7 +797,7 @@ export const BAKERYSWAP_ROUTER_BY_CHAIN_ID = valueByChainId<string>(
|
||||
export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = {
|
||||
[ERC20BridgeSource.Native]: fillData => {
|
||||
// TODO jacob re-order imports so there is no circular rependency with SignedNativeOrder
|
||||
const nativeFillData = fillData as ({ type: FillQuoteTransformerOrderType });
|
||||
const nativeFillData = fillData as { type: FillQuoteTransformerOrderType };
|
||||
return nativeFillData && nativeFillData.type === FillQuoteTransformerOrderType.Limit
|
||||
? PROTOCOL_FEE_MULTIPLIER.plus(100e3).toNumber()
|
||||
: // TODO jacob revisit wth v4 LimitOrders
|
||||
@ -863,6 +884,16 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = {
|
||||
[ERC20BridgeSource.Balancer]: () => 120e3,
|
||||
[ERC20BridgeSource.Cream]: () => 120e3,
|
||||
[ERC20BridgeSource.MStable]: () => 700e3,
|
||||
[ERC20BridgeSource.MakerPsm]: (fillData?: FillData) => {
|
||||
const psmFillData = fillData as MakerPsmFillData;
|
||||
|
||||
// TODO(kimpers): update with more accurate numbers after allowances have been set
|
||||
if (psmFillData.takerToken === psmFillData.gemTokenAddress) {
|
||||
return psmFillData.isSellOperation ? 389e3 : 423e3;
|
||||
} else {
|
||||
return 444e3;
|
||||
}
|
||||
},
|
||||
[ERC20BridgeSource.Mooniswap]: () => 130e3,
|
||||
[ERC20BridgeSource.Swerve]: () => 150e3,
|
||||
[ERC20BridgeSource.Nerve]: () => 150e3,
|
||||
|
@ -16,6 +16,7 @@ import {
|
||||
GenericRouterFillData,
|
||||
KyberFillData,
|
||||
LiquidityProviderFillData,
|
||||
MakerPsmFillData,
|
||||
MooniswapFillData,
|
||||
MultiHopFillData,
|
||||
NativeCollapsedFill,
|
||||
@ -91,6 +92,8 @@ export function getErc20BridgeSourceToBridgeSource(source: ERC20BridgeSource): s
|
||||
case ERC20BridgeSource.LiquidityProvider:
|
||||
// "LiquidityProvider" is too long to encode (17 characters).
|
||||
return encodeBridgeSourceId(BridgeProtocol.Unknown, 'LP');
|
||||
case ERC20BridgeSource.MakerPsm:
|
||||
return encodeBridgeSourceId(BridgeProtocol.MakerPsm, 'MakerPsm');
|
||||
case ERC20BridgeSource.Mooniswap:
|
||||
return encodeBridgeSourceId(BridgeProtocol.Mooniswap, 'Mooniswap');
|
||||
case ERC20BridgeSource.MStable:
|
||||
@ -216,6 +219,10 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder
|
||||
const mStableFillData = (order as OptimizedMarketBridgeOrder<GenericRouterFillData>).fillData;
|
||||
bridgeData = encoder.encode([mStableFillData.router]);
|
||||
break;
|
||||
case ERC20BridgeSource.MakerPsm:
|
||||
const psmFillData = (order as OptimizedMarketBridgeOrder<MakerPsmFillData>).fillData;
|
||||
bridgeData = encoder.encode([psmFillData.psmAddress, psmFillData.gemTokenAddress]);
|
||||
break;
|
||||
default:
|
||||
throw new Error(AggregationError.NoBridgeForSource);
|
||||
}
|
||||
@ -255,6 +262,10 @@ const curveEncoder = AbiEncoder.create([
|
||||
{ name: 'fromTokenIdx', type: 'int128' },
|
||||
{ name: 'toTokenIdx', type: 'int128' },
|
||||
]);
|
||||
const makerPsmEncoder = AbiEncoder.create([
|
||||
{ name: 'psmAddress', type: 'address' },
|
||||
{ name: 'gemTokenAddress', type: 'address' },
|
||||
]);
|
||||
const routerAddressPathEncoder = AbiEncoder.create('(address,address[])');
|
||||
const tokenAddressEncoder = AbiEncoder.create([{ name: 'tokenAddress', type: 'address' }]);
|
||||
|
||||
@ -302,6 +313,8 @@ export const BRIDGE_ENCODERS: {
|
||||
[ERC20BridgeSource.Balancer]: poolEncoder,
|
||||
[ERC20BridgeSource.Cream]: poolEncoder,
|
||||
[ERC20BridgeSource.Uniswap]: poolEncoder,
|
||||
// Custom integrations
|
||||
[ERC20BridgeSource.MakerPsm]: makerPsmEncoder,
|
||||
// BSC
|
||||
[ERC20BridgeSource.PancakeSwap]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.BakerySwap]: routerAddressPathEncoder,
|
||||
|
@ -25,6 +25,7 @@ import {
|
||||
KYBER_CONFIG_BY_CHAIN_ID,
|
||||
LINKSWAP_ROUTER_BY_CHAIN_ID,
|
||||
LIQUIDITY_PROVIDER_REGISTRY,
|
||||
MAKER_PSM_INFO_BY_CHAIN_ID,
|
||||
MAX_UINT256,
|
||||
MOONISWAP_REGISTRIES_BY_CHAIN_ID,
|
||||
MSTABLE_ROUTER_BY_CHAIN_ID,
|
||||
@ -57,8 +58,10 @@ import {
|
||||
KyberSamplerOpts,
|
||||
LiquidityProviderFillData,
|
||||
LiquidityProviderRegistry,
|
||||
MakerPsmFillData,
|
||||
MooniswapFillData,
|
||||
MultiHopFillData,
|
||||
PsmInfo,
|
||||
ShellFillData,
|
||||
SourceQuoteOperation,
|
||||
TokenAdjacencyGraph,
|
||||
@ -857,6 +860,46 @@ export class SamplerOperations {
|
||||
});
|
||||
}
|
||||
|
||||
public getMakerPsmSellQuotes(
|
||||
psmInfo: PsmInfo,
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
takerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation<MakerPsmFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.MakerPsm,
|
||||
fillData: {
|
||||
isSellOperation: true,
|
||||
takerToken,
|
||||
makerToken,
|
||||
...psmInfo,
|
||||
},
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleSellsFromMakerPsm,
|
||||
params: [psmInfo, takerToken, makerToken, takerFillAmounts],
|
||||
});
|
||||
}
|
||||
|
||||
public getMakerPsmBuyQuotes(
|
||||
psmInfo: PsmInfo,
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
makerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation<MakerPsmFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.MakerPsm,
|
||||
fillData: {
|
||||
isSellOperation: false,
|
||||
takerToken,
|
||||
makerToken,
|
||||
...psmInfo,
|
||||
},
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleBuysFromMakerPsm,
|
||||
params: [psmInfo, takerToken, makerToken, makerFillAmounts],
|
||||
});
|
||||
}
|
||||
|
||||
public getMedianSellRate(
|
||||
sources: ERC20BridgeSource[],
|
||||
makerToken: string,
|
||||
@ -1118,6 +1161,12 @@ export class SamplerOperations {
|
||||
ERC20BridgeSource.Linkswap,
|
||||
),
|
||||
);
|
||||
case ERC20BridgeSource.MakerPsm:
|
||||
const psmInfo = MAKER_PSM_INFO_BY_CHAIN_ID[this.chainId];
|
||||
if (!isValidAddress(psmInfo.psmAddress)) {
|
||||
return [];
|
||||
}
|
||||
return this.getMakerPsmSellQuotes(psmInfo, makerToken, takerToken, takerFillAmounts);
|
||||
default:
|
||||
throw new Error(`Unsupported sell sample source: ${source}`);
|
||||
}
|
||||
@ -1298,6 +1347,12 @@ export class SamplerOperations {
|
||||
ERC20BridgeSource.Linkswap,
|
||||
),
|
||||
);
|
||||
case ERC20BridgeSource.MakerPsm:
|
||||
const psmInfo = MAKER_PSM_INFO_BY_CHAIN_ID[this.chainId];
|
||||
if (!isValidAddress(psmInfo.psmAddress)) {
|
||||
return [];
|
||||
}
|
||||
return this.getMakerPsmBuyQuotes(psmInfo, makerToken, takerToken, makerFillAmounts);
|
||||
default:
|
||||
throw new Error(`Unsupported buy sample source: ${source}`);
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ export enum ERC20BridgeSource {
|
||||
Balancer = 'Balancer',
|
||||
Cream = 'CREAM',
|
||||
Bancor = 'Bancor',
|
||||
MakerPsm = 'MakerPsm',
|
||||
MStable = 'mStable',
|
||||
Mooniswap = 'Mooniswap',
|
||||
MultiHop = 'MultiHop',
|
||||
@ -96,6 +97,15 @@ export interface CurveInfo {
|
||||
metaToken: string | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for a specific PSM vault
|
||||
*/
|
||||
export interface PsmInfo {
|
||||
psmAddress: string;
|
||||
ilkIdentifier: string;
|
||||
gemTokenAddress: string;
|
||||
}
|
||||
|
||||
// Internal `fillData` field for `Fill` objects.
|
||||
export interface FillData {}
|
||||
|
||||
@ -165,6 +175,14 @@ export interface MultiHopFillData extends FillData {
|
||||
secondHopSource: SourceQuoteOperation;
|
||||
intermediateToken: string;
|
||||
}
|
||||
|
||||
export interface MakerPsmExtendedData {
|
||||
isSellOperation: boolean;
|
||||
takerToken: string;
|
||||
}
|
||||
|
||||
export type MakerPsmFillData = FillData & MakerPsmExtendedData & PsmInfo;
|
||||
|
||||
export interface HopInfo {
|
||||
sourceIndex: BigNumber;
|
||||
returnData: string;
|
||||
|
@ -29,6 +29,7 @@ import * as IUniswapExchangeQuotes from '../test/generated-artifacts/IUniswapExc
|
||||
import * as IUniswapV2Router01 from '../test/generated-artifacts/IUniswapV2Router01.json';
|
||||
import * as KyberSampler from '../test/generated-artifacts/KyberSampler.json';
|
||||
import * as LiquidityProviderSampler from '../test/generated-artifacts/LiquidityProviderSampler.json';
|
||||
import * as MakerPSMSampler from '../test/generated-artifacts/MakerPSMSampler.json';
|
||||
import * as MooniswapSampler from '../test/generated-artifacts/MooniswapSampler.json';
|
||||
import * as MStableSampler from '../test/generated-artifacts/MStableSampler.json';
|
||||
import * as MultiBridgeSampler from '../test/generated-artifacts/MultiBridgeSampler.json';
|
||||
@ -55,6 +56,7 @@ export const artifacts = {
|
||||
KyberSampler: KyberSampler as ContractArtifact,
|
||||
LiquidityProviderSampler: LiquidityProviderSampler as ContractArtifact,
|
||||
MStableSampler: MStableSampler as ContractArtifact,
|
||||
MakerPSMSampler: MakerPSMSampler as ContractArtifact,
|
||||
MooniswapSampler: MooniswapSampler as ContractArtifact,
|
||||
MultiBridgeSampler: MultiBridgeSampler as ContractArtifact,
|
||||
NativeOrderSampler: NativeOrderSampler as ContractArtifact,
|
||||
|
@ -67,6 +67,7 @@ const DEFAULT_EXCLUDED = [
|
||||
ERC20BridgeSource.Linkswap,
|
||||
ERC20BridgeSource.PancakeSwap,
|
||||
ERC20BridgeSource.BakerySwap,
|
||||
ERC20BridgeSource.MakerPsm,
|
||||
];
|
||||
const BUY_SOURCES = BUY_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Mainnet].sources;
|
||||
const SELL_SOURCES = SELL_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Mainnet].sources;
|
||||
@ -305,6 +306,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
[ERC20BridgeSource.Linkswap]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.PancakeSwap]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.BakerySwap]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.MakerPsm]: _.times(NUM_SAMPLES, () => 0),
|
||||
};
|
||||
|
||||
const DEFAULT_RATES: RatesBySource = {
|
||||
@ -369,6 +371,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
[ERC20BridgeSource.Linkswap]: { tokenAddressPath: [] },
|
||||
[ERC20BridgeSource.Uniswap]: { router: randomAddress() },
|
||||
[ERC20BridgeSource.Eth2Dai]: { router: randomAddress() },
|
||||
[ERC20BridgeSource.MakerPsm]: {},
|
||||
};
|
||||
|
||||
const DEFAULT_OPS = {
|
||||
|
@ -28,6 +28,7 @@ export * from '../test/generated-wrappers/i_uniswap_v2_router01';
|
||||
export * from '../test/generated-wrappers/kyber_sampler';
|
||||
export * from '../test/generated-wrappers/liquidity_provider_sampler';
|
||||
export * from '../test/generated-wrappers/m_stable_sampler';
|
||||
export * from '../test/generated-wrappers/maker_p_s_m_sampler';
|
||||
export * from '../test/generated-wrappers/mooniswap_sampler';
|
||||
export * from '../test/generated-wrappers/multi_bridge_sampler';
|
||||
export * from '../test/generated-wrappers/native_order_sampler';
|
||||
|
@ -31,6 +31,7 @@
|
||||
"test/generated-artifacts/KyberSampler.json",
|
||||
"test/generated-artifacts/LiquidityProviderSampler.json",
|
||||
"test/generated-artifacts/MStableSampler.json",
|
||||
"test/generated-artifacts/MakerPSMSampler.json",
|
||||
"test/generated-artifacts/MooniswapSampler.json",
|
||||
"test/generated-artifacts/MultiBridgeSampler.json",
|
||||
"test/generated-artifacts/NativeOrderSampler.json",
|
||||
|
@ -1,6 +1,6 @@
|
||||
[
|
||||
{
|
||||
"version": "6.0.0-bsc.0",
|
||||
"version": "6.0.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add BSC chain addresses",
|
||||
@ -13,6 +13,10 @@
|
||||
{
|
||||
"note": "Redeployed FQT on BSC",
|
||||
"pr": 181
|
||||
},
|
||||
{
|
||||
"note": "Redeployed FQT on mainnet and ropsten",
|
||||
"pr": 150
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -36,7 +36,7 @@
|
||||
"wethTransformer": "0xb2bc06a4efb20fc6553a69dbfa49b7be938034a7",
|
||||
"payTakerTransformer": "0x4638a7ebe75b911b995d0ec73a81e4f85f41f24e",
|
||||
"affiliateFeeTransformer": "0xda6d9fc5998f550a094585cf9171f0e8ee3ac59f",
|
||||
"fillQuoteTransformer": "0x227e767a9b7517681d1cb6b846aa9e541484c7ab",
|
||||
"fillQuoteTransformer": "0xb8e40acea68db2a7a2020a3eba2664ba4c3b3e3d",
|
||||
"positiveSlippageFeeTransformer": "0xa9416ce1dbde8d331210c07b5c253d94ee4cc3fd"
|
||||
}
|
||||
},
|
||||
@ -77,7 +77,7 @@
|
||||
"wethTransformer": "0x05ad19aa3826e0609a19568ffbd1dfe86c6c7184",
|
||||
"payTakerTransformer": "0x6d0ebf2bcd9cc93ec553b60ad201943dcca4e291",
|
||||
"affiliateFeeTransformer": "0x6588256778ca4432fa43983ac685c45efb2379e2",
|
||||
"fillQuoteTransformer": "0x2088a820787ebbe937a0612ef024f1e1d65f9784",
|
||||
"fillQuoteTransformer": "0xc0c6fc6911978a65fe3b17391bb30b630bfc637d",
|
||||
"positiveSlippageFeeTransformer": "0x8b332f700fd37e71c5c5b26c4d78b5ca63dd33b2"
|
||||
}
|
||||
},
|
||||
|
@ -125,6 +125,7 @@ export enum BridgeProtocol {
|
||||
Bancor,
|
||||
CoFiX,
|
||||
Nerve,
|
||||
MakerPsm,
|
||||
}
|
||||
// tslint:enable: enum-naming
|
||||
|
||||
|
44
yarn.lock
44
yarn.lock
@ -646,7 +646,6 @@
|
||||
"@0x/abi-gen@^5.4.21":
|
||||
version "5.4.21"
|
||||
resolved "https://registry.yarnpkg.com/@0x/abi-gen/-/abi-gen-5.4.21.tgz#96705962c75e116bd5050784287012ede4607564"
|
||||
integrity sha512-rJPzWUjCeygMC71HfyGQAEeYtfkv5Mi+cjIOrmWfTQmM4SN+6wBraEWKLJHkcFTZ3lmFjkS/ZfbGhQere6/Y4w==
|
||||
dependencies:
|
||||
"@0x/types" "^3.3.1"
|
||||
"@0x/typescript-typings" "^5.1.6"
|
||||
@ -712,7 +711,6 @@
|
||||
"@0x/contracts-gen@^2.0.32":
|
||||
version "2.0.32"
|
||||
resolved "https://registry.yarnpkg.com/@0x/contracts-gen/-/contracts-gen-2.0.32.tgz#e4817730685acc0047157e55d58a6cab87596799"
|
||||
integrity sha512-FkdCn9L48u6M2WyyQOWuDFvmqvYIfv1O47Hlwf8MGVJaxGmhDhqJsCr4HlmE4Jg84dK7I7xIeh0MMs8jPNpRUA==
|
||||
dependencies:
|
||||
"@0x/sol-compiler" "^4.6.1"
|
||||
"@0x/sol-resolver" "^3.1.6"
|
||||
@ -805,7 +803,6 @@
|
||||
"@0x/monorepo-scripts@^3.1.1":
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@0x/monorepo-scripts/-/monorepo-scripts-3.1.1.tgz#2ded9ef1d4885bbf106612794a331e29f391733a"
|
||||
integrity sha512-thovxmZMivSeESlY+FXLxkf4wrmLe40ZjfGOcJaPhe29me03ddgEtVgToi+k7ZGfTeRWm5gmvlisHak2D6TFwA==
|
||||
dependencies:
|
||||
"@0x/types" "^3.3.1"
|
||||
"@0x/utils" "^6.2.0"
|
||||
@ -847,7 +844,6 @@
|
||||
"@0x/sol-compiler@^4.6.1":
|
||||
version "4.6.1"
|
||||
resolved "https://registry.yarnpkg.com/@0x/sol-compiler/-/sol-compiler-4.6.1.tgz#d1f9c1547605ddbd4ad9cc6ebed60b91f5e1ce3d"
|
||||
integrity sha512-iEFcrn+5OSNCD2yr0WjF9h0+0J/0DNNpEuc1yK5OAD6F4X6U/YChYohSx/odWNhYfJODW+dj1SABWxZfybgIwQ==
|
||||
dependencies:
|
||||
"@0x/assert" "^3.0.21"
|
||||
"@0x/json-schemas" "^5.4.1"
|
||||
@ -876,7 +872,6 @@
|
||||
"@0x/sol-coverage@^4.0.31":
|
||||
version "4.0.31"
|
||||
resolved "https://registry.yarnpkg.com/@0x/sol-coverage/-/sol-coverage-4.0.31.tgz#ec958d892dce3773059b925e442e21d7c4f9b104"
|
||||
integrity sha512-XcD2MntdpjDAV2KWmZyD6T3dI2sgaXwBXVa/cRtlC0cUAJcXp+tblwvtt1VOxc2J6QFCaTG4UTs9oS2nGbxwbA==
|
||||
dependencies:
|
||||
"@0x/sol-tracing-utils" "^7.1.21"
|
||||
"@0x/subproviders" "^6.4.1"
|
||||
@ -891,7 +886,6 @@
|
||||
"@0x/sol-profiler@^4.1.21":
|
||||
version "4.1.21"
|
||||
resolved "https://registry.yarnpkg.com/@0x/sol-profiler/-/sol-profiler-4.1.21.tgz#76f4860b3e0c73b8e11ac56ce25e52164cee1476"
|
||||
integrity sha512-JFDUhFrWJP1WqVIKK1w/2nU/s8g91xNeZW1l4ZydEGhZPsRNgQdk8rFBwGqxPeqMqUY7T+Xm2Y/IVjYvE+Ck3w==
|
||||
dependencies:
|
||||
"@0x/sol-tracing-utils" "^7.1.21"
|
||||
"@0x/subproviders" "^6.4.1"
|
||||
@ -915,7 +909,6 @@
|
||||
"@0x/sol-trace@^3.0.31":
|
||||
version "3.0.31"
|
||||
resolved "https://registry.yarnpkg.com/@0x/sol-trace/-/sol-trace-3.0.31.tgz#9ed79139c81ad8953a9947019053ead5a20f9408"
|
||||
integrity sha512-wQjdVc/IOcyzIfDVfurzFQuhkZlnejwNVNWn+9S6uYXteIqgHcJv0WqD5dZNFxcNG4Jn7tXxHJ/AXxXDygM+cw==
|
||||
dependencies:
|
||||
"@0x/sol-tracing-utils" "^7.1.21"
|
||||
"@0x/subproviders" "^6.4.1"
|
||||
@ -931,7 +924,6 @@
|
||||
"@0x/sol-tracing-utils@^7.1.21":
|
||||
version "7.1.21"
|
||||
resolved "https://registry.yarnpkg.com/@0x/sol-tracing-utils/-/sol-tracing-utils-7.1.21.tgz#9ffb9f51fdc6bcf0be8f95841563a6ccccbac474"
|
||||
integrity sha512-Y0aYJD1h+0IBZe7A9FKorhf7qtWawftahV61FjPCOaHfvQNfVeza7wm9hdMYOb+B2hbFCDFo06GfZaINw7VFVA==
|
||||
dependencies:
|
||||
"@0x/dev-utils" "^4.2.1"
|
||||
"@0x/sol-compiler" "^4.6.1"
|
||||
@ -1311,18 +1303,38 @@
|
||||
"@ethersproject/logger" "^5.0.5"
|
||||
bn.js "^4.4.0"
|
||||
|
||||
"@ethersproject/bignumber@^5.0.13":
|
||||
version "5.0.15"
|
||||
resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.0.15.tgz#b089b3f1e0381338d764ac1c10512f0c93b184ed"
|
||||
dependencies:
|
||||
"@ethersproject/bytes" "^5.0.9"
|
||||
"@ethersproject/logger" "^5.0.8"
|
||||
bn.js "^4.4.0"
|
||||
|
||||
"@ethersproject/bytes@>=5.0.0-beta.129", "@ethersproject/bytes@^5.0.4":
|
||||
version "5.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.0.5.tgz#688b70000e550de0c97a151a21f15b87d7f97d7c"
|
||||
dependencies:
|
||||
"@ethersproject/logger" "^5.0.5"
|
||||
|
||||
"@ethersproject/bytes@^5.0.9":
|
||||
version "5.0.11"
|
||||
resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.0.11.tgz#21118e75b1d00db068984c15530e316021101276"
|
||||
dependencies:
|
||||
"@ethersproject/logger" "^5.0.8"
|
||||
|
||||
"@ethersproject/constants@>=5.0.0-beta.128", "@ethersproject/constants@^5.0.4":
|
||||
version "5.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.0.5.tgz#0ed19b002e8404bdf6d135234dc86a7d9bcf9b71"
|
||||
dependencies:
|
||||
"@ethersproject/bignumber" "^5.0.7"
|
||||
|
||||
"@ethersproject/constants@^5.0.8":
|
||||
version "5.0.10"
|
||||
resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.0.10.tgz#eb0c604fbc44c53ba9641eed31a1d0c9e1ebcadc"
|
||||
dependencies:
|
||||
"@ethersproject/bignumber" "^5.0.13"
|
||||
|
||||
"@ethersproject/contracts@^5.0.1":
|
||||
version "5.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.0.5.tgz#64831a341ec8ca225e83ff3e9437c26b970fd5d7"
|
||||
@ -1361,6 +1373,10 @@
|
||||
version "5.0.6"
|
||||
resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.0.6.tgz#faa484203e86e08be9e07fef826afeef7183fe88"
|
||||
|
||||
"@ethersproject/logger@^5.0.8":
|
||||
version "5.0.10"
|
||||
resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.0.10.tgz#fd884688b3143253e0356ef92d5f22d109d2e026"
|
||||
|
||||
"@ethersproject/networks@^5.0.3":
|
||||
version "5.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.0.4.tgz#6d320a5e15a0cda804f5da88be0ba846156f6eec"
|
||||
@ -1436,6 +1452,14 @@
|
||||
"@ethersproject/constants" "^5.0.4"
|
||||
"@ethersproject/logger" "^5.0.5"
|
||||
|
||||
"@ethersproject/strings@^5.0.10":
|
||||
version "5.0.10"
|
||||
resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.0.10.tgz#ddce1e9724f4ac4f3f67e0cac0b48748e964bfdb"
|
||||
dependencies:
|
||||
"@ethersproject/bytes" "^5.0.9"
|
||||
"@ethersproject/constants" "^5.0.8"
|
||||
"@ethersproject/logger" "^5.0.8"
|
||||
|
||||
"@ethersproject/transactions@^5.0.0-beta.135", "@ethersproject/transactions@^5.0.5":
|
||||
version "5.0.6"
|
||||
resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.0.6.tgz#b8b27938be6e9ed671dbdd35fe98af8b14d0df7c"
|
||||
@ -2995,7 +3019,6 @@ aws4@^1.8.0:
|
||||
axios-mock-adapter@^1.19.0:
|
||||
version "1.19.0"
|
||||
resolved "https://registry.yarnpkg.com/axios-mock-adapter/-/axios-mock-adapter-1.19.0.tgz#9d72e321a6c5418e1eff067aa99761a86c5188a4"
|
||||
integrity sha512-D+0U4LNPr7WroiBDvWilzTMYPYTuZlbo6BI8YHZtj7wYQS8NkARlP9KBt8IWWHTQJ0q/8oZ0ClPBtKCCkx8cQg==
|
||||
dependencies:
|
||||
fast-deep-equal "^3.1.3"
|
||||
is-buffer "^2.0.3"
|
||||
@ -3003,7 +3026,6 @@ axios-mock-adapter@^1.19.0:
|
||||
axios@^0.21.1:
|
||||
version "0.21.1"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
|
||||
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
|
||||
dependencies:
|
||||
follow-redirects "^1.10.0"
|
||||
|
||||
@ -6359,7 +6381,6 @@ flush-write-stream@^1.0.0, flush-write-stream@^1.0.2:
|
||||
follow-redirects@^1.10.0:
|
||||
version "1.13.3"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267"
|
||||
integrity sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==
|
||||
|
||||
for-each@~0.3.3:
|
||||
version "0.3.3"
|
||||
@ -11692,7 +11713,6 @@ strip-bom@^3.0.0:
|
||||
strip-comments@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-comments/-/strip-comments-2.0.1.tgz#4ad11c3fbcac177a67a40ac224ca339ca1c1ba9b"
|
||||
integrity sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==
|
||||
|
||||
strip-dirs@^2.0.0:
|
||||
version "2.1.0"
|
||||
|
Loading…
x
Reference in New Issue
Block a user