- (SwapsImplSovrynSwap.sol)
View Source: contracts/swaps/connectors/SwapsImplSovrynSwap.sol
↗ Extends: State, ISwapsImpl
This contract code comes from bZx. bZx is a protocol for tokenized margin trading and lending https://bzx.network similar to the dYdX protocol.
- This contract contains the implementation of swap process and rate calculations for Sovryn network.
- getContractHexName(string source)
- getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)
- internalSwap(address sourceTokenAddress, address destTokenAddress, address receiverAddress, address returnToSenderAddress, uint256 minSourceTokenAmount, uint256 maxSourceTokenAmount, uint256 requiredDestTokenAmount)
- allowTransfer(uint256 tokenAmount, address tokenAddress, address sovrynSwapNetwork)
- estimateSourceTokenAmount(address sourceTokenAddress, address destTokenAddress, uint256 requiredDestTokenAmount, uint256 maxSourceTokenAmount)
- internalExpectedRate(address sourceTokenAddress, address destTokenAddress, uint256 sourceTokenAmount, address sovrynSwapContractRegistryAddress)
- internalExpectedReturn(address sourceTokenAddress, address destTokenAddress, uint256 sourceTokenAmount, address sovrynSwapContractRegistry, IERC20[] defaultPath)
- getConversionPath(address sourceTokenAddress, address destTokenAddress, ISovrynSwapNetwork sovrynSwapNetwork)
function getContractHexName(string source) public pure
returns(result bytes32)
Arguments
Name | Type | Description |
---|---|---|
source | string | The name of the contract. |
Source Code
function getContractHexName(string memory source) public pure returns (bytes32 result) {
assembly {
result := mload(add(source, 32))
}
}
function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress) public view
returns(contract ISovrynSwapNetwork)
Arguments
Name | Type | Description |
---|---|---|
sovrynSwapRegistryAddress | address | The address of the registry. |
Source Code
function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)
public
view
returns (ISovrynSwapNetwork)
{
/// State variable sovrynSwapContractRegistryAddress is part of
/// State.sol and set in ProtocolSettings.sol and this function
/// needs to work without delegate call as well -> therefore pass it.
IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);
return
ISovrynSwapNetwork(
contractRegistry.addressOf(getContractHexName("SovrynSwapNetwork"))
);
}
⤾ overrides ISwapsImpl.internalSwap
function internalSwap(address sourceTokenAddress, address destTokenAddress, address receiverAddress, address returnToSenderAddress, uint256 minSourceTokenAmount, uint256 maxSourceTokenAmount, uint256 requiredDestTokenAmount) public payable
returns(destTokenAmountReceived uint256, sourceTokenAmountUsed uint256)
Arguments
Name | Type | Description |
---|---|---|
sourceTokenAddress | address | The address of the source tokens. |
destTokenAddress | address | The address of the destination tokens. |
receiverAddress | address | The address who will received the swap token results |
returnToSenderAddress | address | The address to return unspent tokens to (when called by the protocol, it's always the protocol contract). |
minSourceTokenAmount | uint256 | The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0). |
maxSourceTokenAmount | uint256 | The maximum amount of source tokens to swapped. |
requiredDestTokenAmount | uint256 | The required amount of destination tokens. |
Source Code
function internalSwap(
address sourceTokenAddress,
address destTokenAddress,
address receiverAddress,
address returnToSenderAddress,
uint256 minSourceTokenAmount,
uint256 maxSourceTokenAmount,
uint256 requiredDestTokenAmount
) public payable returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed) {
require(sourceTokenAddress != destTokenAddress, "source == dest");
require(
supportedTokens[sourceTokenAddress] && supportedTokens[destTokenAddress],
"invalid tokens"
);
ISovrynSwapNetwork sovrynSwapNetwork =
getSovrynSwapNetworkContract(sovrynSwapContractRegistryAddress);
IERC20[] memory path =
getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);
uint256 minReturn = 1;
sourceTokenAmountUsed = minSourceTokenAmount;
/// If the required amount of destination tokens is passed, we need to
/// calculate the estimated amount of source tokens regardless of the
/// minimum source token amount (name is misleading).
if (requiredDestTokenAmount > 0) {
sourceTokenAmountUsed = estimateSourceTokenAmount(
sourceTokenAddress,
destTokenAddress,
requiredDestTokenAmount,
maxSourceTokenAmount
);
/// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.
require(
sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=
requiredDestTokenAmount,
"insufficient source tokens provided."
);
minReturn = requiredDestTokenAmount;
}
require(sourceTokenAmountUsed > 0, "cannot swap 0 tokens");
allowTransfer(sourceTokenAmountUsed, sourceTokenAddress, address(sovrynSwapNetwork));
/// @dev Note: the kyber connector uses .call() to interact with kyber
/// to avoid bubbling up. here we allow bubbling up.
destTokenAmountReceived = sovrynSwapNetwork.convertByPath(
path,
sourceTokenAmountUsed,
minReturn,
receiverAddress,
address(0),
0
);
/// If the sender is not the protocol (calling with delegatecall),
/// return the remainder to the specified address.
/// @dev Note: for the case that the swap is used without the
/// protocol. Not sure if it should, though. needs to be discussed.
if (returnToSenderAddress != address(this)) {
if (sourceTokenAmountUsed < maxSourceTokenAmount) {
/// Send unused source token back.
IERC20(sourceTokenAddress).safeTransfer(
returnToSenderAddress,
maxSourceTokenAmount - sourceTokenAmountUsed
);
}
}
}
Check whether the existing allowance suffices to transfer the needed amount of tokens. If not, allows the transfer of an arbitrary amount of tokens. *
function allowTransfer(uint256 tokenAmount, address tokenAddress, address sovrynSwapNetwork) internal nonpayable
Arguments
Name | Type | Description |
---|---|---|
tokenAmount | uint256 | The amount to transfer. |
tokenAddress | address | The address of the token to transfer. |
sovrynSwapNetwork | address | The address of the sovrynSwap network contract. |
Source Code
function allowTransfer(
uint256 tokenAmount,
address tokenAddress,
address sovrynSwapNetwork
) internal {
uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);
if (tempAllowance < tokenAmount) {
IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));
}
}
Calculate the number of source tokens to provide in order to obtain the required destination amount. *
function estimateSourceTokenAmount(address sourceTokenAddress, address destTokenAddress, uint256 requiredDestTokenAmount, uint256 maxSourceTokenAmount) internal view
returns(estimatedSourceAmount uint256)
Arguments
Name | Type | Description |
---|---|---|
sourceTokenAddress | address | The address of the source token address. |
destTokenAddress | address | The address of the destination token address. |
requiredDestTokenAmount | uint256 | The number of destination tokens needed. |
maxSourceTokenAmount | uint256 | The maximum number of source tokens to spend. * |
Returns
The estimated amount of source tokens needed. Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount
Source Code
function estimateSourceTokenAmount(
address sourceTokenAddress,
address destTokenAddress,
uint256 requiredDestTokenAmount,
uint256 maxSourceTokenAmount
) internal view returns (uint256 estimatedSourceAmount) {
uint256 sourceToDestPrecision =
IPriceFeeds(priceFeeds).queryPrecision(sourceTokenAddress, destTokenAddress);
if (sourceToDestPrecision == 0) return maxSourceTokenAmount;
/// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.
uint256 expectedRate =
internalExpectedRate(
sourceTokenAddress,
destTokenAddress,
maxSourceTokenAmount,
sovrynSwapContractRegistryAddress
);
/// Compute the source tokens needed to get the required amount with the worst case rate.
estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(
expectedRate
);
/// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.
/// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000
uint256 buffer = estimatedSourceAmount.div(1000);
if (buffer > sourceBuffer) buffer = sourceBuffer;
estimatedSourceAmount = estimatedSourceAmount.add(buffer);
/// Never spend more than the maximum.
if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)
return maxSourceTokenAmount;
}
⤾ overrides ISwapsImpl.internalExpectedRate
Get the expected rate for 1 source token when exchanging the given amount of source tokens. *
function internalExpectedRate(address sourceTokenAddress, address destTokenAddress, uint256 sourceTokenAmount, address sovrynSwapContractRegistryAddress) public view
returns(uint256)
Arguments
Name | Type | Description |
---|---|---|
sourceTokenAddress | address | The address of the source token contract. |
destTokenAddress | address | The address of the destination token contract. |
sourceTokenAmount | uint256 | The amount of source tokens to get the rate for. |
sovrynSwapContractRegistryAddress | address |
Source Code
function internalExpectedRate(
address sourceTokenAddress,
address destTokenAddress,
uint256 sourceTokenAmount,
address sovrynSwapContractRegistryAddress
) public view returns (uint256) {
ISovrynSwapNetwork sovrynSwapNetwork =
getSovrynSwapNetworkContract(sovrynSwapContractRegistryAddress);
IERC20[] memory path =
getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);
/// Is returning the total amount of destination tokens.
uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);
/// Return the rate for 1 token with 18 decimals.
return expectedReturn.mul(10**18).div(sourceTokenAmount);
}
⤾ overrides ISwapsImpl.internalExpectedReturn
Get the expected return amount when exchanging the given amount of source tokens. *
function internalExpectedReturn(address sourceTokenAddress, address destTokenAddress, uint256 sourceTokenAmount, address sovrynSwapContractRegistry, IERC20[] defaultPath) public view
returns(expectedReturn uint256)
Arguments
Name | Type | Description |
---|---|---|
sourceTokenAddress | address | The address of the source token contract. |
destTokenAddress | address | The address of the destination token contract. |
sourceTokenAmount | uint256 | The amount of source tokens to get the return for. |
sovrynSwapContractRegistry | address | The sovryn swap contract reigstry address. |
defaultPath | IERC20[] | The default path for specific pairs. |
Source Code
function internalExpectedReturn(
address sourceTokenAddress,
address destTokenAddress,
uint256 sourceTokenAmount,
address sovrynSwapContractRegistry,
IERC20[] memory defaultPath
) public view returns (uint256 expectedReturn) {
ISovrynSwapNetwork sovrynSwapNetwork =
getSovrynSwapNetworkContract(sovrynSwapContractRegistry);
IERC20[] memory path =
defaultPath.length >= 3
? defaultPath
: sovrynSwapNetwork.conversionPath(
IERC20(sourceTokenAddress),
IERC20(destTokenAddress)
);
/// Is returning the total amount of destination tokens.
expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);
}
function getConversionPath(address sourceTokenAddress, address destTokenAddress, ISovrynSwapNetwork sovrynSwapNetwork) private view
returns(path contract IERC20[])
Arguments
Name | Type | Description |
---|---|---|
sourceTokenAddress | address | |
destTokenAddress | address | |
sovrynSwapNetwork | ISovrynSwapNetwork |
Source Code
function getConversionPath(
address sourceTokenAddress,
address destTokenAddress,
ISovrynSwapNetwork sovrynSwapNetwork
) private view returns (IERC20[] memory path) {
IERC20[] memory _defaultPathConversion =
defaultPathConversion[sourceTokenAddress][destTokenAddress];
/// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.
path = _defaultPathConversion.length >= 3
? _defaultPathConversion
: sovrynSwapNetwork.conversionPath(
IERC20(sourceTokenAddress),
IERC20(destTokenAddress)
);
}
- Address
- Administered
- AdminRole
- AdvancedToken
- AdvancedTokenStorage
- Affiliates
- AffiliatesEvents
- ApprovalReceiver
- BProPriceFeed
- CheckpointsShared
- Constants
- Context
- DevelopmentFund
- DummyContract
- EnumerableAddressSet
- EnumerableBytes32Set
- EnumerableBytes4Set
- ERC20
- ERC20Detailed
- ErrorDecoder
- Escrow
- EscrowReward
- FeedsLike
- FeesEvents
- FeeSharingCollector
- FeeSharingCollectorProxy
- FeeSharingCollectorStorage
- FeesHelper
- FourYearVesting
- FourYearVestingFactory
- FourYearVestingLogic
- FourYearVestingStorage
- GenericTokenSender
- GovernorAlpha
- GovernorVault
- IApproveAndCall
- IChai
- IContractRegistry
- IConverterAMM
- IERC1820Registry
- IERC20_
- IERC20
- IERC777
- IERC777Recipient
- IERC777Sender
- IFeeSharingCollector
- IFourYearVesting
- IFourYearVestingFactory
- IFunctionsList
- ILiquidityMining
- ILiquidityPoolV1Converter
- ILoanPool
- ILoanToken
- ILoanTokenLogicBeacon
- ILoanTokenLogicModules
- ILoanTokenLogicProxy
- ILoanTokenModules
- ILoanTokenWRBTC
- ILockedSOV
- IMoCState
- IModulesProxyRegistry
- Initializable
- InterestUser
- IPot
- IPriceFeeds
- IPriceFeedsExt
- IProtocol
- IRSKOracle
- ISovryn
- ISovrynSwapNetwork
- IStaking
- ISwapsImpl
- ITeamVesting
- ITimelock
- IV1PoolOracle
- IVesting
- IVestingFactory
- IVestingRegistry
- IWrbtc
- IWrbtcERC20
- LenderInterestStruct
- LiquidationHelper
- LiquidityMining
- LiquidityMiningConfigToken
- LiquidityMiningProxy
- LiquidityMiningStorage
- LoanClosingsEvents
- LoanClosingsLiquidation
- LoanClosingsRollover
- LoanClosingsShared
- LoanClosingsWith
- LoanClosingsWithoutInvariantCheck
- LoanInterestStruct
- LoanMaintenance
- LoanMaintenanceEvents
- LoanOpenings
- LoanOpeningsEvents
- LoanParamsStruct
- LoanSettings
- LoanSettingsEvents
- LoanStruct
- LoanToken
- LoanTokenBase
- LoanTokenLogicBeacon
- LoanTokenLogicLM
- LoanTokenLogicProxy
- LoanTokenLogicStandard
- LoanTokenLogicStorage
- LoanTokenLogicWrbtc
- LoanTokenSettingsLowerAdmin
- LockedSOV
- MarginTradeStructHelpers
- Medianizer
- ModuleCommonFunctionalities
- ModulesCommonEvents
- ModulesProxy
- ModulesProxyRegistry
- MultiSigKeyHolders
- MultiSigWallet
- Mutex
- Objects
- OrderStruct
- OrigingVestingCreator
- OriginInvestorsClaim
- Ownable
- Pausable
- PausableOz
- PreviousLoanToken
- PreviousLoanTokenSettingsLowerAdmin
- PriceFeedRSKOracle
- PriceFeeds
- PriceFeedsLocal
- PriceFeedsMoC
- PriceFeedV1PoolOracle
- ProtocolAffiliatesInterface
- ProtocolLike
- ProtocolSettings
- ProtocolSettingsEvents
- ProtocolSettingsLike
- ProtocolSwapExternalInterface
- ProtocolTokenUser
- Proxy
- ProxyOwnable
- ReentrancyGuard
- RewardHelper
- RSKAddrValidator
- SafeERC20
- SafeMath
- SafeMath96
- setGet
- SharedReentrancyGuard
- SignedSafeMath
- SOV
- sovrynProtocol
- StakingAdminModule
- StakingGovernanceModule
- StakingInterface
- StakingProxy
- StakingRewards
- StakingRewardsProxy
- StakingRewardsStorage
- StakingShared
- StakingStakeModule
- StakingStorageModule
- StakingStorageShared
- StakingVestingModule
- StakingWithdrawModule
- State
- SwapsEvents
- SwapsExternal
- SwapsImplLocal
- SwapsImplSovrynSwap
- SwapsUser
- TeamVesting
- Timelock
- TimelockHarness
- TimelockInterface
- TokenSender
- UpgradableProxy
- USDTPriceFeed
- Utils
- VaultController
- Vesting
- VestingCreator
- VestingFactory
- VestingLogic
- VestingRegistry
- VestingRegistry2
- VestingRegistry3
- VestingRegistryLogic
- VestingRegistryProxy
- VestingRegistryStorage
- VestingStorage
- WeightedStakingModule
- WRBTC