Skip to content
This repository has been archived by the owner on Oct 31, 2023. It is now read-only.

Commit

Permalink
Merge pull request #3 from linki/read-only
Browse files Browse the repository at this point in the history
Allow to read balances without providing a passphrase
  • Loading branch information
linki authored Jan 21, 2018
2 parents 20cd877 + d00aa17 commit 6f857df
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 16 deletions.
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ $ go install
Make sure `$GOPATH/bin` is in your `$PATH`, then run it like that:

```console
$ etherdelta-go --keystore-file "UTC-...98c" --passphrase "my...pass"
$ etherdelta-go --keystore-file "UTC-...98c"
Found tokens: 50
Your address: 0x001...98C
Deposited ETH: 1000000000000000000
...
Deposited AIR: 500000000
Expand All @@ -51,11 +52,12 @@ Deposited AIR: 500000000

Note the balances are displayed using the smallest spendable unit. The above maps to 1 Ethereum and 5 AirToken.

If you have anything deposited you can run the command with the `--withdraw-all` flag which will attempt to withdraw ETH and tokens that have a balance greater than zero.
If you have anything deposited you can run the command with the `--withdraw-all` flag which will attempt to withdraw ETH and tokens that have a balance greater than zero. When using `--withdraw-all` you also have to provide `--passphrase` to unlock your Keystore file.

```console
$ etherdelta-go --keystore-file "UTC-...98c" --passphrase "my...pass" --withdraw-all
Found tokens: 50
Your address: 0x001...98C
Deposited ETH: 1000000000000000000
Withdrawing ETH: 1000000000000000000
Transaction hash: 0x7e3892...be9249
Expand All @@ -69,7 +71,7 @@ Transaction hash: 0x1a6328...7ef38a
The tool won't wait until the transactions have been mined. So just make sure the transactions got successfully submitted and give them some time to be mined. Then you can run the command again and validate that all your deposited ETH and tokens have been withdrawn.

```console
$ etherdelta-go --keystore-file "UTC-...98c" --passphrase "my...pass"
$ etherdelta-go --keystore-file "UTC-...98c"
Found tokens: 50
Deposited ETH: 0
...
Expand All @@ -79,8 +81,8 @@ Deposited AIR: 0

It takes the following arguments:
* `keystore-file`: the location of an Ethereum [Keystore file](https://theethereum.wiki/w/index.php/Accounts,_Addresses,_Public_And_Private_Keys,_And_Tokens#UTC_JSON_Keystore_File) which describes where the funds will be withdrawn to as well as contains the encrypted private key for that address, e.g., `~/Library/Ethereum/keystore/UTC--2017-11-...61d3f9`
* `passphrase`: the passphrase unlocking the `keystore-file`. (This proves that you are the owner of the Keystore file)
* `withdraw-all`: sends a transactions to withdraw the balance if it's greater than zero. Without this flag it will merely print the deposited balances. Note that `passphrase` must be provided and correct in both cases in order to successfully process the Keystore file. Defaults to `false` (disable withdrawal).
* `withdraw-all`: sends a transactions to withdraw the balance if it's greater than zero. Without this flag it will merely print the deposited balances. Note that `passphrase` must be provided and correct in order to successfully sign the transaction. Defaults to `false` (disable withdrawal).
* `passphrase`: the passphrase unlocking the `keystore-file`. It proves that you are the owner of the Keystore file and is only required when using `withdraw-all`.

There are some optional arguments as well:
* `endpoint`: an RPC endpoint to interact with the Ethereum blockchain. You can run your own Ethereum node or connect to one provided by [Infura](https://infura.io/) free of charge. Defaults to `https://mainnet.infura.io`.
Expand Down
41 changes: 30 additions & 11 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package main

import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"log"
Expand All @@ -12,7 +14,6 @@ import (
"github.com/alecthomas/kingpin"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
Expand Down Expand Up @@ -42,15 +43,20 @@ var (
timeout time.Duration
)

// KeyStore is a subset of an Ethereum KeyStore file for parsing the Address only.
type KeyStore struct {
Address string `json:"address"`
}

func init() {
kingpin.Flag("keystore-file", "The owner's Keystore file location (required)").Required().ExistingFileVar(&keyStorePath)
kingpin.Flag("passphrase", "The Keystore file's passphrase (required)").Required().StringVar(&passphrase)
kingpin.Flag("withdraw-all", "Withdraw all deposited tokens (optional, default: false)").BoolVar(&withdrawAll)
kingpin.Flag("passphrase", "The Keystore file's passphrase (optional, required when using --withdraw-all)").StringVar(&passphrase)
kingpin.Flag("endpoint", "Ethereum RPC endpoint (optional, default: https://mainnet.infura.io)").Default(defaultEndpoint).StringVar(&endpoint)
kingpin.Flag("etherdelta", "EtherDelta contract address (optional, default: 0x8d12A197cB00D4747a1fe03395095ce2A5CC6819)").Default(defaultEtherDelta).StringVar(&etherDeltaAddress)
kingpin.Flag("token-registry", "TokenRegistry contract address (optional, default: 0x926a74c5C36adf004C87399e65f75628b0f98D2C)").Default(defaultTokenRegistry).StringVar(&tokenRegistryAddress)
kingpin.Flag("gas-price", "The gas price in wei (optional, default: 1000000000, i.e. 1 Gwei)").Default(defaultGasPrice).Int64Var(&gasPrice)
kingpin.Flag("gas-limit", "The gas limit; default: 100000").Default(defaultGasLimit).Int64Var(&gasLimit)
kingpin.Flag("gas-limit", "The gas limit (optional, default: 100000)").Default(defaultGasLimit).Int64Var(&gasLimit)
kingpin.Flag("timeout", "The timeout to submit a transaction to the Ethereum endpoint (optional, default: 5 seconds)").Default(defaultTimeout).DurationVar(&timeout)
}

Expand All @@ -59,6 +65,11 @@ func main() {
kingpin.Version(version)
kingpin.Parse()

// When balances should be withdrawn, a passphrase to unlock the keystore file is required.
if withdrawAll && passphrase == "" {
log.Fatalf("--passphrase is mandatory when using --withdraw-all.")
}

// Create an Ethereum client connecting to the provided RPC endpoint.
c, err := rpc.DialHTTP(endpoint)
if err != nil {
Expand Down Expand Up @@ -98,17 +109,19 @@ func main() {
log.Fatalf("Failed to parse Keystore file: %v", err)
}

// Parse and decrypt the content given a passphrase.
ownerKey, err := keystore.DecryptKey(keyStoreJSON, passphrase)
if err != nil {
log.Fatalf("Failed to decrypt Keystore file: %v", err)
// Parse the content for the Address field.
keyStore := KeyStore{}
if err = json.Unmarshal(keyStoreJSON, &keyStore); err != nil {
log.Fatalf("Failed to parse Keystore file: %v", err)
}
ownerAddress := common.HexToAddress(keyStore.Address)
fmt.Println("Your address:", ownerAddress.Hex())

// EtherDelta manages the ETH deposits as "Token at address 0".
ethTokenAddress := common.Address{}

// Retrieve the owner's deposited ETH balance.
balance, err := etherDelta.BalanceOf(nil, ethTokenAddress, ownerKey.Address)
balance, err := etherDelta.BalanceOf(nil, ethTokenAddress, ownerAddress)
if err != nil {
log.Fatalf("Failed to retrieve balance: %v", err)
}
Expand All @@ -125,7 +138,10 @@ func main() {

// The transaction needs additional metadata, e.g. the private key for
// authorization as well as gas price and limit.
opts := bind.NewKeyedTransactor(ownerKey.PrivateKey)
opts, err := bind.NewTransactor(bytes.NewReader(keyStoreJSON), passphrase)
if err != nil {
log.Fatalf("Failed to create Transactor from Keystore file: %v", err)
}
opts.Context = ctx
opts.GasLimit = big.NewInt(gasLimit)
opts.GasPrice = big.NewInt(gasPrice)
Expand All @@ -151,7 +167,7 @@ func main() {
}

// Retrieve the owner's deposited balance of the token.
balance, err := etherDelta.BalanceOf(nil, token, ownerKey.Address)
balance, err := etherDelta.BalanceOf(nil, token, ownerAddress)
if err != nil {
log.Fatalf("Failed to retrieve balance: %v", err)
}
Expand All @@ -168,7 +184,10 @@ func main() {

// The transaction needs additional metadata, e.g. the private key for
// authorization as well as gas price and limit.
opts := bind.NewKeyedTransactor(ownerKey.PrivateKey)
opts, err := bind.NewTransactor(bytes.NewReader(keyStoreJSON), passphrase)
if err != nil {
log.Fatalf("Failed to create Transactor from Keystore file: %v", err)
}
opts.Context = ctx
opts.GasLimit = big.NewInt(gasLimit)
opts.GasPrice = big.NewInt(gasPrice)
Expand Down

0 comments on commit 6f857df

Please sign in to comment.