Skip to content

Commit

Permalink
chore(bech32): Port bech32 extension (#2038)
Browse files Browse the repository at this point in the history
* chore(bech32): Port bech32 precompile to Evmos repo

* fix: add bech32 precompile init

* run make format

* fix: tests now use new testing setup

* CHANGELOG

* fix: update expected gas

* fix: slim down testing suite

---------

Co-authored-by: Vvaradinov <Vvaradinov@users.noreply.github.com>
Co-authored-by: stepit <48993133+0xstepit@users.noreply.github.com>
  • Loading branch information
3 people committed Nov 15, 2023
1 parent 17c0a46 commit 2d66645
Show file tree
Hide file tree
Showing 12 changed files with 788 additions and 2 deletions.
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
pragma solidity >=0.8.17;

/// @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:
bz, err = p.Bech32ToHex(method, args)
}

if err != nil {
return nil, err
}

return bz, nil
}

0 comments on commit 2d66645

Please sign in to comment.