Skip to content

Commit

Permalink
Merge pull request #157 from xpladev/feature/precompile
Browse files Browse the repository at this point in the history
feat: precompile contracts
  • Loading branch information
JoowonYun authored Jan 22, 2025
2 parents 3ee8052 + caf9e70 commit dc8bb01
Show file tree
Hide file tree
Showing 28 changed files with 1,487 additions and 14 deletions.
12 changes: 12 additions & 0 deletions app/keepers/keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import (
paramstypes "github.com/cosmos/cosmos-sdk/x/params/types"
slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper"
slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"

"github.com/CosmWasm/wasmd/x/wasm"
Expand All @@ -79,6 +80,7 @@ import (
xplaauthkeeper "github.com/xpladev/xpla/x/auth/keeper"
xplabankkeeper "github.com/xpladev/xpla/x/bank/keeper"

"github.com/xpladev/xpla/precompile"
rewardkeeper "github.com/xpladev/xpla/x/reward/keeper"
rewardtypes "github.com/xpladev/xpla/x/reward/types"
xplastakingkeeper "github.com/xpladev/xpla/x/staking/keeper"
Expand Down Expand Up @@ -578,6 +580,16 @@ func NewAppKeeper(
govModAddress,
)

// Register the precompiled contracts
precompile.RegistPrecompiledContract(
appKeepers.AccountKeeper,
appKeepers.BankKeeper,
stakingkeeper.NewMsgServerImpl(appKeepers.StakingKeeper.Keeper),
distrkeeper.NewMsgServerImpl(appKeepers.DistrKeeper),
wasmkeeper.NewMsgServerImpl(&appKeepers.WasmKeeper),
appKeepers.WasmKeeper,
)

return appKeepers
}

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ replace (
github.com/dgrijalva/jwt-go => github.com/golang-jwt/jwt/v4 v4.4.2

// xpla features
github.com/ethereum/go-ethereum => github.com/xpladev/go-ethereum v1.10.26-xpla
github.com/ethereum/go-ethereum => github.com/xpladev/go-ethereum v1.10.27-0.20241101091644-9889bb150ee0

// Fix upstream GHSA-h395-qcrw-5vmq vulnerability.
// TODO Remove it: https://github.com/cosmos/cosmos-sdk/issues/10409
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1157,8 +1157,8 @@ github.com/xpladev/cosmos-sdk v0.50.10-xpla h1:7ZLmg0tjYmsHZaRn5XJx1BcITB1fuGe6P
github.com/xpladev/cosmos-sdk v0.50.10-xpla/go.mod h1:6Eesrx3ZE7vxBZWpK++30H+Uc7Q4ahQWCL7JKU/LEdU=
github.com/xpladev/ethermint v0.24.0-xpla h1:mBOkS7BPOYIQddkCn/hDJxx5MbcnzSpkombz8xBdaR8=
github.com/xpladev/ethermint v0.24.0-xpla/go.mod h1:8Zb1vDEyjCo+xbyZqExLXdG7aOH8AYiL2jW0nPsMUOk=
github.com/xpladev/go-ethereum v1.10.26-xpla h1:tz9WTV9Fhhu9Xcpxo7RcXBygKcUbb5Zps4PBOVFgRqQ=
github.com/xpladev/go-ethereum v1.10.26-xpla/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg=
github.com/xpladev/go-ethereum v1.10.27-0.20241101091644-9889bb150ee0 h1:aUVjsSerLJdRHWZhosPHx5orFm7qBElfhIpkeJ2oQ0o=
github.com/xpladev/go-ethereum v1.10.27-0.20241101091644-9889bb150ee0/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg=
github.com/xpladev/ledger-cosmos-go v0.13.3-xpla h1:TG+QZ/sudMH2iPF+aJnYs+P9ua6k6KGxBS7Sa6XwjF4=
github.com/xpladev/ledger-cosmos-go v0.13.3-xpla/go.mod h1:HENcEP+VtahZFw38HZ3+LS3Iv5XV6svsnkk9vdJtLr8=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
Expand Down
1 change: 1 addition & 0 deletions precompile/bank/IBank.abi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"string","name":"denom","type":"string"}],"name":"balance","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"fromAddress","type":"address"},{"internalType":"address","name":"toAddress","type":"address"},{"internalType":"string","name":"denom","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"send","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"denom","type":"string"}],"name":"supplyOf","outputs":[{"internalType":"uint256","name":"supply","type":"uint256"}],"stateMutability":"view","type":"function"}]
28 changes: 28 additions & 0 deletions precompile/bank/IBank.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

address constant BANK_PRECOMPILE_ADDRESS = 0x1000000000000000000000000000000000000001;

IBank constant BANK_CONTRACT = IBank(
BANK_PRECOMPILE_ADDRESS
);

interface IBank {
// Transactions
function send(
address fromAddress,
address toAddress,
string calldata denom,
uint256 amount
) external returns (bool success);

// Queries
function balance(
address addr,
string memory denom
) external view returns (uint256 balance);

function supplyOf(
string memory denom
) external view returns (uint256 supply);
}
136 changes: 136 additions & 0 deletions precompile/bank/bank.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package bank

import (
"embed"
"errors"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"

sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/xpladev/ethermint/x/evm/statedb"

"github.com/xpladev/xpla/precompile/util"
)

var _ vm.PrecompiledContract = PrecompiledBank{}

var (
Address = common.HexToAddress(hexAddress)
ABI = abi.ABI{}

//go:embed IBank.abi
abiFS embed.FS
)

type PrecompiledBank struct {
bk BankKeeper
}

func init() {
var err error
ABI, err = util.LoadABI(abiFS, abiFile)
if err != nil {
panic(err)
}
}

func NewPrecompiledBank(bk BankKeeper) PrecompiledBank {
return PrecompiledBank{bk: bk}
}

func (p PrecompiledBank) RequiredGas(input []byte) uint64 {
// Implement the method as needed
return 0
}

func (p PrecompiledBank) Run(evm *vm.EVM, input []byte) ([]byte, error) {
method, argsBz := util.SplitInput(input)

abiMethod, err := ABI.MethodById(method)
if err != nil {
return nil, err
}

args, err := abiMethod.Inputs.Unpack(argsBz)
if err != nil {
return nil, err
}

ctx := evm.StateDB.(*statedb.StateDB).GetContext()

switch MethodBank(abiMethod.Name) {
case Balance:
return p.balance(ctx, abiMethod, args)
case Send:
return p.send(ctx, evm.Origin, abiMethod, args)
case Supply:
return p.supplyOf(ctx, abiMethod, args)
default:
return nil, errors.New("method not found")
}
}

func (p PrecompiledBank) balance(ctx sdk.Context, method *abi.Method, args []interface{}) ([]byte, error) {

address, err := util.GetAccAddress(args[0])
if err != nil {
return nil, err
}

denom, err := util.GetString(args[1])
if err != nil {
return nil, err
}

coin := p.bk.GetBalance(ctx, address, denom)

return method.Outputs.Pack(coin.Amount.BigInt())
}

func (p PrecompiledBank) supplyOf(ctx sdk.Context, method *abi.Method, args []interface{}) ([]byte, error) {
denom, err := util.GetString(args[0])
if err != nil {
return nil, err
}

coin := p.bk.GetSupply(ctx, denom)

return method.Outputs.Pack(coin.Amount.BigInt())
}

func (p PrecompiledBank) send(ctx sdk.Context, sender common.Address, method *abi.Method, args []interface{}) ([]byte, error) {

fromAddress, err := util.GetAccAddress(args[0])
if err != nil {
return nil, err
}

if err = util.ValidateSigner(fromAddress, sender); err != nil {
return nil, err
}

toAddress, err := util.GetAccAddress(args[1])
if err != nil {
return nil, err
}

denom, err := util.GetString(args[2])
if err != nil {
return nil, err
}

amount, err := util.GetBigInt(args[3])
if err != nil {
return nil, err
}

err = p.bk.SendCoins(ctx, fromAddress, toAddress, sdk.NewCoins(sdk.NewCoin(denom, amount)))
if err != nil {
return nil, err
}

return method.Outputs.Pack(true)
}
14 changes: 14 additions & 0 deletions precompile/bank/const.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package bank

const (
hexAddress = "0x1000000000000000000000000000000000000001"
abiFile = "IBank.abi"
)

type MethodBank string

const (
Balance MethodBank = "balance"
Send MethodBank = "send"
Supply MethodBank = "supplyOf"
)
13 changes: 13 additions & 0 deletions precompile/bank/expected_keepers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package bank

import (
"context"

sdk "github.com/cosmos/cosmos-sdk/types"
)

type BankKeeper interface {
GetBalance(context.Context, sdk.AccAddress, string) sdk.Coin
GetSupply(context.Context, string) sdk.Coin
SendCoins(context.Context, sdk.AccAddress, sdk.AccAddress, sdk.Coins) error
}
1 change: 1 addition & 0 deletions precompile/distribution/IDistribution.abi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"inputs":[{"internalType":"address","name":"delegatorAddress","type":"address"},{"internalType":"address","name":"validatorAddress","type":"address"}],"name":"withdrawDelegatorReward","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]
16 changes: 16 additions & 0 deletions precompile/distribution/IDistribution.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

address constant DISTRIBUTION_PRECOMPILE_ADDRESS = 0x1000000000000000000000000000000000000003;

IDistribution constant DISTRIBUTION_CONTRACT = IDistribution(
DISTRIBUTION_PRECOMPILE_ADDRESS
);

interface IDistribution {
// Transactions
function withdrawDelegatorReward(
address delegatorAddress,
address validatorAddress
) external returns (uint256 amount);
}
12 changes: 12 additions & 0 deletions precompile/distribution/const.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package distribution

const (
hexAddress = "0x1000000000000000000000000000000000000003"
abiFile = "IDistribution.abi"
)

type MethodDistribution string

const (
WithdrawDelegatorReward MethodDistribution = "withdrawDelegatorReward"
)
103 changes: 103 additions & 0 deletions precompile/distribution/distribution.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package distribution

import (
"context"
"embed"
"errors"
"math/big"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"

sdk "github.com/cosmos/cosmos-sdk/types"
distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types"

"github.com/xpladev/ethermint/x/evm/statedb"

"github.com/xpladev/xpla/precompile/util"
)

var _ vm.PrecompiledContract = PrecompiledDistribution{}

var (
Address = common.HexToAddress(hexAddress)
ABI = abi.ABI{}

//go:embed IDistribution.abi
abiFS embed.FS
)

type PrecompiledDistribution struct {
dk DistributionKeeper
}

func init() {
var err error
ABI, err = util.LoadABI(abiFS, abiFile)
if err != nil {
panic(err)
}
}

func NewPrecompiledDistribution(dk DistributionKeeper) PrecompiledDistribution {
return PrecompiledDistribution{dk: dk}
}

func (p PrecompiledDistribution) RequiredGas(input []byte) uint64 {
// Implement the method as needed
return 0
}

func (p PrecompiledDistribution) Run(evm *vm.EVM, input []byte) ([]byte, error) {
method, argsBz := util.SplitInput(input)

abiMethod, err := ABI.MethodById(method)
if err != nil {
return nil, err
}

args, err := abiMethod.Inputs.Unpack(argsBz)
if err != nil {
return nil, err
}

ctx := evm.StateDB.(*statedb.StateDB).GetContext()

switch MethodDistribution(abiMethod.Name) {
case WithdrawDelegatorReward:
return p.withdrawDelegatorReward(ctx, evm.Origin, abiMethod, args)
default:
return nil, errors.New("method not found")
}
}

func (p PrecompiledDistribution) withdrawDelegatorReward(ctx context.Context, sender common.Address, method *abi.Method, args []interface{}) ([]byte, error) {
delegatorAddress, err := util.GetAccAddress(args[0])
if err != nil {
return nil, err
}

if err = util.ValidateSigner(delegatorAddress, sender); err != nil {
return nil, err
}

validatorAddress, err := util.GetAccAddress(args[1])
if err != nil {
return nil, err
}

msg := distributiontypes.NewMsgWithdrawDelegatorReward(delegatorAddress.String(), sdk.ValAddress(validatorAddress.Bytes()).String())

res, err := p.dk.WithdrawDelegatorReward(ctx, msg)
if err != nil {
return nil, err
}

amount := big.NewInt(0)
if !res.Amount.IsZero() {
amount = res.Amount[0].Amount.BigInt()
}

return method.Outputs.Pack(amount)
}
11 changes: 11 additions & 0 deletions precompile/distribution/expected_keepers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package distribution

import (
"context"

distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
)

type DistributionKeeper interface {
WithdrawDelegatorReward(ctx context.Context, msg *distributiontypes.MsgWithdrawDelegatorReward) (*distributiontypes.MsgWithdrawDelegatorRewardResponse, error)
}
Loading

0 comments on commit dc8bb01

Please sign in to comment.