GithubHelp home page GithubHelp logo

uniswap / v1-contracts Goto Github PK

View Code? Open in Web Editor NEW
484.0 26.0 322.0 216 KB

🐍Uniswap V1 smart contracts

License: GNU General Public License v3.0

Python 100.00%
vyper decentralized-exchange ethereum smart-contracts cryptocurrency market-maker erc20

v1-contracts's Introduction

Installation:

Requires Python 3

  1. Clone Uniswap
$ git clone https://github.com/Uniswap/contracts-vyper
$ cd contracts-vyper
  1. Setup virtual environment
$ pip3 install virtualenv
$ virtualenv -p python3 env
$ source env/bin/activate
  1. Install dependencies
pip install -r requirements.txt
  1. (Optional) Switch Vyper compiler to version used in Uniswap verification
cd vyper
git reset --hard 35038d20bd9946a35261c4c4fbcb27fe61e65f78
cd ..
  1. Run tests
$ pytest -v tests/

v1-contracts's People

Contributors

clesaege avatar haydenadams avatar kaibakker avatar yzhang90 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

v1-contracts's Issues

Missing ETH after failed attempt to add additional funds to UBT/ETH Liquidity pool

I attempted to add what is for me a fairly substantial amount of ETH and UBT to the v1 liquidity pool (which I already had a small position on). The tx ultimately ended up failing, and though the UBT still remains in my wallet, the 0.5791 ETH portion has disappeared from my wallet and doesn't seem to be accessible. There is a Retry Transaction button at the bottom of the failed TX but I am afraid to push it for fear of losing even more Ethereum.

How would I go about recovering the Ethereum that has seemingly been lost to this contract or is that even possible?

Here is the tx on the blockchain for reference.
https://etherscan.io/tx/0x178a1b9b783b908019d39ee2da7e4df4f3f1bd06a490d3a937a713572f6a6224

ABI removeLiquidity return values name collision

In the Exchange Interface ABI json both return values from the function removeLiquidity are named out. When I generate typescript types from the ABI with typechain I get an error: error TS2300: Duplicate identifier 'out'.

Please rename them with different names.

Return bool in `setup(token_addr: address) -> bool` is uncessary

The function call in vyper is compiled to [assert, call[...]], which means that any exceptions occured in the setup function will propagate to its caller (in this case, createExchange). There is no need to return True in the setup function and assert it in the createExchange.

Support for latest Vyper compiler

Hello!

First of all congrats for Uniswap, amazing project!

I'm starting a project that will be using Uniswap, and I've updated both contracts so they compile with latest Vyper version. Before creating a PR, I'd like to first confirm if this will be a relevant change for the project, and if yes what other critical parts of the project will need to be updated accordingly besides contracts source?

Thanks!

vNext Feature Request: Moving Average Price Feed Data

A dapp wanting to know the approximate price of an asset can get the current exchange rate from Uniswap pretty easily. The problem is that someone can move the price reported by Uniswap at relatively little cost (0.6%) by sandwiching the price read transaction with a large Uniswap buy and a large Uniswap sell. This will cause the price to move up dramatically, followed by the price read, followed by restoring the price to its original level.

In order for Uniswap to be used as an Oracle, it needs to be sufficiently expensive to manipulate the current price reported by Uniswap. To achieve this, we can do a simple moving average or an exponential moving average of the price over time that can then be queried externally. This price will be "delayed" a bit, in the sense that it is more of a rough guess of about what the price is right now rather than an exact value, but for many tools that need an oracle this is sufficient. Manipulating it becomes much more expensive because in order to manipulate the price you must do so you must fight against arbitrageurs who are arbitraging your manipulated price back into line with everything else.

1 Hour Exponential Moving Average (EMA)

Every time someone buys or sells some particular asset, the EMA is updated like so:

const secondsSinceLastUpdate = now() - this.lastUpdateTimestamp
const historicWeight = Max(3600 - secondsSinceLastUpdate, 0)
const currentWeight = Min(secondsSinceLastUpdate, 3600)
this.ema = this.ema * historicWeight / 3600 + getCurrentPrice() * currentWeight / 3600
this.lastUpdateTimestamp = now()
executeTrade(...)

You would apply the same basic formula, just without the state updates or the executeTrade line anytime someone queried for the EMA.

Simple Moving Average (SMA) With 1 Hour Buckets

Every time someone buys or sells some particular asset, the SMA is updated like so:

const secondsSinceLastUpdate = now() - this.lastUpdateTimestamp
const secondsSinceBeginningOfHour = now() - now() % 3600
const historicWeight = Max(secondsSinceBeginningOfHour - secondsSinceLastUpdate, 0)
const currentWeight = Max(secondsSinceLastUpdate, secondsSinceBeginningOfHour)
this.sma = this.sma * historicWeight / secondsSinceBeginningOfHour + getCurrentPrice() * currentWeight / secondsSinceBeginningOfHour
this.lastUpdateTimestamp = now()
executeTrade(...)

Note: The current bucket should probably not be used for an oracle because at the beginning of the hour it is very cheap to manipulate, compared to the end of the hour.

The SMA version has the advantage of the cost of manipulation being higher because there are no points during the time period where manipulation is cheaper, it is expensive anytime during the hour. However, it has the disadvantage of being only reliable for historic hours (previous period), since the current hour will start off heavily manipulable.

The EMA version has the advantage of being continuous, it is always up to date and able to be used as an oracle at any time, and will trail the actual price closer than SMA. However, it has the disadvantage of manipulation being notably cheaper if done during the most recent minutes. For example, if you can control the price for a couple of blocks (e.g. buying blocks) you can have a fairly large impact on the EMA feed price since it weighs recent prices heavier than historic prices.

What will happen in case of REVERT inside DELEGATE_CALL?

I see a lot of BAD JUMP DESTINATION transactions here: https://etherscan.io/address/0x3958b4ec427f8fa24eb60f42821760e88d485f7f

SNX token calls tokenFallback on Uniswap contract in the middle of exchange and it seems Uniswap proxy handles this problem in a wrong way.

Proxy code is:

CALLDATASIZE
PUSH1 0x00
PUSH1 0x00
CALLDATACOPY
PUSH2 0x1000
PUSH1 0x00
CALLDATASIZE
PUSH1 0x00
PUSH20 0x2157a7894439191e520825fe9399ab8655e0f708
GAS
DELEGATE_CALL
ISZERO
PC
JUMPI
PUSH2 0x1000
PUSH1 0x00
RETURN

What does the latest part after DELEGATE_CALL means can anyone describe what should happen after DELEGATE_CALL reverts internally?

It seems Uniswap exchange called by another smart contract will eat all of its gas.

getTokenToTokenPrice

Hi everyone!

What about the idea to extend the exchange contract with

getTokenToTokenPrice

function?

The problem is, that if i try to get price for token to token i have to use:

getEthToTokenInputPrice
and
getTokenToEthInputPrice

that means the fees would be charged twice, but in the function getTokenToTokenPrice only once..

Use an oracle to profit from arbitrage

I love the idea of Uniswap and have been using it myself as a liquidity provider. However, at the moment, it seems that most of the profits are captured primarily by arbitrageurs.

The current state without an oracle:

  1. There are 365.31 ETH and 34783.06 DAI in the contract, price to buy 1 ETH on Uniswap is 94.67
  2. The market price of ETH moves to 110
  3. Uniswap doesn't know this so the price to buy 1 ETH is still 94.67
  4. Someone sees this, executes an arbitrage and brings the price on Uniswap up to 110
  5. Liquidity providers have made only the 0.3% fee from the trading volume and nothing else, missing on an opportunity to sell at a higher price.

The scenario with a price oracle would be:

  1. There are 365.31 ETH and 34783.06 DAI in the contract, price to buy 1 ETH on Uniswap is 94.67
  2. The market price of ETH moves to 110
  3. Uniswap knows this from a price oracle and limits the best possible buy price to at most 2% below the current market price, resulting in 107.8 (110*0.98) for 1 ETH.
  4. This is still profitable for arbitrageurs so they still execute the trade and bring the price on Uniswap up to 110.
  5. However, this time, liquidity providers have made a profit not only from the 0.3% fee but also from the cheaply acquired Ethereum sold at a higher price.

The only function of a price oracle would be to ensure that the best possible arbitrage offered by Uniswap is never more than 2% relative to the market price to allow liquidity providers to capture value from price movements. The rest of the contract would still work the same way. Aside from introducing a point of centralization with an oracle and potentially higher gas fees, are there any other downsides with this approach?

Market limit orders for Uniswap

Reasoning & Overview

I'm proposing market limit orders that would allow users to purchase all the tokens up to a certain price point. This can be implemented as a wrapper contract for V1 and might make sense to be a core function for V2.

Currently, Uniswap lets users trade based on volume and enforce minimum returns on the volume of their trade. This trade type would be the counterpart and have the volume dynamically set based on the price Uniswap is offering to the user.

Implementation Without Fees

Eth to Token Market Limit:

ethToTokenSwapLimit(price_limit: uint256) -> uint256:
    price_accuracy: uint256 = 10**9  #9 decimals of price precision
    start_input_reserve: uint256 = self.balance
    start_output_reserve: uint256 = self.token.balanceOf(self)
    invariant: uint256 = start_input_reserve * start_output_reserve
    
    target_input_reserve: uint256 = sqrt(invariant * target_price / price_accuracy)
    trade_volume: uint256 = target_input_reserve - start_input_reserve
    self.ethToTokenInput(trade_volume, 1, -1, msg.sender, msg.sender)

This method will purchase all the available tokens such that the cost of the last wei of token is <= price_limit.

Dealing with Uniswap's Fees

This works perfectly fine before you introduce fees to the system. Due to the nature of how Uniswap's pricing mechanism works, I am having a hard time predicting token cost with the introduction of fees. For example, simply setting price_limit to price_limit * 997/1000 is too conservative a strategy, resulting in the cost of the last wei of token being well under the price_limit.

It is my hope that someone smarter than me will be able to make this formula work with fees in the way Uniswap has implemented them.

Error while calling `addLiquidity` in Ganache: "VM Exception while processing transaction: invalid JUMP"

Hey,

This issue is similar to #25 except I'm using Etherlime instead of Truffle. Note that the solution applied in #25 (initial ETH value above 1000000000 wei) does not apply in my case.

In a nutshell I want to test a contract that will interact directly with Uniswap. My contract is written in Solidity and I want to do my tests on Ganache. I've imported the abi and bytecodes of the factory and the exchange from the Github repository and put them in UniswapFactory.json and UniswapExchange.json files. The 2 files have the same format as if they had been compiled by Etherlime (i.e. the json looks like {"contractName": , "abi": , "bytecode": } .

My test file is

const etherlime = require('etherlime');
const UniswapFactory = require("../contracts/test/compiled/UniswapFactory");
const UniswapExchange = require("../contracts/test/compiled/UniswapExchange");
const ERC20 = require("../build/TestERC20");
const TestManager = require("../utils/test-manager");

describe("Test Uniswap", function () {
    this.timeout(1000000);
    const manager = new TestManager(accounts, 'ganache');
    let infrastructure = accounts[0].signer;

   describe("Add liquidity ", () => {
        it('should create a liquidity pool with an initial liquidity', async () => {
            deployer = manager.newDeployer();
            // create factory
            const uniswapFactory = await deployer.deploy(UniswapFactory);
            const uniswapTemplateExchange = await deployer.deploy(UniswapExchange);
            await uniswapFactory.initializeFactory(uniswapTemplateExchange.contractAddress); 
            const erc20 = await deployer.deploy(ERC20, {}, [infrastructure.address], 1000, 18); 
            // create liquidity pool
            await uniswapFactory.from(infrastructure).createExchange(erc20.contractAddress); 
            const exchangeAddress = await uniswapFactory.getExchange(erc20.contractAddress); 
            const liquidityPool = await etherlime.ContractAt(UniswapExchange, exchangeAddress); 
            // add initial liquidity
            await erc20.from(infrastructure).approve(liquidityPool.contractAddress, 200000000000); 
            const currentBlock = await manager.getCurrentBlock(); 
            await liquidityPool.from(infrastructure).addLiquidity(1, 2000000000, currentBlock + 3000, {value: 2000000000});
        });
    });
}

The addLiquidity call fails with

1) Test Uniswap
       Add liquidity
         should create a liquidity pool with an initial liquidity:
     Error: VM Exception while processing transaction: invalid JUMP at 84f606a3a88732ef1ca37d72c04534e11d86fa43ccafd8759c3920f51b690aae/4398e3a71c988a9a4db928bc819681b95918a3bf:39
      at getResult (node_modules/etherlime/node_modules/ethers/providers/json-rpc-provider.js:40:21)
      at exports.XMLHttpRequest.request.onreadystatechange (node_modules/etherlime/node_modules/ethers/utils/web.js:111:30)
      at exports.XMLHttpRequest.dispatchEvent (node_modules/xmlhttprequest/lib/XMLHttpRequest.js:591:25)
      at setState (node_modules/xmlhttprequest/lib/XMLHttpRequest.js:610:14)
      at IncomingMessage.<anonymous> (node_modules/xmlhttprequest/lib/XMLHttpRequest.js:447:13)
      at endReadableNT (_stream_readable.js:1064:12)
      at _combinedTickCallback (internal/process/next_tick.js:138:11)
      at process._tickDomainCallback (internal/process/next_tick.js:218:9)

Some of the test scenarios failed!

I have of course tested every property of the liquidity pool (token address, factory address, tokenSupply, ERC20 allowance) to make sure the contract is properly initialised before I call addLiquidity, as well as the ETH and ERC20 balance of the infrastructure account to make sure that none of the assert of the addLiquidity method throws.

What am I missing?

Uniswap on Testnet

Hi,
Great work @Uniswap! Tried writing a mail but did not get a response there. Hence, trying to reach out here.

We are interested in integrating Uniswap for our project Nexus Mutual. Just 2 quick questions here:

  1. Which testnet are you guys on?
  2. We are interested in an exchange between ETH and DAI and vice versa. What is the best way to implement this?

ERC-777 token support

As is widely known at this point, Uniswap is not safe to use with ERC-777 tokens (even if you are only using the ERC-20 interface). More broadly speaking, the Uniswap contracts incorrectly assume that the token contract being called will not call out into any third party (potentially trader-controlled) code prior to returning.

Uniswap vNext should address this issue.

getEthToTokenPrice() can not directly call ethToTokenPrice()

When calling ethToTokenPrice from ethToToken, self.balance is updated (i.e, eth is already sent to the contract). As a result, eth_reserve equals to eth_bal - eth_sold.
However, when calling ethToTokenPrice from getEthToTokenPrice, the eth is not sent to the contract. As a result, eth_reserve should equal to eth_bal. That's why getEthToTokenPrice() should not directly call ethToTokenPrice().

One possible fix would be ethToTokenPrice takes eth_sold and eth_reserve as arguments.

`tokenToEth` to be symmetric to `EthToToken`

I would recommend EthToTokenPrice and TokenToEthPrice to be symmetric (so does EthToToken and TokenToEth`)

e.g, Inside ethToTokenPrice, you do not check eth_sold >0. The check is done at the caller side(ethToToken) . Then, you should do the same check in getEthToTokenPrice.
Or you can move the check to ethToTokenPrice and remove the check at ethToToken.

Once you fixed the pattern in ethToToken, TokenToEth should be symmetric.

contracts-vyper instruction

Using instruction for https://github.com/Uniswap/contracts-vyper

install of requirements.txt uses cytoolz, which in turn needs python3-dev

cd vyper
cd: vyper: No such file or directory

git reset --hard 35038d20bd9946a35261c4c4fbcb27fe61e65f78
fatal: Could not parse object '35038d20bd9946a35261c4c4fbcb27fe61e65f78'.

Can't compile contracts on master branch, are other branch contracts okay to test on local testnet?

I am making an app that uses uniswap's contract also. So as I was trying to compile and deploy the master branch contracts on local testnet Ganache, I was constantly facing issues in the compilation. I think it's because of the old vyper language syntax. So I compiled other branch contracts and it compiled smoothly.
I want to ask can I use them for unit testing? Are they okay? Or what other ways are there to compile the old contract?

UIP 1: Optional Permissioned Liquidity Pools

Uniswap Improvement Proposal

UIP 1: Optional Permissioned Liquidity Pools

Simple Summary

A Pool Factory extension to allow creation of pools and token swapping, where participants can have a choice to be compliant with their local or international laws.

Use case 1: Every non-US corporate and institutional liquidity providers (such as crypto hedge funds, market makers, OTC desks) is mandated, by US Government to pay taxes in the US for income received from US sources. To do so, liquidity providers must know the country of residence (but almost never identity) of Uniswap users who generated that income. To do so, such liquidity providers must have a "country of origin" report for all income they receive from liquidity pools.

Use case 2 - most (but not all) corporate and institutional liquidity providers must have an attestation that Uniswap users - specifically makers and takers (payers of the income generated by liquidity providers) were AML'ed by a 3rd party KYC provider such as onFido, Wyre, Jumio, etc. Almost never liquidity providers want an actual identity of a Uniswap user, - as long as there is a name of 3rd party AML provider and an anonymized customer ID behind 100% of the income received by such liquidity provider.

Use case 3 - most (but not all) corporate and institutional Uniswap users who want to swap tokens must have an attestation that their counterparty in Uniswap - were AML'ed by a 3rd party KYC provider such as onFido, Wyre, Jumio, etc. Almost never makers or takers want an actual identity of a Uniswap user, - as long as there is a name of 3rd party KYC provider and an anonymized customer ID behind 100% of the income received by such liquidity provider.

Abstract

This proposal aims to extend Uniwap by adding a new optional feature for users: Know Your Customer (KYC), Anti-Money Laundering (AML), and Combating the Financing of Terrorism (CFT) regulations compliance. This feature will allow individuals and institutions alike to exchange and invest using Uniswap when these regulations apply.

Motivation

There is a huge opportunity for exchanges such as Uniswap to attract individuals and institutions looking for investment opportunities that require to comply with regulations (e.g.: file reports with both the Internal Revenue Service and the U.S. Treasury, pay taxes on capital gains, etc.). Also, it is needed that every potential counterparty also comply with the regulations. This opportunity is very valuable even if they must go through a thorough KYC/AML/CFT process.

Current permissionless liquidity pools do not enforce KYC/AML validations, which is ok, however they prevent certain traders and investors from using Uniswap.

Specification

Pool Factory extension supporting only KYC’ed addresses to add/remove liquidity, swap and send tokens

In the current implementation only one pool can exist for a given token. We propose adding the possibility of having parallel sets of pools. Each pool in a set can only be used by a given smart contract (meaning, a set of pools is defined by the smart contract that can use those pools). The address of this contract is specified when the pool is created, and then all the interactions with those pools must go through that contract. That is: exchanges created this way will check that msg.sender is equal to the proxy address that was used for creating the pool.

If this is supported, then a set of pools could be created so that they can only be used by addresses that went through a KYC/AML process. This can be done by checking that the account possess some KYC/AML token (see next section).

Note: Both approaches can be useful outside of this: Uniswap can use this “Sender address” for more customized pool factories, and this KYCProxy contract can be used as a proxy for any other contract that requires KYC.

image

In this diagram, we can see how the Registry works today, and how this new registry would work. Notice that the old Registry can continue to work, and the existing liquidity pools are still accessible. We have five different scenarios:

  • A.1 A user adds liquidity to the BAT pool through the (current) registry
  • A.2 Users can also interact with pools without using the registry
  • B.1 If the user doesn't specify a Proxy, the call is delegated to the old registry
  • B.2 If the user specifies a Proxy address, the call is delegated to that added, which then uses a pool that only that proxy can call
  • B.3 Proxied pools can't be used by users directly

Wyre for KYC/AML validation

Wyre offers a service for validating KYC/AML information and it can associate this validation to an ethereum account. This is done by depositing a "KYC token" in that account's address. The KYCProxy contract could just check that this token exists for the transaction originator.

By using the Wyre widget, a full customer on-boarding with minimal coding KYC/AML widget can be integrated into Uniswap UI and flow.

Wyre is just one of the many KYC providers that can be plugged into a standard mechanism.

“KYC’ed pools” to be created from Uniswap UI

image

Proposal: Ability to exchange between any token pair in a single Exchange

As I've wrote in my issue #19, for the Liquidity Providers in makes economical sense to add liquidity only if the price ratio of UniSwap contract assets' is more or less stable. For example a pair DAI <-> GUSD would make sense - the liquidity providers would not risk their funds too much, but they could still collect the fees.

Having two exchanges ETH <-> DAI and ETH <-> GUSD does not fix the price fluctuation problem for the liquidity providers, since they will still loose funds when Ether price changes.

I think this is the only alternative to implementing Oracle to update the prices - UniSwap could work very well in trading assets which relative price does not change much.

P.s. I am not sure how the Ether case should be handled in code - it must either have separate handling logic (more complexity) or it must be wrapped to WETH (extra gas).

how to decide min_eth_bought in tokenToTokenInput and the reason to have it

hey, developers of uniswap.
When using uniswap to trade tokenToToken, it turned out hard to decide value of min_eth_bought to pass in. I read contract's source code, if i understand the protocol correctly, there's already min_tokens_bought in tokenToTokenInput which user can use to control their risk against price changes. So my question is why you put min_eth_bought together with min_tokens_bought? What are the consequences if min_eth_bought is removed.

not considering `ERC20.transfer()` returning `false`

It seems to not consider the fact that transfer() and/or transferFrom() of some ERC20 token contracts could return false instead of throwing an exception in case of failure. Note that such a contract is still ERC20-compliant, as throwing an exception is recommended but not mandatory according to the ERC20 standard.

You may want to add the assertion on the return value, like (not sure about the exact syntax):

assert self.token.transfer(msg.sender, tokens)

Add ERC-20 compatibility check when creating a new exchange

Hello,
I have a small suggestion - currently Uniswap has about 2400 exchanges deployed. A few of the tokens (still) do no fully support ERC-20. The worst was BNB, but there are others - PKG, XYO etc.

Maybe it would be a good idea to a do a simple token compatibility test when creating a new exchange:

assert(token.transferFrom(msg.sender, address(this),1))
assert(token.transfer(msg.sender,1))

This small check would prevent people from loosing money.

What do you think? Maybe it is not too late to implement it in V2?

Another Oracle proposal

Hello,

This is a proposal for a radical change, so feel free to close this issue if Oracle solution is not acceptable from the project's standpoint of view.
Also, there are many ways to integrate Oracle, described below is just one of them.

I really liked the idea of UniSwap, but I also came to the conclusion that the UniSwap's price discovery model is just too expensive. Liquidity providers will be getting "punished" by arbitrage traders for every exchange rate shift.
For the liquidity providers not to loose funds there must be enough "end user" trading so that the collected 0.3% fee covers for the losses caused by price movements. However, the bigger the liquidity fund is, the more losses it will suffer from arbitrage.

For example:
We have created Uniswap 1.000 Ether and 100.000 DAI, when Ether price was $100. If Ether price moves to $150, the arbitrage trader will take away $5.000 (around 33 Ether) from the contract's liquidity to bring the price close to the correct one. To compensate for this move, the UniSwap contract needs to trade around $1.700.000, which is almost 10x the contract's total liquidity.

I think using an Oracle would be much cheaper than that.

I have the following proposal:

Create an Oracle contract which would have the following functionality:

  • external updatePrice() function could be called by anyone (we need to figure out what to do with the gas payments, maybe refund the gas to the caller, but then there is a risk of grief attack). This function would initiate an Oraclize call to get the price.
  • the Oracle contract could add/remove Ether balance to/from the Exchange contract to adjust the price ratio of the assets. We need to figure out the initial funding to Oracle contract.
  • Oracle contract would allow Exchange Contract to add/remove Ether funds

The changes to Exchange contract:

  • it would allow Oracle Contract to add/remove Ether
  • when removing liquidity, it would also remove a proportional part of Ether from the Oracle Contract
  • when adding liquidity, it would also add a certain proportional part of Ether to the Oracle Contract. It could use Oracle Contract price to set the correct rate.
  • add a voting mechanism to for the liquidity providers to change the Oracle contract
  • maybe add a voting mechanism to change the trading fee

How important is the `min_liquidity` argument when adding liquidity

Not an issue per say, but wanted to discuss the usefulness of the min_liquidity argument passed in the addLiquidity() function. It seems to me that other than obtaining less % of the liquidity pool than expected, there isn't really much that can happen as the user can always withdraw the tokens they deposited. It also seems to be mainly a concern with newly created pools where the liquidity can change abruptly.

Any potential attacks I am not seeing that the min_liquidity argument protect against? I see why the max_token is important as you might not want all your funds to be deposited if you also do something else with these tokens, but fail to see the practical relevance of the min_liquidity().

truffle tests erroring with "VM Exception while processing transaction: invalid JUMP"

I'm trying to interact with uniswap through a truffle contract written in solidity 0.5.4. I have truffle migrate able to deploy the contract bytecode that is checked into the repo. The abi is giving me issues, but I've worked around that for now (trufflesuite/truffle#1623). I have a test that AFAICT is successfully initializing the contract and setting up an exchange for a test ERC20 token. However, when I try to add liquidity, I get "invalid JUMP".

To ease debugging this, I should probably just push my whole repo up to GitHub, but I wasn't wanting to open source it just yet.

Here are some relevant pieces:

IUniswapExchange.sol

IUniswapFactory.sol

test/uniswap.js:

const assert = require("chai").assert;

const UniswapExchange = artifacts.require("uniswap_exchange");
const IUniswapExchange = artifacts.require("IUniswapExchange");

const UniswapFactory = artifacts.require("uniswap_factory");
const IUniswapFactory = artifacts.require("IUniswapFactory");

const TutorialToken = artifacts.require("TutorialToken");

contract("uniswap_factory", accounts => {

  it("... should be initializable through the interface", async () => {
    await UniswapFactory.new();
    const uniswapFactoryInstance = await IUniswapFactory.at(UniswapFactory.address);

    // TODO: is this right?
    await UniswapExchange.deployed();
    await uniswapFactoryInstance.initializeFactory(UniswapExchange.address);

    const savedExchangeTemplate = await uniswapFactoryInstance.exchangeTemplate();
    assert.equal(savedExchangeTemplate, UniswapExchange.address);

    const tokenCount = await uniswapFactoryInstance.tokenCount();
    assert.equal(tokenCount, 0);
  });

  it("... should have a pool for TutorialToken", async () => {
    await UniswapExchange.deployed();
    await UniswapFactory.deployed();
    const uniswapFactoryInstance = await IUniswapFactory.at(UniswapFactory.address);

    await TutorialToken.deployed();
    // TODO: return value of this is a tx receipt instead of the address like I expected. i'm doing something wrong
    await uniswapFactoryInstance.createExchange(TutorialToken.address);

    const tokenCount = await uniswapFactoryInstance.tokenCount();
    assert.equal(tokenCount, 1);

    const tutorialTokenUniswapAddress = await uniswapFactoryInstance.getExchange(TutorialToken.address);

    const tutorialTokenUniswapInstance = await IUniswapExchange.at(tutorialTokenUniswapAddress);

    const savedTutorialTokenAddress = await tutorialTokenUniswapInstance.tokenAddress();
    assert.equal(savedTutorialTokenAddress, TutorialToken.address);

    const savedFactoryAddress = await tutorialTokenUniswapInstance.factoryAddress();
    assert.equal(savedFactoryAddress, UniswapFactory.address);
  });

  it("... should add some TutorialToken to the Uniswap pool", async () => {
    await UniswapExchange.deployed();
    await UniswapFactory.deployed();
    const uniswapFactoryInstance = await IUniswapFactory.at(UniswapFactory.address);

    const tutorialTokenInstance = await TutorialToken.deployed();
    const tutorialTokenUniswapAddress = await uniswapFactoryInstance.getExchange(TutorialToken.address);

    await tutorialTokenInstance.approve(tutorialTokenUniswapAddress, 100000000);

    const tutorialTokenUniswapInstance = await IUniswapExchange.at(tutorialTokenUniswapAddress);

    const balanceETH = web3.utils.toBN(await web3.eth.getBalance(accounts[0]));
    assert(balanceETH.gt(1000));

    const balance = await tutorialTokenInstance.balanceOf(accounts[0]);
    assert.isAtLeast(balance.toNumber(), 1000);
    
    const current_block = await web3.eth.getBlock(await web3.eth.getBlockNumber());

    // TODO: why is this reverting?
    await tutorialTokenUniswapInstance.addLiquidity(1000, 1000, current_block.timestamp + 300, {value: 1000});
  });

});
  Contract: uniswap_factory
    ✓ ... should be initializable through the interface (356200 gas)
    ✓ ... should have a pool for TutorialToken (250727 gas)

    1) ... should add some TutorialToken to the Uniswap pool

    Events emitted during test:
    ---------------------------

    Approval(owner: <indexed>, spender: <indexed>, value: 100000000)

    ---------------------------

...

  1) Contract: uniswap_factory
       ... should add some TutorialToken to the Uniswap pool:
     Error: Returned error: VM Exception while processing transaction: invalid JUMP at c03c510f66214a6f07445cebf4484b987f6e99dba476ffd7e760307e3b57bcc3/c4954161e52bb1507cf4927b047cc0d904598510:39
      at Object.ErrorResponse (node_modules/truffle/build/webpack:/~/web3-eth/~/web3-core-helpers/src/errors.js:29:1)
      at node_modules/truffle/build/webpack:/~/web3-eth/~/web3-core-requestmanager/src/index.js:140:1
      at Object.<anonymous> (node_modules/truffle/build/webpack:/packages/truffle-provider/wrapper.js:112:1)
      at node_modules/truffle/build/webpack:/~/web3/~/web3-providers-ws/src/index.js:121:1
      at Array.forEach (<anonymous>)
      at W3CWebSocket.WebsocketProvider.connection.onmessage (node_modules/truffle/build/webpack:/~/web3/~/web3-providers-ws/src/index.js:98:1)
      at W3CWebSocket._dispatchEvent [as dispatchEvent] (node_modules/truffle/build/webpack:/~/yaeti/lib/EventTarget.js:107:1)
      at W3CWebSocket.onMessage (node_modules/truffle/build/webpack:/~/websocket/lib/W3CWebSocket.js:234:1)
      at WebSocketConnection.<anonymous> (node_modules/truffle/build/webpack:/~/websocket/lib/W3CWebSocket.js:205:1)
      at WebSocketConnection.processFrame (node_modules/truffle/build/webpack:/~/websocket/lib/WebSocketConnection.js:552:1)
      at node_modules/truffle/build/webpack:/~/websocket/lib/WebSocketConnection.js:321:34
      at processTicksAndRejections (internal/process/next_tick.js:74:9)

constant pending tx circles

hi there
tried to add an exchange for 0x6251583e7d997df3604bc73b9779196e94a090ce
my HERC token

getting constant pending txs, when i click on them theres not etherscan hash

i managed to stack 3 txs before i gave up.

2 to add HERC 0x6251583e7d997df3604bc73b9779196e94a090ce as exchange
then
1 to unlock LOOM

screenshot 2019-01-04 at 4 52 07 pm

screenshot 2019-01-04 at 4 49 28 pm

Exchange rate from block-to-block

I came across Uniswap & the smart contracts that implement them a couple days ago & so far, I must say it seems to work great. I really like it.

However, looking through the source code, at least one flaw seemed to appear that I'd like to bring to your attention. I have not reviewed them thoroughly, and I'm not a vyper expert, so I definitely could be mistaken.

It looks like the exchange rate can change with each block as new swaps occur. But when you add or remove liquidity, the exchange rate may change between the block that the transaction was created and the mined block that it appears in. Since the arguments for these calls must be calculated exactly from the exchange rate, I think this could make it very difficult to use once activity increases.

Increasing the gas provided with the transaction would decrease the number of blocks between signing a transaction & it being mined, mitigating this somewhat. However, a very active market will be nearly impossible to add or remove liquidity, and when these calls fail, I think they will consume all of the gas provided for them. I think this will be quite hostile for people trying to participate in providing liquidity.

I think this is not an issue if the functions are always called by another contract so that calculations are always correct for the block the transaction is mined in.

I'm currently writing a wrapper contract in solidity to do that, among other things. I might switch to vyper if it always compiles code as efficient as yours. I've been away from coding smart contracts for a bit & vyper was new & untested then, so I've always written them in solidity.

Any thoughts?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.