-
Notifications
You must be signed in to change notification settings - Fork 0
/
output04.go
265 lines (226 loc) · 6.85 KB
/
output04.go
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
package main
import (
"encoding/csv"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os"
"strconv"
"time"
// auth staking "github.com/cosmos/cosmos-sdk/x/auth/types"
)
// Bear with me. I ran into an issue where I had to store the genesis file data in a struct.
// Alternative way (with unresolved bug) at the end of this file
type baseGenesis struct {
Genesis_time time.Time
Chain_id string
Initial_height string
Consensus_Params ConsensusParam
App_hash string
App_state AppState
}
type ConsensusParam struct {
Block BlockStruct
Evidence EvidenceStruct
Validator ValidatorStruct
Version any
}
type BlockStruct struct {
Max_bytes string
Max_gas string
Time_iota_ms string
}
type EvidenceStruct struct {
Max_age_num_blocks string
Max_age_duration string
Max_bytes string
}
type ValidatorStruct struct {
Pub_key_types []string
}
type AppState struct {
Auth AuthStruct
Authz map[string]interface{}
Bank map[string]interface{}
Capability map[string]interface{}
Crisis map[string]interface{}
Distribution map[string]interface{}
Evidence map[string]interface{}
Feegrant map[string]interface{}
Genutil map[string]interface{}
Gov map[string]interface{}
Gravity map[string]interface{}
Ibc map[string]interface{}
Mint map[string]interface{}
Params map[string]interface{}
Slashing map[string]interface{}
Staking map[string]interface{}
Transfer map[string]interface{}
Upgrade map[string]interface{}
Vesting map[string]interface{}
}
type AuthStruct struct {
Params map[string]interface{}
Accounts []AccountStruct
}
type AccountStruct struct {
Type string
Base_vesting_account BaseVestingAccount
}
type BaseVestingAccount struct {
Base_account BaseAccountStruct
Original_vesting []VestingStruct
Delegated_free []any
Delegated_vesting []any
End_time string
}
type BaseAccountStruct struct {
Address string
Pub_key string
Account_number string
Sequence string
}
type VestingStruct struct {
Denom string
Amount string
}
// This is a struct that helps generate and assemble the output
type vestingAccs struct {
vestAddress string
vestTokens string
unlockDate string
}
// This is a struct that helps generate and assemble the output
var vestingAnalysis []vestingAccs
// The genesisFile
var payload baseGenesis
var tokenAmounts = make(map[string]int64)
// An accumulator function that executes all functions for challenge 01 output 1 and stores variables
func Output04() {
getGenesis()
appendVestingData(payload)
getVestingSchedule(payload)
exportOP4(vestingAnalysis)
}
// This function stores the genesisFile in the variable genesisFile
func getGenesis() {
// make sure this file is in the root directory of the
content, err := ioutil.ReadFile("./inputs/umee-genesis.json")
if err != nil {
log.Fatal("Error when opening file: ", err)
}
err = json.Unmarshal(content, &payload)
if err != nil {
log.Fatal("Error when opening file: ", err)
}
}
// This function queries each account's end_time and formats it in a regular timestamp
// It appends a vesting account's data to the output slice
func appendVestingData(payload baseGenesis) {
for _, acc := range payload.App_state.Auth.Accounts {
var vestingAmount string
var unlockTime time.Time
if acc.Base_vesting_account.End_time != "" {
i, err := strconv.ParseInt(acc.Base_vesting_account.End_time, 10, 64)
if err != nil {
panic(err)
}
unlockTime = time.Unix(i, 0)
}
for _, amount := range acc.Base_vesting_account.Original_vesting {
vestingAmount = amount.Amount + amount.Denom
}
vestingAnalysis = append(vestingAnalysis, vestingAccs{
acc.Base_vesting_account.Base_account.Address,
vestingAmount,
unlockTime.String(),
})
}
}
func getVestingSchedule(payload baseGenesis) {
var unlockTimes = make(map[string]int)
for _, acc := range payload.App_state.Auth.Accounts {
unlockTimes[acc.Base_vesting_account.End_time] = unlockTimes[acc.Base_vesting_account.End_time] + 1
for _, v := range acc.Base_vesting_account.Original_vesting {
amount, _ := strconv.ParseInt(v.Amount, 10, 64)
tokenAmounts[acc.Base_vesting_account.End_time] = tokenAmounts[acc.Base_vesting_account.End_time] + amount
}
}
exportOP4_1(tokenAmounts)
}
// This function takes the slice and exports it in a CSV
func exportOP4(vestingAnalysis []vestingAccs) {
file, err := os.Create("output_04.csv")
if err != nil {
log.Fatalln("failed to open file", err)
}
w := csv.NewWriter(file)
defer w.Flush()
// Using Write
header := []string{"Vesting Account", "Vested Tokens", "Unlock Date"}
if err := w.Write(header); err != nil {
log.Fatalln("error writing record to file", err)
}
for _, van := range vestingAnalysis {
if van.vestAddress != "" {
row := []string{van.vestAddress, van.vestTokens, van.unlockDate}
if err := w.Write(row); err != nil {
log.Fatalln("error writing record to file", err)
}
}
}
defer file.Close()
}
func exportOP4_1(tokenAmounts map[string]int64) {
file, err := os.Create("output_04-vesting-schedule.csv")
if err != nil {
log.Fatalln("failed to open file", err)
}
w := csv.NewWriter(file)
defer w.Flush()
// Using Write
header := []string{"Timestamp", "Unlocked Tokens"}
if err := w.Write(header); err != nil {
log.Fatalln("error writing record to file", err)
}
for ts, to := range tokenAmounts {
amount := strconv.FormatInt(to, 10)
timestamp, _ := strconv.ParseInt(ts, 10, 64)
var time = time.Unix(timestamp, 0)
fmt.Println("I'm not sure why the following rows are not written in the csv.")
row := []string{time.String(), amount}
if err := w.Write(row); err != nil {
log.Fatalln("error writing record to file", err)
}
}
defer file.Close()
}
/*
**** Legacy Code. ****
I tried to query the accounts from the node directly, but ran into a bug I couldn't fix in time.
This area is commented out because I want to show you guys my thought process and where I got stuck.
func getGrpcConnC2() (*grpc.ClientConn, error) {
GrpcConnC2, err := grpc.Dial(
"umee-grpc.polkachu.com:13690",
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithDefaultCallOptions(grpc.ForceCodec(codec.NewProtoCodec(nil).GRPCCodec())),
)
if err != nil {
return nil, err
}
return GrpcConnC2, nil
}
func getAccounts(grpcConn *grpc.ClientConn) {
authClient := auth.NewQueryClient(grpcConn)
authRes, err := authClient.Accounts{ //here is where the program paniced with "runtime error: invalid memory address or nil pointer dereference"
context.Background(),
&auth.QueryAccountsRequest{},
}
if err != nil {
return nil, err
}
}
// If this would have worked, I would have been able to query the vesting accounts that came from genesis by calling GetGenesisStateFromAppState.
// This would have avoided parsing the genesis file into a tree of structs.
*/