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

Gas Tokens in Bridges #2523

Merged
merged 3 commits into from
Mar 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions contracts/asset-proxy/CHANGELOG.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
{
"note": "Change names of `ERC20BridgeTransfer` args to be less ambiguous.",
"pr": 2524
},
{
"note": "Added `MixinGasToken` allowing Gas Tokens to be freed",
"pr": 2523
}
]
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,16 @@ import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "../interfaces/IERC20Bridge.sol";
import "../interfaces/ICurve.sol";
import "./MixinGasToken.sol";


// solhint-disable not-rely-on-time
// solhint-disable space-after-comma
contract CurveBridge is
IERC20Bridge,
IWallet,
DeploymentConstants
DeploymentConstants,
MixinGasToken
{
struct CurveBridgeData {
address curveAddress;
Expand All @@ -60,6 +62,7 @@ contract CurveBridge is
bytes calldata bridgeData
)
external
freesGasTokensFromCollector
returns (bytes4 success)
{
// Decode the bridge data to get the Curve metadata.
Expand Down
55 changes: 55 additions & 0 deletions contracts/asset-proxy/contracts/src/bridges/MixinGasToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*

Copyright 2019 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.5.16;

import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "../interfaces/IGasToken.sol";


contract MixinGasToken is
DeploymentConstants
{

/// @dev Frees gas tokens based on the amount of gas consumed in the function
modifier freesGasTokens {
uint256 gasBefore = gasleft();
_;
IGasToken gst = IGasToken(_getGstAddress());
if (address(gst) != address(0)) {
// (gasUsed + FREE_BASE) / (2 * REIMBURSE - FREE_TOKEN)
// 14154 24000 6870
uint256 value = (gasBefore - gasleft() + 14154) / 41130;
Copy link
Contributor

Choose a reason for hiding this comment

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

This tries to refund the entire amount of gas consumed, right? Maybe we should just try to refund half. I believe a quirk of the EVM is that refunds are capped at half the gas consumed, so any excess might be wasted.

Copy link
Member Author

@dekz dekz Mar 26, 2020

Choose a reason for hiding this comment

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

Yes this calculation gets us to maximum efficiency. You can also play with the calculator (https://gastoken.io/) to confirm.

gasUsed = 2,000,000
value = 48 =  (gasUsed + 14154) / 41130 

SELFDESTRUCT = -24000 (refund)
SELFDESTRUCT_COST = 700 (CALL) + 5000 (SUICIDE)
refund = -878,400 = SELFDESTRUCT * 48 + SELFDESTRUCT_COST * 48


newGasUsed = 1,121,600 > gasUsed * 0.5

note: also a bit of book keeping w.r.t balance updates is excluded

gst.freeUpTo(value);
dekz marked this conversation as resolved.
Show resolved Hide resolved
}
}

/// @dev Frees gas tokens using the balance of `from`. Amount freed is based
/// on the gas consumed in the function
modifier freesGasTokensFromCollector() {
uint256 gasBefore = gasleft();
_;
IGasToken gst = IGasToken(_getGstAddress());
if (address(gst) != address(0)) {
// (gasUsed + FREE_BASE) / (2 * REIMBURSE - FREE_TOKEN)
// 14154 24000 6870
uint256 value = (gasBefore - gasleft() + 14154) / 41130;
dekz marked this conversation as resolved.
Show resolved Hide resolved
gst.freeFromUpTo(_getGstCollectorAddress(), value);
}
}
}
40 changes: 40 additions & 0 deletions contracts/asset-proxy/contracts/src/interfaces/IGasToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
Copyright 2019 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.5.15;

import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";


contract IGasToken is IERC20Token {

/// @dev Frees up to `value` sub-tokens
/// @param value The amount of tokens to free
/// @return How many tokens were freed
function freeUpTo(uint256 value) external returns (uint256 freed);

/// @dev Frees up to `value` sub-tokens owned by `from`
/// @param from The owner of tokens to spend
/// @param value The amount of tokens to free
/// @return How many tokens were freed
function freeFromUpTo(address from, uint256 value) external returns (uint256 freed);

/// @dev Mints `value` amount of tokens
/// @param value The amount of tokens to mint
function mint(uint256 value) external;
}
2 changes: 1 addition & 1 deletion contracts/asset-proxy/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
},
"config": {
"abis": "./test/generated-artifacts/@(ChaiBridge|CurveBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestChaiBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json",
"abis": "./test/generated-artifacts/@(ChaiBridge|CurveBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MultiAssetProxy|Ownable|StaticCallProxy|TestChaiBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
},
"repository": {
Expand Down
4 changes: 4 additions & 0 deletions contracts/asset-proxy/src/artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@ import * as IDydx from '../generated-artifacts/IDydx.json';
import * as IDydxBridge from '../generated-artifacts/IDydxBridge.json';
import * as IERC20Bridge from '../generated-artifacts/IERC20Bridge.json';
import * as IEth2Dai from '../generated-artifacts/IEth2Dai.json';
import * as IGasToken from '../generated-artifacts/IGasToken.json';
import * as IKyberNetworkProxy from '../generated-artifacts/IKyberNetworkProxy.json';
import * as IUniswapExchange from '../generated-artifacts/IUniswapExchange.json';
import * as IUniswapExchangeFactory from '../generated-artifacts/IUniswapExchangeFactory.json';
import * as KyberBridge from '../generated-artifacts/KyberBridge.json';
import * as MixinAssetProxyDispatcher from '../generated-artifacts/MixinAssetProxyDispatcher.json';
import * as MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json';
import * as MixinGasToken from '../generated-artifacts/MixinGasToken.json';
import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json';
import * as Ownable from '../generated-artifacts/Ownable.json';
import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json';
Expand All @@ -55,6 +57,7 @@ export const artifacts = {
DydxBridge: DydxBridge as ContractArtifact,
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
KyberBridge: KyberBridge as ContractArtifact,
MixinGasToken: MixinGasToken as ContractArtifact,
UniswapBridge: UniswapBridge as ContractArtifact,
IAssetData: IAssetData as ContractArtifact,
IAssetProxy: IAssetProxy as ContractArtifact,
Expand All @@ -66,6 +69,7 @@ export const artifacts = {
IDydxBridge: IDydxBridge as ContractArtifact,
IERC20Bridge: IERC20Bridge as ContractArtifact,
IEth2Dai: IEth2Dai as ContractArtifact,
IGasToken: IGasToken as ContractArtifact,
IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact,
IUniswapExchange: IUniswapExchange as ContractArtifact,
IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact,
Expand Down
2 changes: 2 additions & 0 deletions contracts/asset-proxy/src/wrappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ export * from '../generated-wrappers/i_dydx';
export * from '../generated-wrappers/i_dydx_bridge';
export * from '../generated-wrappers/i_erc20_bridge';
export * from '../generated-wrappers/i_eth2_dai';
export * from '../generated-wrappers/i_gas_token';
export * from '../generated-wrappers/i_kyber_network_proxy';
export * from '../generated-wrappers/i_uniswap_exchange';
export * from '../generated-wrappers/i_uniswap_exchange_factory';
export * from '../generated-wrappers/kyber_bridge';
export * from '../generated-wrappers/mixin_asset_proxy_dispatcher';
export * from '../generated-wrappers/mixin_authorizable';
export * from '../generated-wrappers/mixin_gas_token';
export * from '../generated-wrappers/multi_asset_proxy';
export * from '../generated-wrappers/ownable';
export * from '../generated-wrappers/static_call_proxy';
Expand Down
4 changes: 4 additions & 0 deletions contracts/asset-proxy/test/artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@ import * as IDydx from '../test/generated-artifacts/IDydx.json';
import * as IDydxBridge from '../test/generated-artifacts/IDydxBridge.json';
import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json';
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
import * as IGasToken from '../test/generated-artifacts/IGasToken.json';
import * as IKyberNetworkProxy from '../test/generated-artifacts/IKyberNetworkProxy.json';
import * as IUniswapExchange from '../test/generated-artifacts/IUniswapExchange.json';
import * as IUniswapExchangeFactory from '../test/generated-artifacts/IUniswapExchangeFactory.json';
import * as KyberBridge from '../test/generated-artifacts/KyberBridge.json';
import * as MixinAssetProxyDispatcher from '../test/generated-artifacts/MixinAssetProxyDispatcher.json';
import * as MixinAuthorizable from '../test/generated-artifacts/MixinAuthorizable.json';
import * as MixinGasToken from '../test/generated-artifacts/MixinGasToken.json';
import * as MultiAssetProxy from '../test/generated-artifacts/MultiAssetProxy.json';
import * as Ownable from '../test/generated-artifacts/Ownable.json';
import * as StaticCallProxy from '../test/generated-artifacts/StaticCallProxy.json';
Expand All @@ -55,6 +57,7 @@ export const artifacts = {
DydxBridge: DydxBridge as ContractArtifact,
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
KyberBridge: KyberBridge as ContractArtifact,
MixinGasToken: MixinGasToken as ContractArtifact,
UniswapBridge: UniswapBridge as ContractArtifact,
IAssetData: IAssetData as ContractArtifact,
IAssetProxy: IAssetProxy as ContractArtifact,
Expand All @@ -66,6 +69,7 @@ export const artifacts = {
IDydxBridge: IDydxBridge as ContractArtifact,
IERC20Bridge: IERC20Bridge as ContractArtifact,
IEth2Dai: IEth2Dai as ContractArtifact,
IGasToken: IGasToken as ContractArtifact,
IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact,
IUniswapExchange: IUniswapExchange as ContractArtifact,
IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact,
Expand Down
2 changes: 2 additions & 0 deletions contracts/asset-proxy/test/wrappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ export * from '../test/generated-wrappers/i_dydx';
export * from '../test/generated-wrappers/i_dydx_bridge';
export * from '../test/generated-wrappers/i_erc20_bridge';
export * from '../test/generated-wrappers/i_eth2_dai';
export * from '../test/generated-wrappers/i_gas_token';
export * from '../test/generated-wrappers/i_kyber_network_proxy';
export * from '../test/generated-wrappers/i_uniswap_exchange';
export * from '../test/generated-wrappers/i_uniswap_exchange_factory';
export * from '../test/generated-wrappers/kyber_bridge';
export * from '../test/generated-wrappers/mixin_asset_proxy_dispatcher';
export * from '../test/generated-wrappers/mixin_authorizable';
export * from '../test/generated-wrappers/mixin_gas_token';
export * from '../test/generated-wrappers/multi_asset_proxy';
export * from '../test/generated-wrappers/ownable';
export * from '../test/generated-wrappers/static_call_proxy';
Expand Down
4 changes: 4 additions & 0 deletions contracts/asset-proxy/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@
"generated-artifacts/IDydxBridge.json",
"generated-artifacts/IERC20Bridge.json",
"generated-artifacts/IEth2Dai.json",
"generated-artifacts/IGasToken.json",
"generated-artifacts/IKyberNetworkProxy.json",
"generated-artifacts/IUniswapExchange.json",
"generated-artifacts/IUniswapExchangeFactory.json",
"generated-artifacts/KyberBridge.json",
"generated-artifacts/MixinAssetProxyDispatcher.json",
"generated-artifacts/MixinAuthorizable.json",
"generated-artifacts/MixinGasToken.json",
"generated-artifacts/MultiAssetProxy.json",
"generated-artifacts/Ownable.json",
"generated-artifacts/StaticCallProxy.json",
Expand Down Expand Up @@ -56,12 +58,14 @@
"test/generated-artifacts/IDydxBridge.json",
"test/generated-artifacts/IERC20Bridge.json",
"test/generated-artifacts/IEth2Dai.json",
"test/generated-artifacts/IGasToken.json",
"test/generated-artifacts/IKyberNetworkProxy.json",
"test/generated-artifacts/IUniswapExchange.json",
"test/generated-artifacts/IUniswapExchangeFactory.json",
"test/generated-artifacts/KyberBridge.json",
"test/generated-artifacts/MixinAssetProxyDispatcher.json",
"test/generated-artifacts/MixinAuthorizable.json",
"test/generated-artifacts/MixinGasToken.json",
"test/generated-artifacts/MultiAssetProxy.json",
"test/generated-artifacts/Ownable.json",
"test/generated-artifacts/StaticCallProxy.json",
Expand Down
9 changes: 9 additions & 0 deletions contracts/utils/CHANGELOG.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
[
{
"version": "4.5.0",
"changes": [
{
"note": "Added `GST_ADDRESS` and `GST_COLLECTOR_ADDRESS`",
"pr": 2523
}
]
},
{
"timestamp": 1583220306,
"version": "4.4.3",
Expand Down
28 changes: 28 additions & 0 deletions contracts/utils/contracts/src/DeploymentConstants.sol
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ contract DeploymentConstants {
address constant internal KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// @dev Mainnet address of the dYdX contract.
address constant private DYDX_ADDRESS = 0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e;
/// @dev Mainnet address of the GST2 contract
address constant private GST_ADDRESS = 0x0000000000b3F879cb30FE243b4Dfee438691c04;
/// @dev Mainnet address of the GST Collector
address constant private GST_COLLECTOR_ADDRESS = address(0);
// /// @dev Kovan address of the GST2 contract
// address constant private GST_ADDRESS = address(0);
// /// @dev Kovan address of the GST Collector
// address constant private GST_COLLECTOR_ADDRESS = address(0);

/// @dev Overridable way to get the `KyberNetworkProxy` address.
/// @return kyberAddress The `IKyberNetworkProxy` address.
Expand Down Expand Up @@ -144,4 +152,24 @@ contract DeploymentConstants {
{
return DYDX_ADDRESS;
}

/// @dev An overridable way to retrieve the GST2 contract address.
/// @return gst The GST contract.
function _getGstAddress()
internal
view
returns (address gst)
{
return GST_ADDRESS;
}

/// @dev An overridable way to retrieve the GST Collector address.
/// @return collector The GST collector address.
function _getGstCollectorAddress()
internal
view
returns (address collector)
{
return GST_COLLECTOR_ADDRESS;
}
}