lambdaclass / ethereum_war_game_tooling

We are slow while using the UI/UX of crypto wallets so we created our CLI version
MIT License
5 stars 2 forks source link
ctf-challenges distributed-systems ethereum wargame

Ethereum War Game and CTF Tooling

EthClient

Simple elixir client to interact with the ethereum blockchain, deploying and calling smart contracts.

Requirements

Quick Start with Tilt

"I just want to try it right now!!"

Run the following commands to get started. This will configure and start both Ethereum nodes, the Livebook server and the EthClient Elixir application.

git clone git@github.com:lambdaclass/ethereum_war_game_tooling.git
cd ethereum_war_game_tooling
tilt up

Now that you have everything ready you can start playing with the tool in one of two ways.

Livebook

Accesing to the Application running at http://localhost:8080 and creating a new notebook.

Elixir IEx terminal

cd eth_client
make tilt.up

Configuration

All global configuration is kept in the EthClient.Context module, which holds the following values:

You can change any of these config values at runtime by using the functions exposed by the EthClient.Context module.

The default config assumes you're running the local ethereum network this repo provides.

If you want to use infura-type host this are the setps you must follow:

First set your infura api key

Context.set_infura_api_key("your_infura_api_key")

Then set the your etherscan api key

Context.set_etherscan_api_key("your_eth_scan_api_key")

And finally set the name of the chain you want to use, for now this are the supported chains: eht mainnet, rinkeby and ropsten.

EthClient.set_chain("chain_name")

Interacting with smart contracts

Without an ABI file

Currently there are three functions in the EthClient module that form the main API:

With an ABI file

When there is an .abi file with the ABI of the contract, user can interact with API in a different way:

Example

When running iex -S mix, there will be a default bin_path variable loaded with the path to a compiled Storage contract and a default abi_path variable with the path to contract's ABI. You can then immediately deploy it with

EthClient.deploy(bin_path)

and then call each of its functions. If you're running the local ethereum network, you should see something like the following:

iex(1)> EthClient.deploy(bin_path)
19:53:26.918 [info]  Deployment transaction accepted by the network, tx_hash: 0x14765466533a85c90ce45dd966854dc5fb95543ba97f343f389872c64ed9597b
19:53:26.922 [info]  Waiting for confirmation...
19:53:28.931 [info]  Contract deployed, address: 0x69148897094941cfad7fd3d52c5e1a810ba4e123 Current contract updated
:ok
iex(2)> EthClient.call("test_function()", [])
{:ok, "0x0000000000000000000000000000000000000000000000000000000000000001"}
iex(3)> EthClient.invoke("store(uint256)", [20], 0)
19:55:28.127 [info]  Transaction accepted by the network, tx_hash: 0x137320dcfb61055313f73aafa799670a4d172936bc91200ebf7a95092f77c297
19:55:28.127 [info]  Waiting for confirmation...
19:55:41.177 [info]  Transaction confirmed!
{:ok, "0x137320dcfb61055313f73aafa799670a4d172936bc91200ebf7a95092f77c297"}
iex(4)> EthClient.call("retrieve()", [])
{:ok, "0x0000000000000000000000000000000000000000000000000000000000000014"}

Local nodes

Install dependencies with

make init

then source your .bashrc, .zshrc or similar files to add foundry to your PATH, then run foundryup to install forge and cast.

To run two local Ethereum nodes:

cd geth_nodes
make setup
make up

Accounts

You can use the miner accounts to pay for transactions.

Node 1 miner account

Node 2 miner account:

Test contract

You can then deploy the test contract with

make deploy_test_contract

under the root directory.

The code for this contract is in contracts/src/Storage.sol; it has 3 functions: test_function will always return 1, store(uint256) stores the given number and retrieve() returns said number.

The output should look like this

forge create --rpc-url http://127.0.0.1:8545 Storage --root contracts/ --private-key df57089febbacf7ba0bc227dafbffa9fc08a93fdc68e1e42411a14efcf23656e
compiling...
Compiling 1 files with 0.8.10
Compilation finished successfully
Compiler run successful
success.
Deployer: 0x8626f6940e2eb28930efb4cef49b2d1f2c9c1199
Deployed to: 0xb581c9264f59bf0289fa76d61b2d0746dce3c30d
Transaction hash: 0xe2c19a2f0766c0e00c416433a8cf53c9993fc918e2b321f348d8de421c195416

Take note of the address you are given after Deployed to:, as that is the contract's address in the local chain. With it, you can now call its test function using cast like this:

cast call <contract_address> "test_function()(uint256)" --rpc-url http://localhost:8545

which should return 1.

You can also send a transaction to call the store function

cast send <contract_address> --private-key <private_key> "store(uint256)" 5 --rpc-url http://localhost:8545

where the private key needs to have some funds to pay for the transaction (for this you can use one of the miner accounts). Output should look like this

blockHash            "0xd2f9afae4ef28c63ceccd7575c4370c17ead74448567ca651ec82a7051434e01"
blockNumber          "0x5"
contractAddress      null
cumulativeGasUsed    "0x6746"
effectiveGasPrice    "0xd1790ced"
gasUsed              "0x6746"
logs                 []
logsBloom            "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
root                 null
status               "0x1"
transactionHash      "0x0bc2448d1f7ee4be24bae1201e687d937d5f094af5e64f09ca0b279d62bf0b81"
transactionIndex     "0x0"
type                 "0x2"

After storing a number, you can retrieve it with

cast call <contract_address> "retrieve()(uint256)" --rpc-url http://localhost:8545

Code

Apart from EthClient calls, other modules can be called.