mirror of
				https://github.com/0glabs/0g-chain.git
				synced 2025-10-31 23:17:27 +00:00 
			
		
		
		
	 f4b8bf8f07
			
		
	
	
		f4b8bf8f07
		
			
		
	
	
	
	
		
			
			* first pass at convert cosmos coin -> evm msg * test ConvertCosmosCoinFromERC20 method * test message server for MsgConvertCosmosCoinFromERC20 * update spec to include MsgConvertCosmosCoinFromERC20 * update changelog * add CLI command for convert-cosmos-coin-from-erc20 * add test of removed/re-enable denom for convert
		
			
				
	
	
		
			108 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			108 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package keeper
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 
 | |
| 	errorsmod "cosmossdk.io/errors"
 | |
| 	sdk "github.com/cosmos/cosmos-sdk/types"
 | |
| 	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
 | |
| 
 | |
| 	"github.com/kava-labs/kava/x/evmutil/types"
 | |
| )
 | |
| 
 | |
| // ConvertCosmosCoinToERC20 locks the initiator's sdk.Coin in the module account
 | |
| // and mints the receiver a corresponding amount of an ERC20 representing the Coin.
 | |
| // If a conversion has never been made before and no contract exists, one will be deployed.
 | |
| // Only denoms registered to the AllowedCosmosDenoms param may be converted.
 | |
| func (k *Keeper) ConvertCosmosCoinToERC20(
 | |
| 	ctx sdk.Context,
 | |
| 	initiator sdk.AccAddress,
 | |
| 	receiver types.InternalEVMAddress,
 | |
| 	amount sdk.Coin,
 | |
| ) error {
 | |
| 	// check that the conversion is allowed
 | |
| 	tokenInfo, allowed := k.GetAllowedTokenMetadata(ctx, amount.Denom)
 | |
| 	if !allowed {
 | |
| 		return errorsmod.Wrapf(types.ErrSDKConversionNotEnabled, amount.Denom)
 | |
| 	}
 | |
| 
 | |
| 	// send coins from initiator to the module account
 | |
| 	// do this before possible contract deploy to prevent unnecessary store interactions
 | |
| 	err := k.bankKeeper.SendCoinsFromAccountToModule(
 | |
| 		ctx, initiator, types.ModuleName, sdk.NewCoins(amount),
 | |
| 	)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// find deployed contract if it exits
 | |
| 	contractAddress, err := k.GetOrDeployCosmosCoinERC20Contract(ctx, tokenInfo)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// mint erc20 tokens for the user
 | |
| 	err = k.MintERC20(ctx, contractAddress, receiver, amount.Amount.BigInt())
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	ctx.EventManager().EmitEvent(sdk.NewEvent(
 | |
| 		types.EventTypeConvertCosmosCoinToERC20,
 | |
| 		sdk.NewAttribute(types.AttributeKeyInitiator, initiator.String()),
 | |
| 		sdk.NewAttribute(types.AttributeKeyReceiver, receiver.String()),
 | |
| 		sdk.NewAttribute(types.AttributeKeyERC20Address, contractAddress.Hex()),
 | |
| 		sdk.NewAttribute(types.AttributeKeyAmount, amount.String()),
 | |
| 	))
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // ConvertCosmosCoinFromERC20 burns the ERC20 wrapper of the cosmos coin and
 | |
| // sends the underlying sdk coin form the module account to the receiver.
 | |
| func (k *Keeper) ConvertCosmosCoinFromERC20(
 | |
| 	ctx sdk.Context,
 | |
| 	initiator types.InternalEVMAddress,
 | |
| 	receiver sdk.AccAddress,
 | |
| 	coin sdk.Coin,
 | |
| ) error {
 | |
| 	amount := coin.Amount.BigInt()
 | |
| 	// get deployed contract
 | |
| 	contractAddress, found := k.GetDeployedCosmosCoinContract(ctx, coin.Denom)
 | |
| 	if !found {
 | |
| 		// no contract deployed
 | |
| 		return errorsmod.Wrapf(types.ErrInvalidCosmosDenom, fmt.Sprintf("no erc20 contract found for %s", coin.Denom))
 | |
| 	}
 | |
| 
 | |
| 	// verify sufficient balance
 | |
| 	balance, err := k.QueryERC20BalanceOf(ctx, contractAddress, initiator)
 | |
| 	if err != nil {
 | |
| 		return errorsmod.Wrapf(types.ErrEVMCall, "failed to retrieve balance %s", err.Error())
 | |
| 	}
 | |
| 	if balance.Cmp(amount) == -1 {
 | |
| 		return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, "failed to convert to cosmos coins")
 | |
| 	}
 | |
| 
 | |
| 	// burn initiator's ERC20 tokens
 | |
| 	err = k.BurnERC20(ctx, contractAddress, initiator, amount)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// send sdk coins to receiver, unlocking them from the module account
 | |
| 	err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, receiver, sdk.NewCoins(coin))
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	ctx.EventManager().EmitEvent(sdk.NewEvent(
 | |
| 		types.EventTypeConvertCosmosCoinFromERC20,
 | |
| 		sdk.NewAttribute(types.AttributeKeyInitiator, initiator.String()),
 | |
| 		sdk.NewAttribute(types.AttributeKeyReceiver, receiver.String()),
 | |
| 		sdk.NewAttribute(types.AttributeKeyERC20Address, contractAddress.Hex()),
 | |
| 		sdk.NewAttribute(types.AttributeKeyAmount, coin.String()),
 | |
| 	))
 | |
| 
 | |
| 	return nil
 | |
| }
 |