Skip to content

Commit

Permalink
feat: UniswapV2Router deployment (#35)
Browse files Browse the repository at this point in the history
* feat: uniswapv2router deployment

* docs: add commands docs
  • Loading branch information
hanchon authored Aug 21, 2024
1 parent b7dc3e2 commit 5c8cfcf
Show file tree
Hide file tree
Showing 6 changed files with 227 additions and 19 deletions.
22 changes: 3 additions & 19 deletions cmd/playground/tx/solidity/deployUniswapV2Factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@ package solidity

import (
"encoding/hex"
"encoding/json"
"fmt"
"os"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/hanchon/hanchond/lib/smartcontract"
"github.com/hanchon/hanchond/playground/evmos"
"github.com/hanchon/hanchond/playground/filesmanager"
Expand Down Expand Up @@ -43,7 +40,7 @@ var deployUniswapV2FactoryCmd = &cobra.Command{

contractName := "/UniswapV2Factory"
// Clone uniswap-v2-core if needed
path, err := solidity.DownloadDep("https://github.com/Uniswap/uniswap-v2-core", "master", "uniswapv2")
path, err := solidity.DownloadUniswapV2Core()
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
Expand Down Expand Up @@ -122,26 +119,13 @@ var deployUniswapV2FactoryCmd = &cobra.Command{
os.Exit(1)
}

codeHash, err := e.NewRequester().EthCode(receipt.Result.ContractAddress, "latest")
codeHash, err := e.NewRequester().EthCodeHash(receipt.Result.ContractAddress, "latest")
if err != nil {
fmt.Println("failed to get the eth code:", err.Error())
os.Exit(1)
}
type code struct {
Result string `json:"result"`
}
var c code
if err := json.Unmarshal(codeHash, &c); err != nil {
fmt.Println("failed to get the eth code:", err.Error())
os.Exit(1)
}

// Perform keccak256 hashing
hash := crypto.Keccak256(common.Hex2Bytes(c.Result[2:]))
// Convert hash to hexadecimal string for display
hashHex := hex.EncodeToString(hash)

fmt.Printf("{\"contract_address\":\"%s\", \"code_hash\":\"%s\", \"tx_hash\":\"%s\"}\n", receipt.Result.ContractAddress, "0x"+hashHex, txHash)
fmt.Printf("{\"contract_address\":\"%s\", \"code_hash\":\"%s\", \"tx_hash\":\"%s\"}\n", receipt.Result.ContractAddress, "0x"+codeHash, txHash)

// Clean up files
if err := filesmanager.CleanUpTempFolder(); err != nil {
Expand Down
171 changes: 171 additions & 0 deletions cmd/playground/tx/solidity/deployUniswapV2Router.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package solidity

import (
"encoding/hex"
"fmt"
"os"
"regexp"

"github.com/hanchon/hanchond/lib/smartcontract"
"github.com/hanchon/hanchond/playground/evmos"
"github.com/hanchon/hanchond/playground/filesmanager"
"github.com/hanchon/hanchond/playground/solidity"
"github.com/hanchon/hanchond/playground/sql"
"github.com/spf13/cobra"
)

// deployUniswapV2RouteryCmd represents the deploy command
var deployUniswapV2RouteryCmd = &cobra.Command{
Use: "deploy-uniswap-v2-router [factory_address] [wrapped_coin_address]",
Args: cobra.ExactArgs(2),
Short: "Deploy uniswap v2 router",
Run: func(cmd *cobra.Command, args []string) {
queries := sql.InitDBFromCmd(cmd)
nodeID, err := cmd.Flags().GetString("node")
if err != nil {
fmt.Println("node not set")
os.Exit(1)
}

gasLimit, err := cmd.Flags().GetInt("gas-limit")
if err != nil {
fmt.Println("incorrect gas limit")
os.Exit(1)
}

factoryAddress := args[0]
wrappedCoinAddress := args[1]

// TODO: allow mainnet as a valid endpoint
e := evmos.NewEvmosFromDB(queries, nodeID)
builder := e.NewTxBuilder(uint64(gasLimit))

factoryCodeHash, err := e.NewRequester().EthCodeHash(factoryAddress, "latest")
if err != nil {
fmt.Println("failed to get the eth code:", err.Error())
os.Exit(1)
}

contractName := "/Router"
// Clone v2-minified if needed
path, err := solidity.DownloadUniswapV2Minified()
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
}

// Keep working with the main contract
path = path + "/contracts" + contractName + ".sol"
libFile, err := filesmanager.ReadFile(path)
if err != nil {
fmt.Println("error opening the router file:", err.Error())
os.Exit(1)
}

regex := regexp.MustCompile(`hex".{3,}"`)
libFile = regex.ReplaceAll(libFile, []byte(fmt.Sprintf("hex'%s'", factoryCodeHash)))
if err := filesmanager.SaveFile(libFile, path); err != nil {
fmt.Println("error saving the router file:", err.Error())
os.Exit(1)
}

// Set up temp folder
if err := filesmanager.CleanUpTempFolder(); err != nil {
fmt.Println("could not clean up the temp folder:", err.Error())
os.Exit(1)
}

folderName := "routerBuilder"
if err := filesmanager.CreateTempFolder(folderName); err != nil {
fmt.Println("could not create the temp folder:", err.Error())
os.Exit(1)
}

// Compile the contract
err = solidity.CompileWithSolc("0.6.6", path, filesmanager.GetBranchFolder(folderName))
if err != nil {
fmt.Println("could not compile the erc20 contract:", err.Error())
os.Exit(1)
}

contractName = "/UniswapV2Router02"

bytecode, err := filesmanager.ReadFile(filesmanager.GetBranchFolder(folderName) + contractName + ".bin")
if err != nil {
fmt.Printf("error reading the bytecode file:%s\n", err.Error())
os.Exit(1)
}

bytecode, err = hex.DecodeString(string(bytecode))
if err != nil {
fmt.Println("error converting bytecode to []byte:", err.Error())
os.Exit(1)
}

// Generate the constructor
abiBytes, err := filesmanager.ReadFile(filesmanager.GetBranchFolder(folderName) + contractName + ".abi")
if err != nil {
fmt.Printf("error reading the abi file:%s\n", err.Error())
os.Exit(1)
}

// Get Params
callArgs, err := smartcontract.StringsToABIArguments(
[]string{
fmt.Sprintf("a:%s", factoryAddress),
fmt.Sprintf("a:%s", wrappedCoinAddress),
},
)
if err != nil {
fmt.Printf("error converting arguments: %s\n", err.Error())
os.Exit(1)
}

callData, err := smartcontract.ABIPackRaw(abiBytes, "", callArgs...)
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
bytecode = append(bytecode, callData...)

txHash, err := builder.DeployContract(0, bytecode, uint64(gasLimit))
if err != nil {
fmt.Printf("error sending the transaction: %s\n", err.Error())
os.Exit(1)
}

receipt, err := e.NewRequester().GetTransactionReceiptWithRetry(txHash, 15)
if err != nil {
fmt.Printf("error getting the tx receipt:%s\n", err.Error())
}

trace, err := e.NewRequester().GetTransactionTrace(txHash)
if err != nil {
fmt.Printf("error getting the tx trace:%s\n", err.Error())
}
if trace.Result.Error != "" {
fmt.Println("failed to execute the transaction:", trace.Result.Error)
os.Exit(1)
}

codeHash, err := e.NewRequester().EthCodeHash(receipt.Result.ContractAddress, "latest")
if err != nil {
fmt.Println("failed to get the eth code:", err.Error())
os.Exit(1)
}

fmt.Printf("{\"contract_address\":\"%s\", \"code_hash\":\"%s\", \"tx_hash\":\"%s\"}\n", receipt.Result.ContractAddress, "0x"+codeHash, txHash)

// Clean up files
if err := filesmanager.CleanUpTempFolder(); err != nil {
fmt.Println("could not clean up the temp folder:", err.Error())
os.Exit(1)
}
os.Exit(0)
},
}

func init() {
SolidityCmd.AddCommand(deployUniswapV2RouteryCmd)
deployUniswapV2RouteryCmd.Flags().Int("gas-limit", 20_000_000, "GasLimit to be used to deploy the transaction")
}
12 changes: 12 additions & 0 deletions docs/pages/hanchond/playground/tx/solidity/deployUniswapV2.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,15 @@ hanchond playground tx solidity deploy-uniswap-v2-factory 0x492bb9bb9a0b5a564307
:::info
The flag `gas-limit` can be set to use custom gas. It defaults to 2_000_000.
:::

## Deploy the Router

Params:

- Factory Address
- WrappedCoin Address

```sh
hanchond playground tx solidity deploy-uniswap-v2-router 0xbb48d7604b522abcbb2f2302d4c18d907c12fd31 0x491bacc7ec4569468f0c21b7ae3629cd9fa6aa39
{"contract_address":"0xd6c873ad9f220279259609ec52fe17702bc47bf8", "code_hash":"0xfffa7b2f489b21362d74fd4ff2c3462d845afc0d0d8170785496d28bb1e568b0", "tx_hash":"0x09df30323ceaa33d5167e31a2faf834b3d253602626d2b256b76bb57a82ad33d"}
```
8 changes: 8 additions & 0 deletions docs/pages/lib/requester/web3.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,11 @@ Gets the smartcontract bytecode at the given height
```go
resp, err := client.EthCode(contract, height)
```

## Eth_code Hash

Gets the smartcontract bytecode hash at the latest height.

```go
hash, err := client.EthCodeHash(contract, height)
```
21 changes: 21 additions & 0 deletions lib/requester/web3.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package requester

import (
"encoding/hex"
"encoding/json"
"fmt"
"math/big"
"strconv"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
coretypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
web3types "github.com/hanchon/hanchond/lib/types/web3"
)

Expand Down Expand Up @@ -154,6 +158,23 @@ func (c *Client) EthCode(address string, height string) ([]byte, error) {
)
}

func (c *Client) EthCodeHash(address string, height string) (string, error) {
codeResp, err := c.EthCode(address, height)
if err != nil {
return "", err
}

type code struct {
Result string `json:"result"`
}
var m code
if err := json.Unmarshal(codeResp, &m); err != nil {
return "", fmt.Errorf("failed to get the eth code:%s", err.Error())
}

return hex.EncodeToString(crypto.Keccak256(common.Hex2Bytes(m.Result[2:]))), nil
}

func heigthToQueryParam(height string) (string, error) {
heightString := "latest"
if height != "latest" {
Expand Down
12 changes: 12 additions & 0 deletions playground/solidity/deps.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,15 @@ func DownloadDep(repoURL, version, name string) (string, error) {

return path, nil
}

func DownloadUniswapV2Core() (string, error) {
return DownloadDep("https://github.com/Uniswap/uniswap-v2-core", "master", "uniswapv2")
}

func DownloadUniswapV2Periphery() (string, error) {
return DownloadDep("https://github.com/Uniswap/v2-periphery", "master", "v2-periphery")
}

func DownloadUniswapV2Minified() (string, error) {
return DownloadDep("https://github.com/casweeney/minified-uniswapv2-contracts", "main", "v2-minified")
}

0 comments on commit 5c8cfcf

Please sign in to comment.