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: asi reconcilliation transfer #344

Merged
Merged
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
162 changes: 129 additions & 33 deletions cmd/fetchd/cmd/genasiupgrade.go
Original file line number Diff line number Diff line change
@@ -1,29 +1,36 @@
package cmd

import (
"bytes"
_ "embed"
"encoding/csv"
"encoding/json"
"fmt"
"github.com/btcsuite/btcutil/bech32"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/server"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/genutil"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types"
ibc_core "github.com/cosmos/ibc-go/v3/modules/core/24-host"
ibccore "github.com/cosmos/ibc-go/v3/modules/core/24-host"
"github.com/spf13/cobra"
"github.com/tendermint/tendermint/types"
"log"
"regexp"
"strconv"
"strings"
)

const (
BridgeContractAddress = "fetch1qxxlalvsdjd07p07y3rc5fu6ll8k4tmetpha8n"
NewBridgeContractAdmin = "fetch15p3rl5aavw9rtu86tna5lgxfkz67zzr6ed4yhw"

IbcWithdrawAddress = "fetch1rhrlzsx9z865dqen8t4v47r99dw6y4va4uph0x" /* "asi1rhrlzsx9z865dqen8t4v47r99dw6y4vaw76rd9" */
IbcWithdrawAddress = "fetch1rhrlzsx9z865dqen8t4v47r99dw6y4va4uph0x" /* "asi1rhrlzsx9z865dqen8t4v47r99dw6y4vaw76rd9" */
ReconciliationWithdrawAddress = "fetch1rhrlzsx9z865dqen8t4v47r99dw6y4va4uph0x"

flagNewDescription = "new-description"
Bech32Chars = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
Expand All @@ -40,11 +47,13 @@ const (
NewChainId = "asi-1"
NewDescription = "ASI Token"

OldBaseDenom = "fet"
OldDenom = "afet"
OldAddrPrefix = "fetch"
)

//go:embed reconciliation_data.csv
var reconciliationData []byte

// ASIGenesisUpgradeCmd returns replace-genesis-values cobra Command.
func ASIGenesisUpgradeCmd(defaultNodeHome string) *cobra.Command {
cmd := &cobra.Command{
Expand Down Expand Up @@ -87,6 +96,11 @@ func ASIGenesisUpgradeCmd(defaultNodeHome string) *cobra.Command {
return err
}

// withdraw balances from reconciliation addresses
if err = ASIGenesisUpgradeWithdrawReconciliationBalances(jsonData); err != nil {
return err
}

// replace denom across the genesis file
ASIGenesisUpgradeReplaceDenom(jsonData)

Expand Down Expand Up @@ -234,18 +248,15 @@ func replaceAddresses(addressTypePrefix string, jsonData map[string]interface{},
func ASIGenesisUpgradeWithdrawIBCChannelsBalances(jsonData map[string]interface{}) error {
bank := jsonData[banktypes.ModuleName].(map[string]interface{})
balances := bank["balances"].([]interface{})
balanceMap, err := getGenesisBalancesMap(balances)
if err != nil {
return err
}
balanceMap := getGenesisBalancesMap(balances)

withdrawalBalanceIdx, ok := (*balanceMap)[IbcWithdrawAddress]
if !ok {
fmt.Println("failed to find Ibc withdrawal address in genesis balances - have addresses already been converted?")
return nil
}

ibc := jsonData[ibc_core.ModuleName].(map[string]interface{})
ibc := jsonData[ibccore.ModuleName].(map[string]interface{})
channelGenesis := ibc["channel_genesis"].(map[string]interface{})
ibcChannels := channelGenesis["channels"].([]interface{})

Expand Down Expand Up @@ -273,13 +284,113 @@ func ASIGenesisUpgradeWithdrawIBCChannelsBalances(jsonData map[string]interface{
balances[withdrawalBalanceIdx].(map[string]interface{})["coins"] = getInterfaceSliceFromCoins(newWithdrawalBalanceCoins)

// zero out the channel balance
balances[balanceIdx] = nil
balances[balanceIdx].(map[string]interface{})["coins"] = []interface{}{}
}

return nil
}

func ASIGenesisUpgradeWithdrawReconciliationBalances() {}
func getGenesisAccountSequenceMap(accounts []interface{}) *map[string]int {
const ModuleAccount = "/cosmos.auth.v1beta1.ModuleAccount"
accountMap := make(map[string]int)

for _, acc := range accounts {
accType := acc.(map[string]interface{})["@type"]

accData := acc
if accType == ModuleAccount {
accData = acc.(map[string]interface{})["base_account"]
}

addr := accData.(map[string]interface{})["address"].(string)
sequence := accData.(map[string]interface{})["sequence"].(string)

sequenceInt, ok := strconv.Atoi(sequence)
if ok != nil {
panic("getGenesisAccountSequenceMap: failed to convert sequence to int")
}
accountMap[addr] = sequenceInt
}

return &accountMap
}

func ASIGenesisUpgradeWithdrawReconciliationBalances(jsonData map[string]interface{}) error {
bank := jsonData[banktypes.ModuleName].(map[string]interface{})
balances := bank["balances"].([]interface{})

balanceMap := getGenesisBalancesMap(balances)

auth := jsonData[authtypes.ModuleName].(map[string]interface{})
accounts := auth["accounts"].([]interface{})
accountSequenceMap := getGenesisAccountSequenceMap(accounts)

fileData := reconciliationData
r := csv.NewReader(bytes.NewReader(fileData))
items, err := r.ReadAll()
if err != nil {
log.Fatalf("Error reading reconciliation data: %s", err)
}

reconciliationBalanceIdx, ok := (*balanceMap)[ReconciliationWithdrawAddress]
if !ok {
return fmt.Errorf("no genesis match for reconciliation address: %s", ReconciliationWithdrawAddress)
}

for _, row := range items {
addr := row[2]

//_ = row[3] balance from CSV

accSequence, ok := (*accountSequenceMap)[addr]
if !ok {
return fmt.Errorf("no genesis match for reconciliation address: %s", addr)
}

balanceIdx, ok := (*balanceMap)[addr]
if !ok {
continue
}

accBalance := balances[balanceIdx]
accBalanceCoins := getCoinsFromInterfaceSlice(accBalance)

reconciliationBalance := balances[reconciliationBalanceIdx]
reconciliationBalanceCoins := getCoinsFromInterfaceSlice(reconciliationBalance)

// check if the reconciliation address is still dormant and contains funds
if accSequence != 0 || !accBalanceCoins.IsAllPositive() {
continue
}

// add reconciliation account balance to withdrawal balance
newReconciliationBalanceCoins := reconciliationBalanceCoins.Add(accBalanceCoins...)
reconciliationBalance.(map[string]interface{})["coins"] = getInterfaceSliceFromCoins(newReconciliationBalanceCoins)

// zero out the reconciliation account balance
balances[balanceIdx].(map[string]interface{})["coins"] = []interface{}{}
}
return nil
}

func convertAddressToASI(addr string, addressPrefix string) (string, error) {
_, decodedAddrData, err := bech32.Decode(addr)
if err != nil {
return "", err
}

newAddress, err := bech32.Encode(NewAddrPrefix+addressPrefix, decodedAddrData)
if err != nil {
return "", err
}

err = sdk.VerifyAddressFormat(decodedAddrData)
if err != nil {
return "", err
}

return newAddress, nil
}

func crawlJson(key string, value interface{}, idx int, strHandler func(string, interface{}, int) interface{}) interface{} {
switch val := value.(type) {
Expand All @@ -299,34 +410,19 @@ func crawlJson(key string, value interface{}, idx int, strHandler func(string, i
return value
}

func getGenesisBalancesMap(balances []interface{}) (*map[string]int, error) {
func getGenesisBalancesMap(balances []interface{}) *map[string]int {
balanceMap := make(map[string]int)

for i, balance := range balances {
addr := balance.(map[string]interface{})["address"].(string)
balanceMap[addr] = i
}

return &balanceMap, nil
}

func convertAddressToASI(addr string, addressTypePrefix string) (string, error) {
_, decodedAddrData, err := bech32.Decode(addr)
if err != nil {
return "", fmt.Errorf("failed to decode address: %w", err)
}

err = sdk.VerifyAddressFormat(decodedAddrData)
if err != nil {
return "", fmt.Errorf("failed to verify address format: %w", err)
}

newAddress, err := bech32.Encode(NewAddrPrefix+addressTypePrefix, decodedAddrData)
if err != nil {
return "", fmt.Errorf("failed to encode new address: %w", err)
addr := balance.(map[string]interface{})["address"]
if addr == nil {
fmt.Println(balance)
}
addrStr := addr.(string)
balanceMap[addrStr] = i
}

return newAddress, nil
return &balanceMap
}

func getCoinsFromInterfaceSlice(data interface{}) sdk.Coins {
Expand Down
Loading