Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: command to deploy UniswapV2 Factory #33

Merged
merged 4 commits into from
Aug 20, 2024
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
39 changes: 39 additions & 0 deletions cmd/playground/tx/solidity/deployContract.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"os"

"github.com/hanchon/hanchond/lib/smartcontract"
"github.com/hanchon/hanchond/playground/evmos"
"github.com/hanchon/hanchond/playground/filesmanager"
"github.com/hanchon/hanchond/playground/sql"
Expand Down Expand Up @@ -49,6 +50,34 @@ var deployContractCmd = &cobra.Command{
os.Exit(1)
}

abiPath, err := cmd.Flags().GetString("abi")
if err != nil {
fmt.Println("could not read abi path:", err.Error())
os.Exit(1)
}

if abiPath != "" {
// It requires a constructor
abiBytes, err := filesmanager.ReadFile(abiPath)
if err != nil {
fmt.Printf("error reading the abi file:%s\n", err.Error())
os.Exit(1)
}
// Get Params
callArgs, err := smartcontract.StringsToABIArguments(params)
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())
Expand All @@ -59,6 +88,14 @@ var deployContractCmd = &cobra.Command{
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)
}

fmt.Printf("{\"contract_address\":\"%s\", \"tx_hash\":\"%s\"}\n", receipt.Result.ContractAddress, txHash)
os.Exit(0)
Expand All @@ -68,4 +105,6 @@ var deployContractCmd = &cobra.Command{
func init() {
SolidityCmd.AddCommand(deployContractCmd)
deployContractCmd.Flags().Int("gas-limit", 2_000_000, "GasLimit to be used to deploy the transaction")
deployContractCmd.Flags().String("abi", "", "ABI file if the contract has a contronstructor that needs params")
deployContractCmd.Flags().StringSliceVarP(&params, "params", "p", []string{}, "A list of params. If the param is an address, prefix with `a:0x123...`")
}
136 changes: 136 additions & 0 deletions cmd/playground/tx/solidity/deployUniswapV2Factory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package solidity

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

"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"
)

// deployUniswapV2FactoryCmd represents the deploy command
var deployUniswapV2FactoryCmd = &cobra.Command{
Use: "deploy-uniswap-v2-factory [fee_wallet]",
Args: cobra.ExactArgs(1),
Short: "Deploy uniswap v2 factory",
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)
}

feeWallet := args[0]

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

contractName := "/UniswapV2Factory"
// Clone uniswap-v2-core if needed
path, err := solidity.DownloadDep("https://github.com/Uniswap/uniswap-v2-core", "master", "uniswapv2")
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
path = path + "/contracts" + contractName + ".sol"

// 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 := "factoryBuilder"
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.5.16", path, filesmanager.GetBranchFolder(folderName))
if err != nil {
fmt.Println("could not compile the erc20 contract:", err.Error())
os.Exit(1)
}

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", feeWallet)})
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)
}

fmt.Printf("{\"contract_address\":\"%s\", \"tx_hash\":\"%s\"}\n", receipt.Result.ContractAddress, 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(deployUniswapV2FactoryCmd)
deployUniswapV2FactoryCmd.Flags().Int("gas-limit", 20_000_000, "GasLimit to be used to deploy the transaction")
}
18 changes: 18 additions & 0 deletions docs/pages/hanchond/playground/tx/solidity/deploy.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,21 @@ The compiled`.bin` file must have the following format:
hanchond playground tx solidity deploy-contract /tmp/CheckAddress.bin
{"contract_address":"0xc2f633d1e91e1a2edeb55274753b44b204a4df91", "tx_hash":"0xa0a473953fb8ff88cbd7f63c956992d2621a7fbc47a6ba59427ef8482a0baf9f"}
```

## Deploy the Contract with Params

Requirements:

- ABI path
- Params

```bash
hanchond playground tx solidity deploy-contract ./UniswapV2Factory.bin --gas-limit=1000000000 --abi=./UniswapV2Factory.abi --params=a:0x492bb9bb9a0b5a564307f65a75253e5d054669a9
{"contract_address":"0xc2f633d1e91e1a2edeb55274753b44b204a4df91", "tx_hash":"0xa0a473953fb8ff88cbd7f63c956992d2621a7fbc47a6ba59427ef8482a0baf9f"}
```

The supported params list can be found [here](/lib/smartcontract/ABI)

:::info
The params MUST be prefixed with the type followed by `:`
:::
18 changes: 18 additions & 0 deletions docs/pages/hanchond/playground/tx/solidity/deployUniswapV2.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Deploy UniswapV2

Before being able to deploy this contract, it requires `solc` `v0.5.16`. You can use the [Build Solc](/hanchond/playground/buildSolc) command to get the compiler.

## Deploy the Factory

Params:

- Wallet that will get the fees

```sh
hanchond playground tx solidity deploy-uniswap-v2-factory 0x492bb9bb9a0b5a564307f65a75253e5d054669a9
{"contract_address":"0xe38de16950d3f1048f940268f80ef80bdd10d750", "tx_hash":"0x0ba8e69c71013345f28d7514125c7f323464b4179a68b2a8c28defcf2e96ef3a"}
```

:::info
The flag `gas-limit` can be set to use custom gas. It defaults to 2_000_000.
:::
4 changes: 4 additions & 0 deletions docs/pages/lib/smartcontract/ABI.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ callData, err := smartcontract.ABIPack(abiBytes, method, callArgs...)

This is meant to be used after reading the `abi` file from disk.

### ABIPackRaw

It is the same as the `ABIPack` function but it returns a byte array instead of an `hex` string.

## Strings To ABIArguments

The `StringsToABIArguments` function can be used to convert the strings used in the `cli` to the correct type used by solidity.
Expand Down
15 changes: 12 additions & 3 deletions lib/smartcontract/smartcontract.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,26 @@ import (
"github.com/ethereum/go-ethereum/common"
)

func ABIPack(abiBytes []byte, method string, args ...interface{}) (string, error) {
// ABIPackRaw returns []byte instead of string
func ABIPackRaw(abiBytes []byte, method string, args ...interface{}) ([]byte, error) {
parsedABI, err := abi.JSON(strings.NewReader(string(abiBytes)))
if err != nil {
return "", fmt.Errorf("failed to parse the ABI: %s", err.Error())
return []byte{}, fmt.Errorf("failed to parse the ABI: %s", err.Error())
}

callData, err := parsedABI.Pack(method, args...)
if err != nil {
return "", fmt.Errorf("failed to pack the ABI: %s", err.Error())
return []byte{}, fmt.Errorf("failed to pack the ABI: %s", err.Error())
}

return callData, nil
}

func ABIPack(abiBytes []byte, method string, args ...interface{}) (string, error) {
callData, err := ABIPackRaw(abiBytes, method, args...)
if err != nil {
return "", err
}
return "0x" + hex.EncodeToString(callData), nil
}

Expand Down
13 changes: 0 additions & 13 deletions lib/txbuilder/contract_deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,5 @@ func (t *TxBuilder) DeployContract(
return "", err
}

// TODO: add support for constructors args
// parsedABI, err := abi.JSON(bytes.NewReader(abiFile))
// if err != nil {
// log.Fatalf("Failed to parse ABI: %v", err)
// }
// input, err := parsedABI.Pack("", "Hello, Ethereum!")
// if err != nil {
// log.Fatalf("Failed to pack input parameters: %v", err)
// }
//
// // Combine bytecode + constructor arguments
// fullBytecode := append(bytecode, input...)

return t.SendTx(account.Address, nil, value, gasLimit, bytecode, privateKey)
}
2 changes: 1 addition & 1 deletion playground/cosmosdaemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func NewDameon(
ValidatorInitialSupply: "100000000000000000000000000",

// Maybe move this to just evmos
GasLimit: "10000000",
GasLimit: "1000000000",
BaseFee: "1000000000",

Ports: nil,
Expand Down
4 changes: 4 additions & 0 deletions vocs.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,10 @@ export default defineConfig({
text: "Call Contract View",
link: "/hanchond/playground/tx/solidity/contractView",
},
{
text: "Deploy UniswapV2",
link: "/hanchond/playground/tx/solidity/deployUniswapV2",
},
],
},
],
Expand Down
Loading