Skip to content
This repository has been archived by the owner on Jul 9, 2021. It is now read-only.

UniswapV2Bridge #2590

Merged
merged 7 commits into from
Jun 5, 2020
Merged

UniswapV2Bridge #2590

merged 7 commits into from
Jun 5, 2020

Conversation

xianny
Copy link
Contributor

@xianny xianny commented May 27, 2020

Description

Implement UniswapV2Bridge contract. Allows us to swap tokens through the UniswapV2 Router.

Testing instructions

Please review unit tests and comment if you think any cases should be added.

Types of changes

  • New feature (non-breaking change which adds functionality)

Checklist:

  • Prefix PR title with [WIP] if necessary.
  • Add tests to cover changes as needed.
  • Update documentation as needed.
  • Add new entries to the relevant CHANGELOG.jsons.

@xianny xianny force-pushed the feat/uniswap-v2 branch from 82ea407 to f38514e Compare June 1, 2020 19:35
@xianny xianny force-pushed the feat/uniswap-v2 branch 2 times, most recently from ba6f7d5 to c375398 Compare June 2, 2020 20:22
@xianny xianny force-pushed the feat/uniswap-v2 branch from c375398 to e9bf474 Compare June 2, 2020 20:22
@xianny xianny requested review from dorothy-zbornak and dekz June 3, 2020 19:34
@xianny xianny changed the title wip: implement uniswapv2 bridge and sampler UniswapV2Bridge Jun 3, 2020
@xianny xianny force-pushed the feat/uniswap-v2 branch from 96785af to 3fcb609 Compare June 3, 2020 19:37
@xianny xianny marked this pull request as ready for review June 3, 2020 19:38
@xianny xianny requested review from abandeali1 and hysz as code owners June 3, 2020 19:38
@xianny xianny removed request for hysz and abandeali1 June 3, 2020 19:38
@coveralls
Copy link

coveralls commented Jun 3, 2020

Coverage Status

Coverage decreased (-0.2%) to 79.588% when pulling 7cc50c8 on feat/uniswap-v2 into 32793cc on development.

state.fromTokenBalance = IERC20Token(state.fromTokenAddress).balanceOf(address(this));

// Grant the Uniswap router an allowance.
LibERC20Token.approve(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a LibERC20Token .approveIfBelow so we keep it as high as possible and only write the state (expensive) if we have to.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also important for USDT and some others, which will fail after the first approve().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okiedokie will switch

block.timestamp
);

state.boughtAmount = amounts[0];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


| amounts | uint[] memory | The input token amount and all subsequent output token amounts.|

https://uniswap.org/docs/v2/smart-contracts/router/#swapexacttokensfortokens

does this mean the first element is amountSold?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah seems like we want the second element here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could also just do state.boughtAmount = router.swapExactTokensForTokens(...)[1].

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops my bad. Looks like we want the second element (last element if more than 2 tokens in the path).

state.fromTokenBalance = IERC20Token(state.fromTokenAddress).balanceOf(address(this));

// Grant the Uniswap router an allowance.
LibERC20Token.approve(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also important for USDT and some others, which will fail after the first approve().

block.timestamp
);

state.boughtAmount = amounts[0];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah seems like we want the second element here.

block.timestamp
);

state.boughtAmount = amounts[0];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could also just do state.boughtAmount = router.swapExactTokensForTokens(...)[1].

IWallet,
DeploymentConstants
{
using LibAddressArray for address[];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think you don't need this.

Comment on lines 89 to 91
address[] memory path = new address[](2);
path[0] = state.fromTokenAddress;
path[1] = toTokenAddress;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought there would be multihop support out of the gate? Should we just encode an address[] path as the bridge data?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ya let's do that. I'll change it.

@xianny xianny requested review from dekz and dorothy-zbornak June 5, 2020 03:05
@xianny xianny force-pushed the feat/uniswap-v2 branch from 1bf86a1 to d37e963 Compare June 5, 2020 03:14
Copy link
Contributor

@dorothy-zbornak dorothy-zbornak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small nits, but otherwise great job on this!
👁️      👁️
     :nose:
     :lips:


// Decode the bridge data to get the `fromTokenAddress`.
// solhint-disable indent
(state.path) = abi.decode(bridgeData, (address[]));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can just do state.path = ... here?

IWallet,
DeploymentConstants
{

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for empty line here (this rule is confusing, I know).

Comment on lines 73 to 74
require(state.path.length >= 2, "PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
require(state.path[state.path.length - 1] == toTokenAddress, "LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
require(state.path.length >= 2, "PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
require(state.path[state.path.length - 1] == toTokenAddress, "LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN");
require(state.path.length >= 2, "UniswapV2Bridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
require(state.path[state.path.length - 1] == toTokenAddress, "UniswapV2Bridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN");

struct TransferState {
address[] path;
uint256 fromTokenBalance;
uint256 boughtAmount;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No real point to this field since we can just access amounts[amounts.length-1].

function createTransferFromOpts(opts?: Partial<TransferFromOpts>): TransferFromOpts {
const amount = getRandomInteger(1, TO_TOKEN_BASE.times(100));
return {
tokenAddressesPath: Array(2).fill(constants.NULL_ADDRESS),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where has this pattern been all my life.

@xianny xianny merged commit 7127f54 into development Jun 5, 2020
@xianny xianny deleted the feat/uniswap-v2 branch June 5, 2020 18:56
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants