From f12c29822cfa5636b7fca699ba2430ab88582d68 Mon Sep 17 00:00:00 2001 From: zakir <80246097+zakir-code@users.noreply.github.com> Date: Thu, 16 Jan 2025 23:29:42 +0800 Subject: [PATCH] feat: migrate WFX to WPUNDIAI (#917) --- app/upgrade_test.go | 25 ++++++++ app/upgrades/v8/upgrade.go | 5 ++ app/upgrades/v8/wrap_token.go | 107 ++++++++++++++++++++++++++++++++++ scripts/linter.sh | 2 +- 4 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 app/upgrades/v8/wrap_token.go diff --git a/app/upgrade_test.go b/app/upgrade_test.go index 1f491634..1373896e 100644 --- a/app/upgrade_test.go +++ b/app/upgrade_test.go @@ -97,6 +97,7 @@ func Test_UpgradeTestnet(t *testing.T) { checkMetadataValidate(t, ctx, myApp) checkPundiAIFXERC20Token(t, ctx, myApp) + checkWrapToken(t, ctx, myApp) } func buildApp(t *testing.T) *app.App { @@ -164,6 +165,9 @@ func beforeUpgrade(ctx sdk.Context, myApp *app.App) BeforeUpgradeData { func checkAppUpgrade(t *testing.T, ctx sdk.Context, myApp *app.App, bdd BeforeUpgradeData) { t.Helper() + + checkWrapToken(t, ctx, myApp) + checkStakingMigrationDelete(t, ctx, myApp) checkGovCustomParams(t, ctx, myApp) @@ -183,6 +187,27 @@ func checkAppUpgrade(t *testing.T, ctx sdk.Context, myApp *app.App, bdd BeforeUp checkPundiAIFXERC20Token(t, ctx, myApp) } +func checkWrapToken(t *testing.T, ctx sdk.Context, myApp *app.App) { + t.Helper() + erc20TokenKeeper := contract.NewERC20TokenKeeper(myApp.EvmKeeper) + wrapTokenAddress := nextversion.GetWFXAddress(ctx.ChainID()) + name, err := erc20TokenKeeper.Name(ctx, wrapTokenAddress) + require.NoError(t, err) + assert.EqualValues(t, nextversion.WrapTokenName, name) + symbol, err := erc20TokenKeeper.Symbol(ctx, wrapTokenAddress) + require.NoError(t, err) + assert.EqualValues(t, nextversion.WrapTokenSymbol, symbol) + decimals, err := erc20TokenKeeper.Decimals(ctx, wrapTokenAddress) + require.NoError(t, err) + assert.EqualValues(t, 18, decimals) + owner, err := erc20TokenKeeper.Owner(ctx, wrapTokenAddress) + require.NoError(t, err) + assert.EqualValues(t, common.BytesToAddress(myApp.AccountKeeper.GetModuleAddress(erc20types.ModuleName).Bytes()), owner) + supply, err := erc20TokenKeeper.TotalSupply(ctx, wrapTokenAddress) + require.NoError(t, err) + assert.EqualValues(t, 1, supply.Cmp(big.NewInt(0))) +} + func checkLayer2OracleIsOnline(t *testing.T, ctx sdk.Context, layer2Keeper crosschainkeeper.Keeper) { t.Helper() oracles := layer2Keeper.GetAllOracles(ctx, false) diff --git a/app/upgrades/v8/upgrade.go b/app/upgrades/v8/upgrade.go index ae130a34..62efbdd9 100644 --- a/app/upgrades/v8/upgrade.go +++ b/app/upgrades/v8/upgrade.go @@ -97,6 +97,9 @@ func upgradeTestnet(ctx sdk.Context, app *keepers.AppKeepers) error { if err := migrateErc20FXToPundiAI(ctx, app.Erc20Keeper); err != nil { return err } + + migrationWFXToWPUNDIAI(ctx, app.EvmKeeper) + return migrateMetadataFXToPundiAI(ctx, app.BankKeeper) } @@ -122,6 +125,8 @@ func upgradeMainnet( return fromVM, err } + migrationWFXToWPUNDIAI(ctx, app.EvmKeeper) + if err = migrateEvmParams(ctx, app.EvmKeeper); err != nil { return fromVM, err } diff --git a/app/upgrades/v8/wrap_token.go b/app/upgrades/v8/wrap_token.go new file mode 100644 index 00000000..f2c7bfbc --- /dev/null +++ b/app/upgrades/v8/wrap_token.go @@ -0,0 +1,107 @@ +package v8 + +import ( + "bytes" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + + fxtypes "github.com/pundiai/fx-core/v8/types" + fxevmkeeper "github.com/pundiai/fx-core/v8/x/evm/keeper" +) + +const ( + WrapTokenSymbol = "WPUNDIAI" + // #nosec G101 + WrapTokenName = "Wrapped Pundi AIFX Token" +) + +const ( + nameSlot = 201 + symbolSlot = 202 + totalSupplySlot = 204 + lastSlot = 300 +) + +var ( + // skip eip1967.proxy.implementation 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc + eip1967ProxyImplKey = common.HexToHash("0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc") + // skip eip1967.proxy.admin + eip1967ProxyAdminKey = common.HexToHash("0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103") + // skip eip1967.proxy.rollback + eip1967ProxyRollbackKey = common.HexToHash("0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143") + // skip eip1967.proxy.beacon + eip1967ProxyBeaconKey = common.HexToHash("0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50") + + mainnetWFXAddress = common.HexToAddress("0x80b5a32E4F032B2a058b4F29EC95EEfEEB87aDcd") + + testnetWFXAddress = common.HexToAddress("0x3452e23F9c4cC62c70B7ADAd699B264AF3549C19") +) + +func migrationWFXToWPUNDIAI(ctx sdk.Context, evmKeeper *fxevmkeeper.Keeper) { + wfxAddr := GetWFXAddress(ctx.ChainID()) + + totalUpdateState := 0 + evmKeeper.ForEachStorage(ctx, wfxAddr, func(key, value common.Hash) bool { + slot := big.NewInt(0).SetBytes(key.Bytes()) + if slot.Cmp(big.NewInt(lastSlot)) < 0 || isEip1967ProxyKey(key) { + return true + } + evmKeeper.SetState(ctx, wfxAddr, key, scaleDownBy100(value.Bytes())) + totalUpdateState++ + return true + }) + + ctx.Logger().Info("total update state", "total", totalUpdateState) + + // set totalSupply + totalSupplyByte := evmKeeper.GetState(ctx, wfxAddr, slotToHashByte(totalSupplySlot)) + evmKeeper.SetState(ctx, wfxAddr, slotToHashByte(totalSupplySlot), scaleDownBy100(totalSupplyByte.Bytes())) + + // test update storage + nameBytes := encodeShortStringWithoutPrefix(WrapTokenName) + evmKeeper.SetState(ctx, wfxAddr, slotToHashByte(nameSlot), nameBytes) + + symbolBytes := encodeShortStringWithoutPrefix(WrapTokenSymbol) + evmKeeper.SetState(ctx, wfxAddr, slotToHashByte(symbolSlot), symbolBytes) + ctx.Logger().Info("migration WFX to WPUNDIAI done") +} + +func GetWFXAddress(chainID string) common.Address { + if chainID == fxtypes.MainnetChainId { + return mainnetWFXAddress + } + return testnetWFXAddress +} + +func isEip1967ProxyKey(key common.Hash) bool { + return bytes.Equal(key.Bytes(), eip1967ProxyImplKey.Bytes()) || + bytes.Equal(key.Bytes(), eip1967ProxyAdminKey.Bytes()) || + bytes.Equal(key.Bytes(), eip1967ProxyRollbackKey.Bytes()) || + bytes.Equal(key.Bytes(), eip1967ProxyBeaconKey.Bytes()) +} + +func slotToHashByte(slot uint64) common.Hash { + return common.BigToHash(big.NewInt(int64(slot))) +} + +func scaleDownBy100(valueByte []byte) []byte { + value := big.NewInt(0).SetBytes(valueByte) + newValue := value.Div(value, big.NewInt(100)) + return common.BigToHash(newValue).Bytes() +} + +func encodeShortStringWithoutPrefix(s string) []byte { + if len(s) > 31 { + panic("String exceeds 31 bytes, requires dynamic encoding!") + } + data := []byte(s) + dataLen := len(data) * 2 + padding := make([]byte, 31-len(data)) + // add padding to the end + data = append(data, padding...) + // add length to last byte (add suffix length) + data = append(data, byte(dataLen)) + return data +} diff --git a/scripts/linter.sh b/scripts/linter.sh index e2573a1b..f5d6b5c1 100755 --- a/scripts/linter.sh +++ b/scripts/linter.sh @@ -4,7 +4,7 @@ set -eo pipefail patternLimits=( "nolint:23" - "#nosec:5" + "#nosec:6" "CrossChain:4" "cross chain:0" "GetERC1967Proxy:4"