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

chore(bech32): Port bech32 extension #2038

Merged
merged 11 commits into from
Nov 15, 2023
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
- (erc20) [#1995](https://github.com/evmos/evmos/pull/1995) Add ERC-20 precompile approvals and authorizations.
- (osmosis-outpost) [#1986](https://github.com/evmos/evmos/pull/1986) Add Osmosis outpost transaction.
- (erc20) [#1997](https://github.com/evmos/evmos/pull/1997) Add logic for ERC-20 precompile registration.
- (bech32) [#2038](https://github.com/evmos/evmos/pull/2038) Add `bech32` conversion precompile.

### Improvements

Expand Down
28 changes: 28 additions & 0 deletions precompiles/bech32/Bech32.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: LGPL-3.0-only
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
pragma solidity >=0.8.17;
fedekunze marked this conversation as resolved.
Show resolved Hide resolved

/// @dev The Bech32I contract's address.
address constant Bech32_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000000400;

/// @author Evmos Team
/// @title Bech32 Precompiled Contract
/// @dev The interface through which solidity contracts can convert addresses from
/// hex to bech32 and vice versa.
/// @custom:address 0x0000000000000000000000000000000000000400
interface Bech32I {
/// @dev Defines a method for converting a hex formatted address to bech32.
/// @param addr The hex address to be converted.
/// @param prefix The human readable prefix (HRP) of the bech32 address.
/// @return bech32Address The address in bech32 format.
function hexToBech32(
address addr,
string memory prefix
) external returns (string memory bech32Address);

/// @dev Defines a method for converting a bech32 formatted address to hex.
/// @param bech32Address The bech32 address to be converted.
/// @return addr The address in hex format.
function bech32ToHex(
string memory bech32Address
) external returns (address addr);
}
45 changes: 45 additions & 0 deletions precompiles/bech32/abi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
[
{
"inputs": [
{
"internalType": "string",
"name": "bech32Address",
"type": "string"
}
],
"name": "bech32ToHex",
"outputs": [
{
"internalType": "address",
"name": "addr",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "addr",
"type": "address"
},
{
"internalType": "string",
"name": "prefix",
"type": "string"
}
],
"name": "hexToBech32",
"outputs": [
{
"internalType": "string",
"name": "bech32Address",
"type": "string"
}
],
"stateMutability": "nonpayable",
"type": "function"
}
]
91 changes: 91 additions & 0 deletions precompiles/bech32/bech32.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright Tharsis Labs Ltd.(Evmos)
// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE)

package bech32

import (
"embed"
"fmt"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
cmn "github.com/evmos/evmos/v15/precompiles/common"
)

var _ vm.PrecompiledContract = &Precompile{}

const (
// PrecompileAddress defines the address of the bech32 precompile contract.
PrecompileAddress = "0x0000000000000000000000000000000000000400"
)

// Embed abi json file to the executable binary. Needed when importing as dependency.
//
//go:embed abi.json
var f embed.FS

// Precompile defines the precompiled contract for Bech32 encoding.
type Precompile struct {
abi.ABI
baseGas uint64
}

// NewPrecompile creates a new bech32 Precompile instance as a
// PrecompiledContract interface.
func NewPrecompile(baseGas uint64) (*Precompile, error) {
newABI, err := cmn.LoadABI(f, "abi.json")
if err != nil {
return nil, err
}

if baseGas == 0 {
return nil, fmt.Errorf("baseGas cannot be zero")
}

return &Precompile{
ABI: newABI,
baseGas: baseGas,
}, nil
}

// Address defines the address of the bech32 compile contract.
// address: 0x0000000000000000000000000000000000000400
func (Precompile) Address() common.Address {
return common.HexToAddress(PrecompileAddress)
}

// RequiredGas calculates the contract gas use.
func (p Precompile) RequiredGas(_ []byte) uint64 {
return p.baseGas
}

// Run executes the precompiled contract bech32 methods defined in the ABI.
func (p Precompile) Run(_ *vm.EVM, contract *vm.Contract, _ bool) (bz []byte, err error) {
methodID := contract.Input[:4]
// NOTE: this function iterates over the method map and returns
// the method with the given ID
method, err := p.MethodById(methodID)
if err != nil {
return nil, err
}

argsBz := contract.Input[4:]
args, err := method.Inputs.Unpack(argsBz)
if err != nil {
return nil, err
}

switch method.Name {
case HexToBech32Method:
bz, err = p.HexToBech32(method, args)
case Bech32ToHexMethod:
Dismissed Show dismissed Hide dismissed
bz, err = p.Bech32ToHex(method, args)
}

if err != nil {
return nil, err
}

return bz, nil
}