mirror of
				https://github.com/0glabs/0g-chain.git
				synced 2025-11-04 01:07:28 +00:00 
			
		
		
		
	Compare commits
	
		
			12 Commits
		
	
	
		
			fcd654b85a
			...
			0a31f108df
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					0a31f108df | ||
| 
						 | 
					e54d5ba99a | ||
| 
						 | 
					a0426c63f7 | ||
| 
						 | 
					a32dad8373 | ||
| 
						 | 
					4f53e59af7 | ||
| 
						 | 
					8ecfda7bd2 | ||
| 
						 | 
					bbd02215f7 | ||
| 
						 | 
					d4066b6a3d | ||
| 
						 | 
					7900795654 | ||
| 
						 | 
					6df54c84b5 | ||
| 
						 | 
					ec7e0c3163 | ||
| 
						 | 
					7fbf83bacb | 
							
								
								
									
										51
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								README.md
									
									
									
									
									
								
							@ -25,11 +25,58 @@ Continue reading [here](https://docs.0g.ai/intro) if you want to learn more abou
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
- If you want to run a validator node, DA node, or storage node, please refer to the [Run a Node Documentation](https://docs.0g.ai/run-a-node/overview).
 | 
					- If you want to run a validator node, DA node, or storage node, please refer to the [Run a Node Documentation](https://docs.0g.ai/run-a-node/overview).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Getting Started
 | 
				
			||||||
 | 
					To get started with 0G Chain, you'll need to:
 | 
				
			||||||
 | 
					1. Read our [documentation](https://docs.0g.ai/intro)
 | 
				
			||||||
 | 
					2. Choose which component you want to work with (DA, Storage, Inference Serving, or Network)
 | 
				
			||||||
 | 
					3. Follow the setup instructions in the relevant documentation section
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Contributing
 | 
				
			||||||
 | 
					We welcome contributions from the community! Here's how you can contribute:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. Fork the repository
 | 
				
			||||||
 | 
					2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
 | 
				
			||||||
 | 
					3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
 | 
				
			||||||
 | 
					4. Push to the branch (`git push origin feature/AmazingFeature`)
 | 
				
			||||||
 | 
					5. Open a Pull Request
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Please make sure to:
 | 
				
			||||||
 | 
					- Follow our coding standards
 | 
				
			||||||
 | 
					- Write clear commit messages
 | 
				
			||||||
 | 
					- Update documentation as needed
 | 
				
			||||||
 | 
					- Add tests for new features
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Technical Overview
 | 
				
			||||||
 | 
					0G Chain consists of several key components:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Data Availability (DA) Layer
 | 
				
			||||||
 | 
					- Ultra high-performance with KZG commitments
 | 
				
			||||||
 | 
					- Quorum-based Data Availability Sampling
 | 
				
			||||||
 | 
					- Optimized for AI workloads
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Decentralized Storage
 | 
				
			||||||
 | 
					- Erasure coding for data reliability
 | 
				
			||||||
 | 
					- Efficient replication mechanisms
 | 
				
			||||||
 | 
					- Optimized for large-scale AI models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Inference Serving
 | 
				
			||||||
 | 
					- Flexible framework for AI model deployment
 | 
				
			||||||
 | 
					- Support for model fine-tuning
 | 
				
			||||||
 | 
					- Distributed inference capabilities
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Network Layer
 | 
				
			||||||
 | 
					- High-performance P2P communication
 | 
				
			||||||
 | 
					- Low-latency data transfer
 | 
				
			||||||
 | 
					- Decentralized architecture
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Support and Additional Resources
 | 
					## Support and Additional Resources
 | 
				
			||||||
We want to do everything we can to help you be successful while working on your contribution and projects. Here you'll find various resources and communities that may help you complete a project or contribute to 0G. 
 | 
					We're here to help you succeed in contributing to and building with 0G Chain:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Official Links
 | 
				
			||||||
 | 
					- [Official Website](https://0g.ai)
 | 
				
			||||||
 | 
					- [Technical Documentation](https://docs.0g.ai)
 | 
				
			||||||
 | 
					- [GitHub Repository](https://github.com/0glabs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Communities
 | 
					### Communities
 | 
				
			||||||
- [0G Telegram](https://t.me/web3_0glabs)
 | 
					- [0G Telegram](https://t.me/web3_0glabs)
 | 
				
			||||||
- [0G Discord](https://discord.com/invite/0glabs)
 | 
					- [0G Discord](https://discord.com/invite/0glabs)
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,10 @@ package app
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"math/big"
 | 
				
			||||||
 | 
						"sort"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/0glabs/0g-chain/chaincfg"
 | 
				
			||||||
	"github.com/cockroachdb/errors"
 | 
						"github.com/cockroachdb/errors"
 | 
				
			||||||
	abci "github.com/cometbft/cometbft/abci/types"
 | 
						abci "github.com/cometbft/cometbft/abci/types"
 | 
				
			||||||
	gethtypes "github.com/ethereum/go-ethereum/core/types"
 | 
						gethtypes "github.com/ethereum/go-ethereum/core/types"
 | 
				
			||||||
@ -13,6 +16,8 @@ import (
 | 
				
			|||||||
	"github.com/cosmos/cosmos-sdk/x/auth/signing"
 | 
						"github.com/cosmos/cosmos-sdk/x/auth/signing"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const gasPriceSuggestionBlockNum int64 = 5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type (
 | 
					type (
 | 
				
			||||||
	// GasTx defines the contract that a transaction with a gas limit must implement.
 | 
						// GasTx defines the contract that a transaction with a gas limit must implement.
 | 
				
			||||||
	GasTx interface {
 | 
						GasTx interface {
 | 
				
			||||||
@ -30,17 +35,29 @@ type (
 | 
				
			|||||||
	// DefaultProposalHandler defines the default ABCI PrepareProposal and
 | 
						// DefaultProposalHandler defines the default ABCI PrepareProposal and
 | 
				
			||||||
	// ProcessProposal handlers.
 | 
						// ProcessProposal handlers.
 | 
				
			||||||
	DefaultProposalHandler struct {
 | 
						DefaultProposalHandler struct {
 | 
				
			||||||
		mempool    mempool.Mempool
 | 
							mempool         mempool.Mempool
 | 
				
			||||||
		txVerifier ProposalTxVerifier
 | 
							txVerifier      ProposalTxVerifier
 | 
				
			||||||
		txSelector TxSelector
 | 
							txSelector      TxSelector
 | 
				
			||||||
 | 
							feemarketKeeper FeeMarketKeeper
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						FeeMarketKeeper interface {
 | 
				
			||||||
 | 
							SetSuggestionGasPrice(ctx sdk.Context, gas *big.Int)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						txnInfo struct {
 | 
				
			||||||
 | 
							gasPrice *big.Int
 | 
				
			||||||
 | 
							gasLimit uint64
 | 
				
			||||||
 | 
							nonce    uint64
 | 
				
			||||||
 | 
							sender   string
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewDefaultProposalHandler(mp mempool.Mempool, txVerifier ProposalTxVerifier) *DefaultProposalHandler {
 | 
					func NewDefaultProposalHandler(mp mempool.Mempool, txVerifier ProposalTxVerifier, feemarketKeeper FeeMarketKeeper) *DefaultProposalHandler {
 | 
				
			||||||
	return &DefaultProposalHandler{
 | 
						return &DefaultProposalHandler{
 | 
				
			||||||
		mempool:    mp,
 | 
							mempool:         mp,
 | 
				
			||||||
		txVerifier: txVerifier,
 | 
							txVerifier:      txVerifier,
 | 
				
			||||||
		txSelector: NewDefaultTxSelector(),
 | 
							txSelector:      NewDefaultTxSelector(),
 | 
				
			||||||
 | 
							feemarketKeeper: feemarketKeeper,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -97,11 +114,14 @@ func (h *DefaultProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHan
 | 
				
			|||||||
			return abci.ResponsePrepareProposal{Txs: h.txSelector.SelectedTxs()}
 | 
								return abci.ResponsePrepareProposal{Txs: h.txSelector.SelectedTxs()}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							txnInfoMap := make(map[string][]*txnInfo, h.mempool.CountTx())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		iterator := h.mempool.Select(ctx, req.Txs)
 | 
							iterator := h.mempool.Select(ctx, req.Txs)
 | 
				
			||||||
		selectedTxsSignersSeqs := make(map[string]uint64)
 | 
							selectedTxsSignersSeqs := make(map[string]uint64)
 | 
				
			||||||
		var selectedTxsNums int
 | 
							var selectedTxsNums int
 | 
				
			||||||
		for iterator != nil {
 | 
							for iterator != nil {
 | 
				
			||||||
			memTx := iterator.Tx()
 | 
								memTx := iterator.Tx()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			sigs, err := memTx.(signing.SigVerifiableTx).GetSignaturesV2()
 | 
								sigs, err := memTx.(signing.SigVerifiableTx).GetSignaturesV2()
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				panic(fmt.Errorf("failed to get signatures: %w", err))
 | 
									panic(fmt.Errorf("failed to get signatures: %w", err))
 | 
				
			||||||
@ -134,10 +154,42 @@ func (h *DefaultProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHan
 | 
				
			|||||||
									txSignersSeqs[signer] = nonce
 | 
														txSignersSeqs[signer] = nonce
 | 
				
			||||||
								}
 | 
													}
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												if _, exists := txnInfoMap[signer]; !exists {
 | 
				
			||||||
 | 
													txnInfoMap[signer] = make([]*txnInfo, 0, 128)
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												txnInfoMap[signer] = append(txnInfoMap[signer], &txnInfo{
 | 
				
			||||||
 | 
													gasPrice: ethTx.GasPrice(),
 | 
				
			||||||
 | 
													gasLimit: ethTx.Gas(),
 | 
				
			||||||
 | 
													nonce:    nonce,
 | 
				
			||||||
 | 
													sender:   signer,
 | 
				
			||||||
 | 
												})
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
 | 
									// ignore multisig case now
 | 
				
			||||||
 | 
									fee := memTx.(sdk.Fee)
 | 
				
			||||||
 | 
									if len(sigs) == 1 {
 | 
				
			||||||
 | 
										signer := sdk.AccAddress(sigs[0].PubKey.Address()).String()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if _, exists := txnInfoMap[signer]; !exists {
 | 
				
			||||||
 | 
											txnInfoMap[signer] = make([]*txnInfo, 0, 16)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										evmGasPrice, err := utilCosmosDemonGasPriceToEvmDemonGasPrice(fee.GetAmount())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if err == nil {
 | 
				
			||||||
 | 
											txnInfoMap[signer] = append(txnInfoMap[signer], &txnInfo{
 | 
				
			||||||
 | 
												gasPrice: evmGasPrice,
 | 
				
			||||||
 | 
												gasLimit: utilCosmosDemonGasLimitToEvmDemonGasLimit(fee.GetGas()),
 | 
				
			||||||
 | 
												nonce:    sigs[0].Sequence,
 | 
				
			||||||
 | 
												sender:   signer,
 | 
				
			||||||
 | 
											})
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				for _, sig := range sigs {
 | 
									for _, sig := range sigs {
 | 
				
			||||||
					signer := sdk.AccAddress(sig.PubKey.Address()).String()
 | 
										signer := sdk.AccAddress(sig.PubKey.Address()).String()
 | 
				
			||||||
					seq, ok := selectedTxsSignersSeqs[signer]
 | 
										seq, ok := selectedTxsSignersSeqs[signer]
 | 
				
			||||||
@ -198,6 +250,65 @@ func (h *DefaultProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHan
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			iterator = iterator.Next()
 | 
								iterator = iterator.Next()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if len(txnInfoMap) == 0 {
 | 
				
			||||||
 | 
								h.feemarketKeeper.SetSuggestionGasPrice(ctx, big.NewInt(0))
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								senderCnt := 0
 | 
				
			||||||
 | 
								txnCnt := 0
 | 
				
			||||||
 | 
								for sender := range txnInfoMap {
 | 
				
			||||||
 | 
									sort.Slice(txnInfoMap[sender], func(i, j int) bool {
 | 
				
			||||||
 | 
										return txnInfoMap[sender][i].nonce < txnInfoMap[sender][j].nonce
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
									txnCnt += len(txnInfoMap[sender])
 | 
				
			||||||
 | 
									senderCnt++
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								remaing := gasPriceSuggestionBlockNum * int64(maxBlockGas)
 | 
				
			||||||
 | 
								var lastProcessedTx *txnInfo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for remaing > 0 && len(txnInfoMap) > 0 {
 | 
				
			||||||
 | 
									// Find the highest gas price among the first transaction of each account
 | 
				
			||||||
 | 
									var highestGasPrice *big.Int
 | 
				
			||||||
 | 
									var selectedSender string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// Compare first transaction (lowest nonce) from each account
 | 
				
			||||||
 | 
									for sender, txns := range txnInfoMap {
 | 
				
			||||||
 | 
										if len(txns) == 0 {
 | 
				
			||||||
 | 
											delete(txnInfoMap, sender)
 | 
				
			||||||
 | 
											continue
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// First tx has lowest nonce due to earlier sorting
 | 
				
			||||||
 | 
										if highestGasPrice == nil || txns[0].gasPrice.Cmp(highestGasPrice) > 0 {
 | 
				
			||||||
 | 
											highestGasPrice = txns[0].gasPrice
 | 
				
			||||||
 | 
											selectedSender = sender
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if selectedSender == "" {
 | 
				
			||||||
 | 
										break
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// Process the selected transaction
 | 
				
			||||||
 | 
									selectedTx := txnInfoMap[selectedSender][0]
 | 
				
			||||||
 | 
									remaing -= int64(selectedTx.gasLimit)
 | 
				
			||||||
 | 
									lastProcessedTx = selectedTx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// Remove processed transaction
 | 
				
			||||||
 | 
									txnInfoMap[selectedSender] = txnInfoMap[selectedSender][1:]
 | 
				
			||||||
 | 
									if len(txnInfoMap[selectedSender]) == 0 {
 | 
				
			||||||
 | 
										delete(txnInfoMap, selectedSender)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if lastProcessedTx != nil && remaing <= 0 {
 | 
				
			||||||
 | 
									h.feemarketKeeper.SetSuggestionGasPrice(ctx, lastProcessedTx.gasPrice)
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									h.feemarketKeeper.SetSuggestionGasPrice(ctx, big.NewInt(0))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return abci.ResponsePrepareProposal{Txs: h.txSelector.SelectedTxs()}
 | 
							return abci.ResponsePrepareProposal{Txs: h.txSelector.SelectedTxs()}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -336,3 +447,22 @@ func (ts *defaultTxSelector) SelectTxForProposal(maxTxBytes, maxBlockGas uint64,
 | 
				
			|||||||
	// check if we've reached capacity; if so, we cannot select any more transactions
 | 
						// check if we've reached capacity; if so, we cannot select any more transactions
 | 
				
			||||||
	return ts.totalTxBytes >= maxTxBytes || (maxBlockGas > 0 && (ts.totalTxGas >= maxBlockGas))
 | 
						return ts.totalTxBytes >= maxTxBytes || (maxBlockGas > 0 && (ts.totalTxGas >= maxBlockGas))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func utilCosmosDemonGasPriceToEvmDemonGasPrice(gasGroup sdk.Coins) (*big.Int, error) {
 | 
				
			||||||
 | 
						gasPrice := big.NewInt(0)
 | 
				
			||||||
 | 
						for _, coin := range gasGroup {
 | 
				
			||||||
 | 
							if coin.Denom == chaincfg.GasDenom {
 | 
				
			||||||
 | 
								thisGasPrice := big.NewInt(0).SetUint64(coin.Amount.Uint64())
 | 
				
			||||||
 | 
								thisGasPrice = thisGasPrice.Mul(thisGasPrice, big.NewInt(0).SetInt64(chaincfg.GasDenomConversionMultiplier))
 | 
				
			||||||
 | 
								gasPrice = gasPrice.Add(gasPrice, thisGasPrice)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return big.NewInt(0), fmt.Errorf("invalid denom: %s", coin.Denom)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return gasPrice, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func utilCosmosDemonGasLimitToEvmDemonGasLimit(gasLimit uint64) uint64 {
 | 
				
			||||||
 | 
						return gasLimit * chaincfg.GasDenomConversionMultiplier
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -52,13 +52,17 @@ func TestAppAnteHandler_AuthorizedMempool(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	tApp := app.TestApp{
 | 
						tApp := app.TestApp{
 | 
				
			||||||
		App: *app.NewApp(
 | 
							App: *app.NewApp(
 | 
				
			||||||
			log.NewNopLogger(),
 | 
					 | 
				
			||||||
			tmdb.NewMemDB(),
 | 
					 | 
				
			||||||
			chaincfg.DefaultNodeHome,
 | 
								chaincfg.DefaultNodeHome,
 | 
				
			||||||
			nil,
 | 
								nil,
 | 
				
			||||||
			encodingConfig,
 | 
								encodingConfig,
 | 
				
			||||||
			opts,
 | 
								opts,
 | 
				
			||||||
			baseapp.SetChainID(app.TestChainId),
 | 
								app.NewBaseApp(
 | 
				
			||||||
 | 
									log.NewNopLogger(),
 | 
				
			||||||
 | 
									tmdb.NewMemDB(),
 | 
				
			||||||
 | 
									encodingConfig,
 | 
				
			||||||
 | 
									baseapp.SetChainID(app.TestChainId),
 | 
				
			||||||
 | 
								),
 | 
				
			||||||
 | 
								nil,
 | 
				
			||||||
		),
 | 
							),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -267,7 +267,7 @@ type App struct {
 | 
				
			|||||||
	packetForwardKeeper   *packetforwardkeeper.Keeper
 | 
						packetForwardKeeper   *packetforwardkeeper.Keeper
 | 
				
			||||||
	evmKeeper             *evmkeeper.Keeper
 | 
						evmKeeper             *evmkeeper.Keeper
 | 
				
			||||||
	evmutilKeeper         evmutilkeeper.Keeper
 | 
						evmutilKeeper         evmutilkeeper.Keeper
 | 
				
			||||||
	feeMarketKeeper       feemarketkeeper.Keeper
 | 
						feeMarketKeeper       *feemarketkeeper.Keeper
 | 
				
			||||||
	upgradeKeeper         upgradekeeper.Keeper
 | 
						upgradeKeeper         upgradekeeper.Keeper
 | 
				
			||||||
	evidenceKeeper        evidencekeeper.Keeper
 | 
						evidenceKeeper        evidencekeeper.Keeper
 | 
				
			||||||
	transferKeeper        ibctransferkeeper.Keeper
 | 
						transferKeeper        ibctransferkeeper.Keeper
 | 
				
			||||||
@ -313,6 +313,7 @@ func NewApp(
 | 
				
			|||||||
	encodingConfig chainparams.EncodingConfig,
 | 
						encodingConfig chainparams.EncodingConfig,
 | 
				
			||||||
	options Options,
 | 
						options Options,
 | 
				
			||||||
	bApp *baseapp.BaseApp,
 | 
						bApp *baseapp.BaseApp,
 | 
				
			||||||
 | 
						setAbciProposalHandler func(feemarketKeeper FeeMarketKeeper) sdk.PrepareProposalHandler,
 | 
				
			||||||
) *App {
 | 
					) *App {
 | 
				
			||||||
	appCodec := encodingConfig.Marshaler
 | 
						appCodec := encodingConfig.Marshaler
 | 
				
			||||||
	legacyAmino := encodingConfig.Amino
 | 
						legacyAmino := encodingConfig.Amino
 | 
				
			||||||
@ -901,6 +902,10 @@ func NewApp(
 | 
				
			|||||||
	app.SetBeginBlocker(app.BeginBlocker)
 | 
						app.SetBeginBlocker(app.BeginBlocker)
 | 
				
			||||||
	app.SetEndBlocker(app.EndBlocker)
 | 
						app.SetEndBlocker(app.EndBlocker)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if setAbciProposalHandler != nil {
 | 
				
			||||||
 | 
							abciProposalHandler := setAbciProposalHandler(app.feeMarketKeeper)
 | 
				
			||||||
 | 
							bApp.SetPrepareProposal(abciProposalHandler)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	// load store
 | 
						// load store
 | 
				
			||||||
	if !options.SkipLoadLatest {
 | 
						if !options.SkipLoadLatest {
 | 
				
			||||||
		if err := app.LoadLatestVersion(); err != nil {
 | 
							if err := app.LoadLatestVersion(); err != nil {
 | 
				
			||||||
 | 
				
			|||||||
@ -28,19 +28,36 @@ import (
 | 
				
			|||||||
func TestNewApp(t *testing.T) {
 | 
					func TestNewApp(t *testing.T) {
 | 
				
			||||||
	chaincfg.SetSDKConfig()
 | 
						chaincfg.SetSDKConfig()
 | 
				
			||||||
	NewApp(
 | 
						NewApp(
 | 
				
			||||||
		log.NewTMLogger(log.NewSyncWriter(os.Stdout)),
 | 
					 | 
				
			||||||
		db.NewMemDB(),
 | 
					 | 
				
			||||||
		chaincfg.DefaultNodeHome,
 | 
							chaincfg.DefaultNodeHome,
 | 
				
			||||||
		nil,
 | 
							nil,
 | 
				
			||||||
		MakeEncodingConfig(),
 | 
							MakeEncodingConfig(),
 | 
				
			||||||
		DefaultOptions,
 | 
							DefaultOptions,
 | 
				
			||||||
 | 
							NewBaseApp(
 | 
				
			||||||
 | 
								log.NewTMLogger(log.NewSyncWriter(os.Stdout)),
 | 
				
			||||||
 | 
								db.NewMemDB(),
 | 
				
			||||||
 | 
								MakeEncodingConfig(),
 | 
				
			||||||
 | 
								baseapp.SetChainID(TestChainId),
 | 
				
			||||||
 | 
							),
 | 
				
			||||||
 | 
							nil,
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestExport(t *testing.T) {
 | 
					func TestExport(t *testing.T) {
 | 
				
			||||||
	chaincfg.SetSDKConfig()
 | 
						chaincfg.SetSDKConfig()
 | 
				
			||||||
	db := db.NewMemDB()
 | 
						db := db.NewMemDB()
 | 
				
			||||||
	app := NewApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, chaincfg.DefaultNodeHome, nil, MakeEncodingConfig(), DefaultOptions, baseapp.SetChainID(TestChainId))
 | 
						app := NewApp(
 | 
				
			||||||
 | 
							chaincfg.DefaultNodeHome,
 | 
				
			||||||
 | 
							nil,
 | 
				
			||||||
 | 
							MakeEncodingConfig(),
 | 
				
			||||||
 | 
							DefaultOptions,
 | 
				
			||||||
 | 
							NewBaseApp(
 | 
				
			||||||
 | 
								log.NewTMLogger(log.NewSyncWriter(os.Stdout)),
 | 
				
			||||||
 | 
								db,
 | 
				
			||||||
 | 
								MakeEncodingConfig(),
 | 
				
			||||||
 | 
								baseapp.SetChainID(TestChainId),
 | 
				
			||||||
 | 
							),
 | 
				
			||||||
 | 
							nil,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	genesisState := GenesisStateWithSingleValidator(&TestApp{App: *app}, NewDefaultGenesisState())
 | 
						genesisState := GenesisStateWithSingleValidator(&TestApp{App: *app}, NewDefaultGenesisState())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -96,7 +96,7 @@ func NewTestAppFromSealed() TestApp {
 | 
				
			|||||||
	bApp := NewBaseApp(log.NewNopLogger(), db, encCfg, baseapp.SetChainID(TestChainId))
 | 
						bApp := NewBaseApp(log.NewNopLogger(), db, encCfg, baseapp.SetChainID(TestChainId))
 | 
				
			||||||
	app := NewApp(
 | 
						app := NewApp(
 | 
				
			||||||
		chaincfg.DefaultNodeHome, nil,
 | 
							chaincfg.DefaultNodeHome, nil,
 | 
				
			||||||
		encCfg, DefaultOptions, bApp,
 | 
							encCfg, DefaultOptions, bApp, nil,
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	return TestApp{App: *app}
 | 
						return TestApp{App: *app}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -117,7 +117,7 @@ func (tApp TestApp) GetPriceFeedKeeper() pricefeedkeeper.Keeper     { return tAp
 | 
				
			|||||||
func (tApp TestApp) GetCommitteeKeeper() committeekeeper.Keeper     { return tApp.committeeKeeper }
 | 
					func (tApp TestApp) GetCommitteeKeeper() committeekeeper.Keeper     { return tApp.committeeKeeper }
 | 
				
			||||||
func (tApp TestApp) GetEvmutilKeeper() evmutilkeeper.Keeper         { return tApp.evmutilKeeper }
 | 
					func (tApp TestApp) GetEvmutilKeeper() evmutilkeeper.Keeper         { return tApp.evmutilKeeper }
 | 
				
			||||||
func (tApp TestApp) GetEvmKeeper() *evmkeeper.Keeper                { return tApp.evmKeeper }
 | 
					func (tApp TestApp) GetEvmKeeper() *evmkeeper.Keeper                { return tApp.evmKeeper }
 | 
				
			||||||
func (tApp TestApp) GetFeeMarketKeeper() feemarketkeeper.Keeper     { return tApp.feeMarketKeeper }
 | 
					func (tApp TestApp) GetFeeMarketKeeper() *feemarketkeeper.Keeper    { return tApp.feeMarketKeeper }
 | 
				
			||||||
func (tApp TestApp) GetDASignersKeeper() dasignerskeeper.Keeper     { return tApp.dasignersKeeper }
 | 
					func (tApp TestApp) GetDASignersKeeper() dasignerskeeper.Keeper     { return tApp.dasignersKeeper }
 | 
				
			||||||
func (tApp TestApp) GetPrecisebankKeeper() precisebankkeeper.Keeper { return tApp.precisebankKeeper }
 | 
					func (tApp TestApp) GetPrecisebankKeeper() precisebankkeeper.Keeper { return tApp.precisebankKeeper }
 | 
				
			||||||
func (tApp TestApp) GetWrappedA0GIBaseKeeper() wrappeda0gibasekeeper.Keeper {
 | 
					func (tApp TestApp) GetWrappedA0GIBaseKeeper() wrappeda0gibasekeeper.Keeper {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,434 +1 @@
 | 
				
			|||||||
package app_test
 | 
					package app_test
 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"strconv"
 | 
					 | 
				
			||||||
	"testing"
 | 
					 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sdkmath "cosmossdk.io/math"
 | 
					 | 
				
			||||||
	"github.com/0glabs/0g-chain/app"
 | 
					 | 
				
			||||||
	evmutiltypes "github.com/0glabs/0g-chain/x/evmutil/types"
 | 
					 | 
				
			||||||
	precisebankkeeper "github.com/0glabs/0g-chain/x/precisebank/keeper"
 | 
					 | 
				
			||||||
	precisebanktypes "github.com/0glabs/0g-chain/x/precisebank/types"
 | 
					 | 
				
			||||||
	tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
 | 
					 | 
				
			||||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
					 | 
				
			||||||
	"github.com/stretchr/testify/require"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestMigrateEvmutilToPrecisebank(t *testing.T) {
 | 
					 | 
				
			||||||
	// Full test case with all components together
 | 
					 | 
				
			||||||
	tests := []struct {
 | 
					 | 
				
			||||||
		name               string
 | 
					 | 
				
			||||||
		initialReserve     sdkmath.Int
 | 
					 | 
				
			||||||
		fractionalBalances []sdkmath.Int
 | 
					 | 
				
			||||||
	}{
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			"no fractional balances",
 | 
					 | 
				
			||||||
			sdkmath.NewInt(0),
 | 
					 | 
				
			||||||
			[]sdkmath.Int{},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			"sufficient reserve, 0 remainder",
 | 
					 | 
				
			||||||
			// Accounts adding up to 2 int units, same as reserve
 | 
					 | 
				
			||||||
			sdkmath.NewInt(2),
 | 
					 | 
				
			||||||
			[]sdkmath.Int{
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			"insufficient reserve, 0 remainder",
 | 
					 | 
				
			||||||
			// Accounts adding up to 2 int units, but only 1 int unit in reserve
 | 
					 | 
				
			||||||
			sdkmath.NewInt(1),
 | 
					 | 
				
			||||||
			[]sdkmath.Int{
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			"excess reserve, 0 remainder",
 | 
					 | 
				
			||||||
			// Accounts adding up to 2 int units, but 3 int unit in reserve
 | 
					 | 
				
			||||||
			sdkmath.NewInt(3),
 | 
					 | 
				
			||||||
			[]sdkmath.Int{
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			"sufficient reserve, non-zero remainder",
 | 
					 | 
				
			||||||
			// Accounts adding up to 1.5 int units, same as reserve
 | 
					 | 
				
			||||||
			sdkmath.NewInt(2),
 | 
					 | 
				
			||||||
			[]sdkmath.Int{
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			"insufficient reserve, non-zero remainder",
 | 
					 | 
				
			||||||
			// Accounts adding up to 1.5 int units, less than reserve,
 | 
					 | 
				
			||||||
			// Reserve should be 2 and remainder 0.5
 | 
					 | 
				
			||||||
			sdkmath.NewInt(1),
 | 
					 | 
				
			||||||
			[]sdkmath.Int{
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			"excess reserve, non-zero remainder",
 | 
					 | 
				
			||||||
			// Accounts adding up to 1.5 int units, 3 int units in reserve
 | 
					 | 
				
			||||||
			sdkmath.NewInt(3),
 | 
					 | 
				
			||||||
			[]sdkmath.Int{
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, tt := range tests {
 | 
					 | 
				
			||||||
		t.Run(tt.name, func(t *testing.T) {
 | 
					 | 
				
			||||||
			tApp := app.NewTestApp()
 | 
					 | 
				
			||||||
			tApp.InitializeFromGenesisStates()
 | 
					 | 
				
			||||||
			ctx := tApp.NewContext(true, tmproto.Header{Height: 1, Time: time.Now()})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			ak := tApp.GetAccountKeeper()
 | 
					 | 
				
			||||||
			bk := tApp.GetBankKeeper()
 | 
					 | 
				
			||||||
			evmuk := tApp.GetEvmutilKeeper()
 | 
					 | 
				
			||||||
			pbk := tApp.GetPrecisebankKeeper()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			reserveCoin := sdk.NewCoin(precisebanktypes.IntegerCoinDenom, tt.initialReserve)
 | 
					 | 
				
			||||||
			err := bk.MintCoins(ctx, evmutiltypes.ModuleName, sdk.NewCoins(reserveCoin))
 | 
					 | 
				
			||||||
			require.NoError(t, err)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			oldReserveAddr := tApp.GetAccountKeeper().GetModuleAddress(evmutiltypes.ModuleName)
 | 
					 | 
				
			||||||
			newReserveAddr := tApp.GetAccountKeeper().GetModuleAddress(precisebanktypes.ModuleName)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Double check balances
 | 
					 | 
				
			||||||
			oldReserveBalance := bk.GetBalance(ctx, oldReserveAddr, precisebanktypes.IntegerCoinDenom)
 | 
					 | 
				
			||||||
			newReserveBalance := bk.GetBalance(ctx, newReserveAddr, precisebanktypes.IntegerCoinDenom)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			require.Equal(t, tt.initialReserve, oldReserveBalance.Amount, "initial x/evmutil reserve balance")
 | 
					 | 
				
			||||||
			require.True(t, newReserveBalance.IsZero(), "empty initial new reserve")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Set accounts
 | 
					 | 
				
			||||||
			for i, balance := range tt.fractionalBalances {
 | 
					 | 
				
			||||||
				addr := sdk.AccAddress([]byte(strconv.Itoa(i)))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				err := evmuk.SetBalance(ctx, addr, balance)
 | 
					 | 
				
			||||||
				require.NoError(t, err)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Run full x/evmutil -> x/precisebank migration
 | 
					 | 
				
			||||||
			err = app.MigrateEvmutilToPrecisebank(
 | 
					 | 
				
			||||||
				ctx,
 | 
					 | 
				
			||||||
				ak,
 | 
					 | 
				
			||||||
				bk,
 | 
					 | 
				
			||||||
				evmuk,
 | 
					 | 
				
			||||||
				pbk,
 | 
					 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
			require.NoError(t, err)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Check old reserve is empty
 | 
					 | 
				
			||||||
			oldReserveBalanceAfter := bk.GetBalance(ctx, oldReserveAddr, precisebanktypes.IntegerCoinDenom)
 | 
					 | 
				
			||||||
			require.True(t, oldReserveBalanceAfter.IsZero(), "old reserve should be empty")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Check new reserve fully backs fractional balances
 | 
					 | 
				
			||||||
			newReserveBalanceAfter := bk.GetBalance(ctx, newReserveAddr, precisebanktypes.IntegerCoinDenom)
 | 
					 | 
				
			||||||
			fractionalBalanceTotal := pbk.GetTotalSumFractionalBalances(ctx)
 | 
					 | 
				
			||||||
			remainder := pbk.GetRemainderAmount(ctx)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			expectedReserveBal := fractionalBalanceTotal.Add(remainder)
 | 
					 | 
				
			||||||
			require.Equal(
 | 
					 | 
				
			||||||
				t,
 | 
					 | 
				
			||||||
				expectedReserveBal,
 | 
					 | 
				
			||||||
				newReserveBalanceAfter.Amount.Mul(precisebanktypes.ConversionFactor()),
 | 
					 | 
				
			||||||
				"new reserve should equal total fractional balances",
 | 
					 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Check balances are deleted in evmutil and migrated to precisebank
 | 
					 | 
				
			||||||
			for i := range tt.fractionalBalances {
 | 
					 | 
				
			||||||
				addr := sdk.AccAddress([]byte(strconv.Itoa(i)))
 | 
					 | 
				
			||||||
				acc := evmuk.GetAccount(ctx, addr)
 | 
					 | 
				
			||||||
				require.Nil(t, acc, "account should be deleted")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				balance := pbk.GetFractionalBalance(ctx, addr)
 | 
					 | 
				
			||||||
				require.Equal(t, tt.fractionalBalances[i], balance, "balance should be migrated")
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Checks balances valid and remainder
 | 
					 | 
				
			||||||
			res, stop := precisebankkeeper.AllInvariants(pbk)(ctx)
 | 
					 | 
				
			||||||
			require.Falsef(t, stop, "invariants should pass: %s", res)
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestTransferFractionalBalances(t *testing.T) {
 | 
					 | 
				
			||||||
	tests := []struct {
 | 
					 | 
				
			||||||
		name               string
 | 
					 | 
				
			||||||
		fractionalBalances []sdkmath.Int
 | 
					 | 
				
			||||||
	}{
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			"no fractional balances",
 | 
					 | 
				
			||||||
			[]sdkmath.Int{},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			"balanced fractional balances",
 | 
					 | 
				
			||||||
			[]sdkmath.Int{
 | 
					 | 
				
			||||||
				// 4 accounts
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			"unbalanced balances",
 | 
					 | 
				
			||||||
			[]sdkmath.Int{
 | 
					 | 
				
			||||||
				// 3 accounts
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, tt := range tests {
 | 
					 | 
				
			||||||
		t.Run(tt.name, func(t *testing.T) {
 | 
					 | 
				
			||||||
			tApp := app.NewTestApp()
 | 
					 | 
				
			||||||
			tApp.InitializeFromGenesisStates()
 | 
					 | 
				
			||||||
			ctx := tApp.NewContext(true, tmproto.Header{Height: 1, Time: time.Now()})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			evmutilk := tApp.GetEvmutilKeeper()
 | 
					 | 
				
			||||||
			pbk := tApp.GetPrecisebankKeeper()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			for i, balance := range tt.fractionalBalances {
 | 
					 | 
				
			||||||
				addr := sdk.AccAddress([]byte(strconv.Itoa(i)))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				err := evmutilk.SetBalance(ctx, addr, balance)
 | 
					 | 
				
			||||||
				require.NoError(t, err)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Run balance transfer
 | 
					 | 
				
			||||||
			aggregateSum, err := app.TransferFractionalBalances(
 | 
					 | 
				
			||||||
				ctx,
 | 
					 | 
				
			||||||
				evmutilk,
 | 
					 | 
				
			||||||
				pbk,
 | 
					 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
			require.NoError(t, err)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Check balances are deleted in evmutil and migrated to precisebank
 | 
					 | 
				
			||||||
			sum := sdkmath.ZeroInt()
 | 
					 | 
				
			||||||
			for i := range tt.fractionalBalances {
 | 
					 | 
				
			||||||
				sum = sum.Add(tt.fractionalBalances[i])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				addr := sdk.AccAddress([]byte(strconv.Itoa(i)))
 | 
					 | 
				
			||||||
				acc := evmutilk.GetAccount(ctx, addr)
 | 
					 | 
				
			||||||
				require.Nil(t, acc, "account should be deleted")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				balance := pbk.GetFractionalBalance(ctx, addr)
 | 
					 | 
				
			||||||
				require.Equal(t, tt.fractionalBalances[i], balance, "balance should be migrated")
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			require.Equal(t, sum, aggregateSum, "aggregate sum should be correct")
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestInitializeRemainder(t *testing.T) {
 | 
					 | 
				
			||||||
	tests := []struct {
 | 
					 | 
				
			||||||
		name             string
 | 
					 | 
				
			||||||
		giveAggregateSum sdkmath.Int
 | 
					 | 
				
			||||||
		wantRemainder    sdkmath.Int
 | 
					 | 
				
			||||||
	}{
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			"0 remainder, 1ukava",
 | 
					 | 
				
			||||||
			precisebanktypes.ConversionFactor(),
 | 
					 | 
				
			||||||
			sdkmath.NewInt(0),
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			"0 remainder, multiple ukava",
 | 
					 | 
				
			||||||
			precisebanktypes.ConversionFactor().MulRaw(5),
 | 
					 | 
				
			||||||
			sdkmath.NewInt(0),
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			"non-zero remainder, min",
 | 
					 | 
				
			||||||
			precisebanktypes.ConversionFactor().SubRaw(1),
 | 
					 | 
				
			||||||
			sdkmath.NewInt(1),
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			"non-zero remainder, max",
 | 
					 | 
				
			||||||
			sdkmath.NewInt(1),
 | 
					 | 
				
			||||||
			precisebanktypes.ConversionFactor().SubRaw(1),
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			"non-zero remainder, half",
 | 
					 | 
				
			||||||
			precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
			precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, tt := range tests {
 | 
					 | 
				
			||||||
		t.Run(tt.name, func(t *testing.T) {
 | 
					 | 
				
			||||||
			tApp := app.NewTestApp()
 | 
					 | 
				
			||||||
			tApp.InitializeFromGenesisStates()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			pbk := tApp.GetPrecisebankKeeper()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			ctx := tApp.NewContext(true, tmproto.Header{Height: 1, Time: time.Now()})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			remainder := app.InitializeRemainder(
 | 
					 | 
				
			||||||
				ctx,
 | 
					 | 
				
			||||||
				tApp.GetPrecisebankKeeper(),
 | 
					 | 
				
			||||||
				tt.giveAggregateSum,
 | 
					 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
			require.Equal(t, tt.wantRemainder, remainder)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Check actual state
 | 
					 | 
				
			||||||
			remainderAfter := pbk.GetRemainderAmount(ctx)
 | 
					 | 
				
			||||||
			require.Equal(t, tt.wantRemainder, remainderAfter)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Not checking invariants here since it requires actual balance state
 | 
					 | 
				
			||||||
			aggregateSumWithRemainder := tt.giveAggregateSum.Add(remainder)
 | 
					 | 
				
			||||||
			require.True(
 | 
					 | 
				
			||||||
				t,
 | 
					 | 
				
			||||||
				aggregateSumWithRemainder.
 | 
					 | 
				
			||||||
					Mod(precisebanktypes.ConversionFactor()).
 | 
					 | 
				
			||||||
					IsZero(),
 | 
					 | 
				
			||||||
				"remainder + aggregate sum should be a multiple of the conversion factor",
 | 
					 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestTransferFractionalBalanceReserve(t *testing.T) {
 | 
					 | 
				
			||||||
	tests := []struct {
 | 
					 | 
				
			||||||
		name               string
 | 
					 | 
				
			||||||
		initialReserve     sdk.Coin
 | 
					 | 
				
			||||||
		fractionalBalances []sdkmath.Int
 | 
					 | 
				
			||||||
	}{
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			"balanced reserve, no remainder",
 | 
					 | 
				
			||||||
			sdk.NewCoin(precisebanktypes.IntegerCoinDenom, sdk.NewInt(1)),
 | 
					 | 
				
			||||||
			[]sdkmath.Int{
 | 
					 | 
				
			||||||
				// 2 accounts
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			"insufficient reserve",
 | 
					 | 
				
			||||||
			sdk.NewCoin(precisebanktypes.IntegerCoinDenom, sdk.NewInt(1)),
 | 
					 | 
				
			||||||
			[]sdkmath.Int{
 | 
					 | 
				
			||||||
				// 4 accounts, total 2 int units
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			"extra reserve funds",
 | 
					 | 
				
			||||||
			sdk.NewCoin(precisebanktypes.IntegerCoinDenom, sdk.NewInt(2)),
 | 
					 | 
				
			||||||
			[]sdkmath.Int{
 | 
					 | 
				
			||||||
				// 2 accounts, total 1 int units
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			"insufficient reserve, with remainder",
 | 
					 | 
				
			||||||
			sdk.NewCoin(precisebanktypes.IntegerCoinDenom, sdk.NewInt(1)),
 | 
					 | 
				
			||||||
			[]sdkmath.Int{
 | 
					 | 
				
			||||||
				// 5 accounts, total 2.5 int units
 | 
					 | 
				
			||||||
				// Expected 3 int units in reserve, 0.5 remainder
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			"extra reserve funds, with remainder",
 | 
					 | 
				
			||||||
			sdk.NewCoin(precisebanktypes.IntegerCoinDenom, sdk.NewInt(3)),
 | 
					 | 
				
			||||||
			[]sdkmath.Int{
 | 
					 | 
				
			||||||
				// 3 accounts, total 1.5 int units.
 | 
					 | 
				
			||||||
				// Expected 2 int units in reserve, 0.5 remainder
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
				precisebanktypes.ConversionFactor().QuoRaw(2),
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, tt := range tests {
 | 
					 | 
				
			||||||
		t.Run(tt.name, func(t *testing.T) {
 | 
					 | 
				
			||||||
			tApp := app.NewTestApp()
 | 
					 | 
				
			||||||
			tApp.InitializeFromGenesisStates()
 | 
					 | 
				
			||||||
			ctx := tApp.NewContext(true, tmproto.Header{Height: 1, Time: time.Now()})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			bk := tApp.GetBankKeeper()
 | 
					 | 
				
			||||||
			pbk := tApp.GetPrecisebankKeeper()
 | 
					 | 
				
			||||||
			err := bk.MintCoins(ctx, evmutiltypes.ModuleName, sdk.NewCoins(tt.initialReserve))
 | 
					 | 
				
			||||||
			require.NoError(t, err)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			oldReserveAddr := tApp.GetAccountKeeper().GetModuleAddress(evmutiltypes.ModuleName)
 | 
					 | 
				
			||||||
			newReserveAddr := tApp.GetAccountKeeper().GetModuleAddress(precisebanktypes.ModuleName)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Double check balances
 | 
					 | 
				
			||||||
			oldReserveBalance := bk.GetBalance(ctx, oldReserveAddr, precisebanktypes.IntegerCoinDenom)
 | 
					 | 
				
			||||||
			newReserveBalance := bk.GetBalance(ctx, newReserveAddr, precisebanktypes.IntegerCoinDenom)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			require.Equal(t, tt.initialReserve, oldReserveBalance)
 | 
					 | 
				
			||||||
			require.True(t, newReserveBalance.IsZero(), "empty initial new reserve")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			for i, balance := range tt.fractionalBalances {
 | 
					 | 
				
			||||||
				addr := sdk.AccAddress([]byte{byte(i)})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				require.NotPanics(t, func() {
 | 
					 | 
				
			||||||
					pbk.SetFractionalBalance(ctx, addr, balance)
 | 
					 | 
				
			||||||
				}, "given fractional balances should be valid")
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Run reserve migration
 | 
					 | 
				
			||||||
			err = app.TransferFractionalBalanceReserve(
 | 
					 | 
				
			||||||
				ctx,
 | 
					 | 
				
			||||||
				tApp.GetAccountKeeper(),
 | 
					 | 
				
			||||||
				bk,
 | 
					 | 
				
			||||||
				tApp.GetPrecisebankKeeper(),
 | 
					 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
			require.NoError(t, err)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Check old reserve is empty
 | 
					 | 
				
			||||||
			oldReserveBalanceAfter := bk.GetBalance(ctx, oldReserveAddr, precisebanktypes.IntegerCoinDenom)
 | 
					 | 
				
			||||||
			require.True(t, oldReserveBalanceAfter.IsZero(), "old reserve should be empty")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Check new reserve fully backs fractional balances
 | 
					 | 
				
			||||||
			newReserveBalanceAfter := bk.GetBalance(ctx, newReserveAddr, precisebanktypes.IntegerCoinDenom)
 | 
					 | 
				
			||||||
			fractionalBalanceTotal := pbk.GetTotalSumFractionalBalances(ctx)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			expectedReserveBal := fractionalBalanceTotal.
 | 
					 | 
				
			||||||
				Quo(precisebanktypes.ConversionFactor())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Check if theres a remainder
 | 
					 | 
				
			||||||
			if fractionalBalanceTotal.Mod(precisebanktypes.ConversionFactor()).IsPositive() {
 | 
					 | 
				
			||||||
				expectedReserveBal = expectedReserveBal.Add(sdkmath.OneInt())
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			require.Equal(
 | 
					 | 
				
			||||||
				t,
 | 
					 | 
				
			||||||
				expectedReserveBal,
 | 
					 | 
				
			||||||
				newReserveBalanceAfter.Amount,
 | 
					 | 
				
			||||||
				"new reserve should equal total fractional balances + remainder",
 | 
					 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -126,8 +126,6 @@ func (ac appCreator) newApp(
 | 
				
			|||||||
		baseapp.SetMempool(mempool),
 | 
							baseapp.SetMempool(mempool),
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	bApp.SetTxEncoder(ac.encodingConfig.TxConfig.TxEncoder())
 | 
						bApp.SetTxEncoder(ac.encodingConfig.TxConfig.TxEncoder())
 | 
				
			||||||
	abciProposalHandler := app.NewDefaultProposalHandler(mempool, bApp)
 | 
					 | 
				
			||||||
	bApp.SetPrepareProposal(abciProposalHandler.PrepareProposalHandler())
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	newApp := app.NewApp(
 | 
						newApp := app.NewApp(
 | 
				
			||||||
		homeDir, traceStore, ac.encodingConfig,
 | 
							homeDir, traceStore, ac.encodingConfig,
 | 
				
			||||||
@ -142,6 +140,10 @@ func (ac appCreator) newApp(
 | 
				
			|||||||
			EVMMaxGasWanted:       cast.ToUint64(appOpts.Get(ethermintflags.EVMMaxTxGasWanted)),
 | 
								EVMMaxGasWanted:       cast.ToUint64(appOpts.Get(ethermintflags.EVMMaxTxGasWanted)),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		bApp,
 | 
							bApp,
 | 
				
			||||||
 | 
							func(k app.FeeMarketKeeper) sdk.PrepareProposalHandler {
 | 
				
			||||||
 | 
								abciProposalHandler := app.NewDefaultProposalHandler(mempool, bApp, k)
 | 
				
			||||||
 | 
								return abciProposalHandler.PrepareProposalHandler()
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return newApp
 | 
						return newApp
 | 
				
			||||||
@ -170,14 +172,14 @@ func (ac appCreator) appExport(
 | 
				
			|||||||
	var tempApp *app.App
 | 
						var tempApp *app.App
 | 
				
			||||||
	if height != -1 {
 | 
						if height != -1 {
 | 
				
			||||||
		bApp := app.NewBaseApp(logger, db, ac.encodingConfig)
 | 
							bApp := app.NewBaseApp(logger, db, ac.encodingConfig)
 | 
				
			||||||
		tempApp = app.NewApp(homePath, traceStore, ac.encodingConfig, options, bApp)
 | 
							tempApp = app.NewApp(homePath, traceStore, ac.encodingConfig, options, bApp, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := tempApp.LoadHeight(height); err != nil {
 | 
							if err := tempApp.LoadHeight(height); err != nil {
 | 
				
			||||||
			return servertypes.ExportedApp{}, err
 | 
								return servertypes.ExportedApp{}, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		bApp := app.NewBaseApp(logger, db, ac.encodingConfig)
 | 
							bApp := app.NewBaseApp(logger, db, ac.encodingConfig)
 | 
				
			||||||
		tempApp = app.NewApp(homePath, traceStore, ac.encodingConfig, options, bApp)
 | 
							tempApp = app.NewApp(homePath, traceStore, ac.encodingConfig, options, bApp, nil)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return tempApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport)
 | 
						return tempApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							@ -250,7 +250,7 @@ replace (
 | 
				
			|||||||
	// TODO: Tag before release
 | 
						// TODO: Tag before release
 | 
				
			||||||
	github.com/ethereum/go-ethereum => github.com/evmos/go-ethereum v1.10.26-evmos-rc2
 | 
						github.com/ethereum/go-ethereum => github.com/evmos/go-ethereum v1.10.26-evmos-rc2
 | 
				
			||||||
	// Use ethermint fork that respects min-gas-price with NoBaseFee true and london enabled, and includes eip712 support
 | 
						// Use ethermint fork that respects min-gas-price with NoBaseFee true and london enabled, and includes eip712 support
 | 
				
			||||||
	github.com/evmos/ethermint => github.com/0glabs/ethermint v0.21.0-0g.v3.1.9
 | 
						github.com/evmos/ethermint => github.com/0glabs/ethermint v0.21.0-0g.v3.1.10
 | 
				
			||||||
	// See https://github.com/cosmos/cosmos-sdk/pull/10401, https://github.com/cosmos/cosmos-sdk/commit/0592ba6158cd0bf49d894be1cef4faeec59e8320
 | 
						// See https://github.com/cosmos/cosmos-sdk/pull/10401, https://github.com/cosmos/cosmos-sdk/commit/0592ba6158cd0bf49d894be1cef4faeec59e8320
 | 
				
			||||||
	github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.9.0
 | 
						github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.9.0
 | 
				
			||||||
	// Downgraded to avoid bugs in following commits which causes "version does not exist" errors
 | 
						// Downgraded to avoid bugs in following commits which causes "version does not exist" errors
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
									
									
									
									
								
							@ -213,8 +213,8 @@ github.com/0glabs/cometbft v0.37.9-0glabs.1 h1:KQJG17Y21suKP3QNICLto4b5Ak73XbSmK
 | 
				
			|||||||
github.com/0glabs/cometbft v0.37.9-0glabs.1/go.mod h1:j0Q3RqrCd+cztWCugs3obbzC4NyHGBPZZjtm/fWV00I=
 | 
					github.com/0glabs/cometbft v0.37.9-0glabs.1/go.mod h1:j0Q3RqrCd+cztWCugs3obbzC4NyHGBPZZjtm/fWV00I=
 | 
				
			||||||
github.com/0glabs/cosmos-sdk v0.47.10-0glabs.10 h1:NJp0RwczHBO4EvrQdDxxftHOgUDBtNh7M/vpaG7wFtQ=
 | 
					github.com/0glabs/cosmos-sdk v0.47.10-0glabs.10 h1:NJp0RwczHBO4EvrQdDxxftHOgUDBtNh7M/vpaG7wFtQ=
 | 
				
			||||||
github.com/0glabs/cosmos-sdk v0.47.10-0glabs.10/go.mod h1:KskIVnhXTFqrw7CDccMvx7To5KzUsOomIsQV7sPGOog=
 | 
					github.com/0glabs/cosmos-sdk v0.47.10-0glabs.10/go.mod h1:KskIVnhXTFqrw7CDccMvx7To5KzUsOomIsQV7sPGOog=
 | 
				
			||||||
github.com/0glabs/ethermint v0.21.0-0g.v3.1.9 h1:oTHp7tSAqoML7D/+RXsBzA9DsbZ80MX93VJYjR/Akh4=
 | 
					github.com/0glabs/ethermint v0.21.0-0g.v3.1.10 h1:DE8hK2OJp9rKYdT2Y0G259/6nAFcOQi383l2e7/VFnE=
 | 
				
			||||||
github.com/0glabs/ethermint v0.21.0-0g.v3.1.9/go.mod h1:6e/gOcDLhvlDWK3JLJVBgki0gD6H4E1eG7l9byocgWA=
 | 
					github.com/0glabs/ethermint v0.21.0-0g.v3.1.10/go.mod h1:6e/gOcDLhvlDWK3JLJVBgki0gD6H4E1eG7l9byocgWA=
 | 
				
			||||||
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs=
 | 
					github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs=
 | 
				
			||||||
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4=
 | 
					github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4=
 | 
				
			||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM=
 | 
					github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM=
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user