Skip to content
Basic interaction with the Compound suite of smart contracts
TypeScript JavaScript
Branch: master
Clone or download

Latest commit

Latest commit 09738e7 Mar 22, 2020


Type Name Latest commit message Commit time
Failed to load latest commit information.
assets Add baDAPPorve notes in README Mar 22, 2020
client_db Update to new testnet contracts Feb 27, 2020
src Add baDAPPorve notes in README Mar 22, 2020
.eslintrc.js Fix compilation error Jan 28, 2020
.gitignore Fix compilation error Jan 28, 2020
package.json Add baDAPPorve notes in README Mar 22, 2020
tsconfig.json Initial commit Nov 10, 2019
yarn.lock Fix compilation error Jan 28, 2020

Compound Playground

This demo app demonstrates basic interaction with the compound smart contracts system for supplying liquidity and borrowing funds.

This also demonstrates how to send multiple Ethereum transaction, without having to wait for each transaction to complete, a way to mitigate the baDAPProve security issue.

The baDAPProve issue

DeFi contracts actions such as lending typically require the pre-approval of a user to be able to transfer ERC20 tokens on his behalf. This approval is done by calling the approve function of ERC20, where a sender permits a different address (i.e. spender, in this case the DeFi contract) to spend a given amount on his behalf. This is usually a mandatory prerequisite before a user can continue to some core action as part of the interaction with the DeFi app.

The security issue

The clear drawback of this solution it allows the contract to withdraw more than the user intended due to a bug, vulnerability etc. Once a user approves an infinite amount, the contract might withdraw the entire balance of the approve ERC20. The user might not even own any tokens at the moment of approval, the contract might still be able to withdraw them in the future.

The parallelization issue

Sending both transactions (approve, action) in parallel can save time. However, when estimateGas function is called on the action Tx, it will not be updated with the results of the user approve, the function simulation will probably fail. This might result in a wrong GasLimit estimation of the action transaction. Consequently, the action Tx will fail upon broadcast. Sending both transactions serially (waiting for the first to be confirmed before sending the other) could lead to long waiting periods between before the action is finally complete.

The solution

A non compromise solution uses the fact that you can send several transactions in parallel, manually increasing the nonce. You also need to manually specify the gasLimit for each transaction.
This repository demonstrates how to execute these two transactions with minimal trade-offs between latency and security.

Fee estimation algorithm

  1. Estimate gas based on historical data and set it as Gas_Limit
  2. Take a margin of L>1 and set Limit_used = Gas_Limit * L
  3. For each executed transaction(With Limit_Used), read the actual gas used: Gas_used
  4. If Gas_used > Gas_Limit, set Gas_Limit = Gas_used, Limit_used = Gas_used * L
  5. If a transaction fails for insufficient gas:
    • Run estimateGas() on the failed transaction and obtain Failed_Limit
    • Create and sign a new transaction
    • Retransmit transaction with new estimation
    • Update Gas_Limit = Failed_Limit
    • Raise error for investigation


Building from source

yarn install
yarn run build
./demo/client <option>

Options to use on client:

  • balance <token>
    Get your balance in cToken or underlying Token Example ./demo/client dai ./demo/client cdai

  • appmint <cToken> <amount>
    This operation demonstrates the discussed technique above. GasLimit for the approve and mint transactions is read from the database. Both transactions are created and signed with nonce=n and nonce=n+1 respectively.
    Both transactions are then broadcaster to the network asyncronously.
    Example, to supply 100 DAI to compound:
    ./demo/client appmint cdai 100

  • approve <cToken> <amount>
    Supply the passed amount to compound cToken contract. Amount is specified in underlying token. Example, to supply 100 DAI to compound:
    ./demo/client mint cdai 100

  • mint <cToken> <amount>
    Supply the passed amount to compound cToken contract. Amount is specified in underlying token. Example, to supply 100 DAI to compound:
    ./demo/client mint cdai 100

  • redeem <cToken> <amount>
    Redeem an amount corresponding to the underlying token. Example, to redeem 50 DAI from compound:
    ./demo/client redeem cdai 50

Demo Gif

Recording of the appmint in action, sending two Txs asynchronously

You can’t perform that action at this time.