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

DexForwarderBridge #2525

Merged
merged 7 commits into from
Mar 27, 2020
Merged

Conversation

dorothy-zbornak
Copy link
Contributor

@dorothy-zbornak dorothy-zbornak commented Mar 18, 2020

Description

We can reduce swap protocol fees by unifying bridge orders under a single fill. We can take advantage of the fact that DEX bridges are permissionless. This PR introduces the DexForwarderBridge bridge, which essentially performs market fills over a sequence of bridge calls.

Testing instructions

Types of changes

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.

@dorothy-zbornak dorothy-zbornak force-pushed the feat/bridge/DexForwarderBridge branch 2 times, most recently from 75b8bf7 to ade380d Compare March 18, 2020 20:26
@dorothy-zbornak dorothy-zbornak force-pushed the feat/bridge/DexForwarderBridge branch 2 times, most recently from 5bf0ead to ab409f4 Compare March 26, 2020 05:48
@dorothy-zbornak dorothy-zbornak marked this pull request as ready for review March 26, 2020 05:48

for (uint256 i = 0; i < state.calls.length; ++i) {
// Stop if the we've sold all our input tokens.
if (state.totalInputTokenSold >= state.initialInputTokenBalance) {
Copy link
Contributor Author

@dorothy-zbornak dorothy-zbornak Mar 26, 2020

Choose a reason for hiding this comment

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

I had a version where we also could stop based on output tokens bought (market buy), but ran into some issues:

  • we can't use amount because we underestimate this value in AS w/ bridgeSlippage
  • this contract can end up with a balance of input tokens, so would we refund those to to?
  • I'm not sure this is the same behavior you would get if not using the DFB (individual bridge orders)
  • Not sure any of this is even worth it.

Copy link
Contributor

Choose a reason for hiding this comment

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

yeah I think this is probably cleaner

@dorothy-zbornak dorothy-zbornak requested a review from dekz March 26, 2020 05:59
@coveralls
Copy link

coveralls commented Mar 26, 2020

Coverage Status

Coverage increased (+0.2%) to 79.739% when pulling c5a6e49 on feat/bridge/DexForwarderBridge into 277dbac on development.

Copy link
Contributor

@moodlezoup moodlezoup left a comment

Choose a reason for hiding this comment

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

good stuff, just some typos/nits

state.calls
) = abi.decode(bridgeData, (address, BridgeCall[]));

state.initialInputTokenBalance = IERC20Token(state.inputToken).balanceOf(address(this));
Copy link
Contributor

Choose a reason for hiding this comment

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

might as well use LibERC20Token for balances

Copy link
Contributor Author

Choose a reason for hiding this comment

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

LibERC20Token.balanceOf() swallows reverts. Not my jam.

call.outputTokenAmount
);

(bool didSucceed, ) = address(this)
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we should decode the return data here and check that it equals BRIDGE_SUCCESS?

Copy link
Contributor Author

@dorothy-zbornak dorothy-zbornak Mar 26, 2020

Choose a reason for hiding this comment

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

executeBridgeCall() doesn't return anything. It just succeeds or reverts.


for (uint256 i = 0; i < state.calls.length; ++i) {
// Stop if the we've sold all our input tokens.
if (state.totalInputTokenSold >= state.initialInputTokenBalance) {
Copy link
Contributor

Choose a reason for hiding this comment

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

yeah I think this is probably cleaner

Comment on lines 3 to 12
export interface DexForwaderBridgeCall {
target: string;
inputTokenAmount: BigNumber;
outputTokenAmount: BigNumber;
bridgeData: string;
}

export interface DexForwaderBridgeData {
inputToken: string;
calls: DexForwaderBridgeCall[];
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
export interface DexForwaderBridgeCall {
target: string;
inputTokenAmount: BigNumber;
outputTokenAmount: BigNumber;
bridgeData: string;
}
export interface DexForwaderBridgeData {
inputToken: string;
calls: DexForwaderBridgeCall[];
export interface DexForwarderBridgeCall {
target: string;
inputTokenAmount: BigNumber;
outputTokenAmount: BigNumber;
bridgeData: string;
}
export interface DexForwarderBridgeData {
inputToken: string;
calls: DexForwarderBridgeCall[];

Copy link
Contributor Author

Choose a reason for hiding this comment

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

help me jesus

// Revert if we were not able to sell our entire input token balance.
require(
state.totalInputTokenSold >= state.initialInputTokenBalance,
"DexForwaderBridge/INCOMPLETE_FILL"
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
"DexForwaderBridge/INCOMPLETE_FILL"
"DexForwarderBridge/INCOMPLETE_FILL"

Copy link
Member

Choose a reason for hiding this comment

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

and a few more 😆


if (!didSucceed) {
// Log errors.
emit DexForwarderBridgeCallFailed(
Copy link
Member

Choose a reason for hiding this comment

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

Is this just for internal data gathering/insights?

AS makes heavy use of FillOrKill so the only case where it'd reasonably be emitted is when succeed with enough slippage/backup path?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, that's what I'm thinking. These won't be going through fillOrder() or the ERC20BridgeProxy so it's a less obvious path to detecting them. Maybe it's not worth it, though, since the bridge itself can revert if not enough input tokens are sold. We'd have to rely on traces for those situations (and the market fn failing).

Now I'm leaning towards nixing this event.

@dorothy-zbornak dorothy-zbornak force-pushed the feat/bridge/DexForwarderBridge branch from 2e5bf37 to 02e47c7 Compare March 27, 2020 20:35
@dorothy-zbornak dorothy-zbornak force-pushed the feat/bridge/DexForwarderBridge branch from 02e47c7 to a509af2 Compare March 27, 2020 20:40
@dorothy-zbornak dorothy-zbornak merged commit bf00e67 into development Mar 27, 2020
@dorothy-zbornak dorothy-zbornak deleted the feat/bridge/DexForwarderBridge branch March 27, 2020 21:44
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.

5 participants