diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 0ce752103c..01c8141d4a 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -103,6 +103,21 @@ func NewSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBac return NewSimulatedBackendWithDatabase(rawdb.NewMemoryDatabase(), alloc, gasLimit) } +func NewSimulatedBackendChain(database ethdb.Database, blockchain *core.BlockChain) *SimulatedBackend { + backend := &SimulatedBackend{ + database: database, + blockchain: blockchain, + config: blockchain.Config(), + } + + filterBackend := &filterBackend{database, blockchain, backend} + backend.filterSystem = filters.NewFilterSystem(filterBackend, filters.Config{}) + backend.events = filters.NewEventSystem(backend.filterSystem, false) + backend.rollback(blockchain.CurrentBlock()) + + return backend +} + // Close terminates the underlying blockchain's update loop. func (b *SimulatedBackend) Close() error { b.blockchain.Stop() diff --git a/builder/builder.go b/builder/builder.go index c732bf0553..12ef6ca117 100644 --- a/builder/builder.go +++ b/builder/builder.go @@ -44,7 +44,7 @@ type IRelay interface { } type IBuilder interface { - OnPayloadAttribute(attrs *BuilderPayloadAttributes) error + OnPayloadAttribute(attrs *types.BuilderPayloadAttributes) error Start() error Stop() error } @@ -63,7 +63,7 @@ type Builder struct { slotMu sync.Mutex slot uint64 - slotAttrs []BuilderPayloadAttributes + slotAttrs []types.BuilderPayloadAttributes slotCtx context.Context slotCtxCancel context.CancelFunc } @@ -99,7 +99,7 @@ func (b *Builder) Stop() error { return nil } -func (b *Builder) onSealedBlock(block *types.Block, ordersClosedAt time.Time, sealedAt time.Time, commitedBundles []types.SimulatedBundle, allBundles []types.SimulatedBundle, proposerPubkey boostTypes.PublicKey, vd ValidatorData, attrs *BuilderPayloadAttributes) error { +func (b *Builder) onSealedBlock(block *types.Block, ordersClosedAt time.Time, sealedAt time.Time, commitedBundles []types.SimulatedBundle, allBundles []types.SimulatedBundle, proposerPubkey boostTypes.PublicKey, vd ValidatorData, attrs *types.BuilderPayloadAttributes) error { executableData := beacon.BlockToExecutableData(block) payload, err := executableDataToExecutionPayload(executableData) if err != nil { @@ -157,7 +157,7 @@ func (b *Builder) onSealedBlock(block *types.Block, ordersClosedAt time.Time, se return nil } -func (b *Builder) OnPayloadAttribute(attrs *BuilderPayloadAttributes) error { +func (b *Builder) OnPayloadAttribute(attrs *types.BuilderPayloadAttributes) error { if attrs == nil { return nil } @@ -222,7 +222,7 @@ type blockQueueEntry struct { allBundles []types.SimulatedBundle } -func (b *Builder) runBuildingJob(slotCtx context.Context, proposerPubkey boostTypes.PublicKey, vd ValidatorData, attrs *BuilderPayloadAttributes) { +func (b *Builder) runBuildingJob(slotCtx context.Context, proposerPubkey boostTypes.PublicKey, vd ValidatorData, attrs *types.BuilderPayloadAttributes) { ctx, cancel := context.WithTimeout(slotCtx, 12*time.Second) defer cancel() diff --git a/builder/builder_test.go b/builder/builder_test.go index 7857a82762..c1a413d3b4 100644 --- a/builder/builder_test.go +++ b/builder/builder_test.go @@ -64,7 +64,7 @@ func TestOnPayloadAttributes(t *testing.T) { require.NoError(t, err) testBlock.Profit = big.NewInt(10) - testPayloadAttributes := &BuilderPayloadAttributes{ + testPayloadAttributes := &types.BuilderPayloadAttributes{ Timestamp: hexutil.Uint64(104), Random: common.Hash{0x05, 0x10}, SuggestedFeeRecipient: common.Address{0x04, 0x10}, diff --git a/builder/eth_service.go b/builder/eth_service.go index 47ef090d5c..5c5366930f 100644 --- a/builder/eth_service.go +++ b/builder/eth_service.go @@ -13,7 +13,7 @@ import ( ) type IEthereumService interface { - BuildBlock(attrs *BuilderPayloadAttributes, sealedBlockCallback miner.BlockHookFn) error + BuildBlock(attrs *types.BuilderPayloadAttributes, sealedBlockCallback miner.BlockHookFn) error GetBlockByHash(hash common.Hash) *types.Block Synced() bool } @@ -26,7 +26,7 @@ type testEthereumService struct { testAllBundles []types.SimulatedBundle } -func (t *testEthereumService) BuildBlock(attrs *BuilderPayloadAttributes, sealedBlockCallback miner.BlockHookFn) error { +func (t *testEthereumService) BuildBlock(attrs *types.BuilderPayloadAttributes, sealedBlockCallback miner.BlockHookFn) error { sealedBlockCallback(t.testBlock, time.Now(), t.testBundlesMerged, t.testAllBundles) return nil } @@ -43,7 +43,7 @@ func NewEthereumService(eth *eth.Ethereum) *EthereumService { return &EthereumService{eth: eth} } -func (s *EthereumService) BuildBlock(attrs *BuilderPayloadAttributes, sealedBlockCallback miner.BlockHookFn) error { +func (s *EthereumService) BuildBlock(attrs *types.BuilderPayloadAttributes, sealedBlockCallback miner.BlockHookFn) error { // Send a request to generate a full block in the background. // The result can be obtained via the returned channel. resCh, err := s.eth.Miner().GetSealingBlockAsync(attrs.HeadHash, uint64(attrs.Timestamp), attrs.SuggestedFeeRecipient, attrs.GasLimit, attrs.Random, false, sealedBlockCallback) diff --git a/builder/eth_service_test.go b/builder/eth_service_test.go index e13a05e288..297a398fce 100644 --- a/builder/eth_service_test.go +++ b/builder/eth_service_test.go @@ -82,7 +82,7 @@ func TestBuildBlock(t *testing.T) { parent := ethservice.BlockChain().CurrentBlock() - testPayloadAttributes := &BuilderPayloadAttributes{ + testPayloadAttributes := &types.BuilderPayloadAttributes{ Timestamp: hexutil.Uint64(parent.Time() + 1), Random: common.Hash{0x05, 0x10}, SuggestedFeeRecipient: common.Address{0x04, 0x10}, diff --git a/builder/local_relay_test.go b/builder/local_relay_test.go index 39c202629e..d992db064a 100644 --- a/builder/local_relay_test.go +++ b/builder/local_relay_test.go @@ -146,7 +146,7 @@ func TestGetHeader(t *testing.T) { require.Equal(t, ``, rr.Body.String()) require.Equal(t, 204, rr.Code) - backend.OnPayloadAttribute(&BuilderPayloadAttributes{}) + backend.OnPayloadAttribute(&types.BuilderPayloadAttributes{}) time.Sleep(2 * time.Second) path = fmt.Sprintf("/eth/v1/builder/header/%d/%s/%s", 0, forkchoiceData.ParentHash.Hex(), validator.Pk.String()) @@ -194,7 +194,7 @@ func TestGetPayload(t *testing.T) { backend, relay, validator := newTestBackend(t, forkchoiceData, forkchoiceBlock) registerValidator(t, validator, relay) - backend.OnPayloadAttribute(&BuilderPayloadAttributes{}) + backend.OnPayloadAttribute(&types.BuilderPayloadAttributes{}) time.Sleep(2 * time.Second) path := fmt.Sprintf("/eth/v1/builder/header/%d/%s/%s", 0, forkchoiceData.ParentHash.Hex(), validator.Pk.String()) diff --git a/builder/service.go b/builder/service.go index e343bcfae1..2481bf5400 100644 --- a/builder/service.go +++ b/builder/service.go @@ -31,15 +31,6 @@ const ( _PathGetPayload = "/eth/v1/builder/blinded_blocks" ) -type BuilderPayloadAttributes struct { - Timestamp hexutil.Uint64 `json:"timestamp"` - Random common.Hash `json:"prevRandao"` - SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient,omitempty"` - Slot uint64 `json:"slot"` - HeadHash common.Hash `json:"blockHash"` - GasLimit uint64 -} - type Service struct { srv *http.Server builder IBuilder @@ -64,7 +55,7 @@ func (s *Service) Stop() error { return nil } -func (s *Service) PayloadAttributes(payloadAttributes *BuilderPayloadAttributes) error { +func (s *Service) PayloadAttributes(payloadAttributes *types.BuilderPayloadAttributes) error { return s.builder.OnPayloadAttribute(payloadAttributes) } @@ -83,7 +74,7 @@ func getRouter(localRelay *LocalRelay) http.Handler { return loggedRouter } -func NewService(listenAddr string, localRelay *LocalRelay, builder *Builder) *Service { +func NewService(listenAddr string, localRelay *LocalRelay, builder IBuilder) *Service { var srv *http.Server if localRelay != nil { srv = &http.Server{ @@ -105,26 +96,11 @@ func NewService(listenAddr string, localRelay *LocalRelay, builder *Builder) *Se } func Register(stack *node.Node, backend *eth.Ethereum, cfg *Config) error { - envRelaySkBytes, err := hexutil.Decode(cfg.RelaySecretKey) - if err != nil { - return errors.New("incorrect builder API secret key provided") - } - - relaySk, err := bls.SecretKeyFromBytes(envRelaySkBytes[:]) - if err != nil { - return errors.New("incorrect builder API secret key provided") - } - envBuilderSkBytes, err := hexutil.Decode(cfg.BuilderSecretKey) if err != nil { return errors.New("incorrect builder API secret key provided") } - builderSk, err := bls.SecretKeyFromBytes(envBuilderSkBytes[:]) - if err != nil { - return errors.New("incorrect builder API secret key provided") - } - genesisForkVersionBytes, err := hexutil.Decode(cfg.GenesisForkVersion) if err != nil { return fmt.Errorf("invalid genesisForkVersion: %w", err) @@ -148,6 +124,16 @@ func Register(stack *node.Node, backend *eth.Ethereum, cfg *Config) error { var localRelay *LocalRelay if cfg.EnableLocalRelay { + envRelaySkBytes, err := hexutil.Decode(cfg.RelaySecretKey) + if err != nil { + return errors.New("incorrect builder API secret key provided") + } + + relaySk, err := bls.SecretKeyFromBytes(envRelaySkBytes[:]) + if err != nil { + return errors.New("incorrect builder API secret key provided") + } + localRelay = NewLocalRelay(relaySk, beaconClient, builderSigningDomain, proposerSigningDomain, ForkData{cfg.GenesisForkVersion, cfg.BellatrixForkVersion, cfg.GenesisValidatorsRoot}, cfg.EnableValidatorChecks) } @@ -203,6 +189,12 @@ func Register(stack *node.Node, backend *eth.Ethereum, cfg *Config) error { } ethereumService := NewEthereumService(backend) + + builderSk, err := bls.SecretKeyFromBytes(envBuilderSkBytes[:]) + if err != nil { + return errors.New("incorrect builder API secret key provided") + } + builderBackend := NewBuilder(builderSk, ds, relay, builderSigningDomain, ethereumService, cfg.DryRun, validator) builderService := NewService(cfg.ListenAddr, localRelay, builderBackend) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 52d93c75db..324f0ab348 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -30,7 +30,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/scwallet" "github.com/ethereum/go-ethereum/accounts/usbwallet" - builder "github.com/ethereum/go-ethereum/builder" + "github.com/ethereum/go-ethereum/builder" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/core/rawdb" blockvalidationapi "github.com/ethereum/go-ethereum/eth/block-validation" @@ -171,7 +171,6 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { override := ctx.Bool(utils.OverrideTerminalTotalDifficultyPassed.Name) cfg.Eth.OverrideTerminalTotalDifficultyPassed = &override } - // Construct the backend service. backend, eth := utils.RegisterEthService(stack, &cfg.Eth, &cfg.Builder) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 7b55b48745..217f00359e 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -32,7 +32,7 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" - builder "github.com/ethereum/go-ethereum/builder" + "github.com/ethereum/go-ethereum/builder" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/fdlimit" "github.com/ethereum/go-ethereum/consensus" diff --git a/core/types/builder.go b/core/types/builder.go new file mode 100644 index 0000000000..b851149daa --- /dev/null +++ b/core/types/builder.go @@ -0,0 +1,15 @@ +package types + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" +) + +type BuilderPayloadAttributes struct { + Timestamp hexutil.Uint64 `json:"timestamp"` + Random common.Hash `json:"prevRandao"` + SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient,omitempty"` + Slot uint64 `json:"slot"` + HeadHash common.Hash `json:"blockHash"` + GasLimit uint64 +} diff --git a/core/types/transaction.go b/core/types/transaction.go index b87549ac1f..017ad735bf 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -459,13 +459,39 @@ func (s TxByNonce) Len() int { return len(s) } func (s TxByNonce) Less(i, j int) bool { return s[i].Nonce() < s[j].Nonce() } func (s TxByNonce) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +type _Order interface { + AsTx() *Transaction + AsBundle() *SimulatedBundle +} + +type _TxOrder struct { + tx *Transaction +} + +func (o _TxOrder) AsTx() *Transaction { return o.tx } +func (o _TxOrder) AsBundle() *SimulatedBundle { return nil } + +type _BundleOrder struct { + bundle *SimulatedBundle +} + +func (o _BundleOrder) AsTx() *Transaction { return nil } +func (o _BundleOrder) AsBundle() *SimulatedBundle { return o.bundle } + // TxWithMinerFee wraps a transaction with its gas price or effective miner gasTipCap type TxWithMinerFee struct { - Tx *Transaction - Bundle *SimulatedBundle + order _Order minerFee *big.Int } +func (t *TxWithMinerFee) Tx() *Transaction { + return t.order.AsTx() +} + +func (t *TxWithMinerFee) Bundle() *SimulatedBundle { + return t.order.AsBundle() +} + // NewTxWithMinerFee creates a wrapped transaction, calculating the effective // miner gasTipCap if a base fee is provided. // Returns error in case of a negative effective miner gasTipCap. @@ -475,7 +501,7 @@ func NewTxWithMinerFee(tx *Transaction, baseFee *big.Int) (*TxWithMinerFee, erro return nil, err } return &TxWithMinerFee{ - Tx: tx, + order: _TxOrder{tx}, minerFee: minerFee, }, nil } @@ -484,7 +510,7 @@ func NewTxWithMinerFee(tx *Transaction, baseFee *big.Int) (*TxWithMinerFee, erro func NewBundleWithMinerFee(bundle *SimulatedBundle, baseFee *big.Int) (*TxWithMinerFee, error) { minerFee := bundle.MevGasPrice return &TxWithMinerFee{ - Bundle: bundle, + order: _BundleOrder{bundle}, minerFee: minerFee, }, nil } @@ -499,13 +525,14 @@ func (s TxByPriceAndTime) Less(i, j int) bool { // deterministic sorting cmp := s[i].minerFee.Cmp(s[j].minerFee) if cmp == 0 { - if s[i].Tx != nil && s[j].Tx != nil { - return s[i].Tx.time.Before(s[j].Tx.time) - } else if s[i].Bundle != nil && s[j].Bundle != nil { - return s[i].Bundle.TotalGasUsed <= s[j].Bundle.TotalGasUsed - } else if s[i].Bundle != nil { + if s[i].Tx() != nil && s[j].Tx() != nil { + return s[i].Tx().time.Before(s[j].Tx().time) + } else if s[i].Bundle() != nil && s[j].Bundle() != nil { + return s[i].Bundle().TotalGasUsed <= s[j].Bundle().TotalGasUsed + } else if s[i].Bundle() != nil { return false } + return true } return cmp > 0 @@ -549,6 +576,7 @@ func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transa } heads = append(heads, wrapped) } + for from, accTxs := range txs { acc, _ := Sender(signer, accTxs[0]) wrapped, err := NewTxWithMinerFee(accTxs[0], baseFee) @@ -594,8 +622,8 @@ func (t *TransactionsByPriceAndNonce) Peek() *TxWithMinerFee { // Shift replaces the current best head with the next one from the same account. func (t *TransactionsByPriceAndNonce) Shift() { - if t.heads[0].Tx != nil { - acc, _ := Sender(t.signer, t.heads[0].Tx) + if tx := t.heads[0].Tx(); tx != nil { + acc, _ := Sender(t.signer, tx) if txs, ok := t.txs[acc]; ok && len(txs) > 0 { if wrapped, err := NewTxWithMinerFee(txs[0], t.baseFee); err == nil { t.heads[0], t.txs[acc] = wrapped, txs[1:] diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index 47a6bc638e..386e68bb90 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -324,7 +324,7 @@ func testTransactionPriceNonceSort(t *testing.T, baseFee *big.Int) { txs := Transactions{} for tx := txset.Peek(); tx != nil; tx = txset.Peek() { - txs = append(txs, tx.Tx) + txs = append(txs, tx.Tx()) txset.Shift() } if len(txs) != expectedCount { @@ -381,7 +381,7 @@ func TestTransactionTimeSort(t *testing.T) { txs := Transactions{} for tx := txset.Peek(); tx != nil; tx = txset.Peek() { - txs = append(txs, tx.Tx) + txs = append(txs, tx.Tx()) txset.Shift() } if len(txs) != len(keys) { diff --git a/eth/tracers/logger/account_touch_tracer.go b/eth/tracers/logger/account_touch_tracer.go index 4c24779637..ef3bfeeb94 100644 --- a/eth/tracers/logger/account_touch_tracer.go +++ b/eth/tracers/logger/account_touch_tracer.go @@ -33,10 +33,14 @@ type AccountTouchTracer struct { // including tx sender and tx.to from the top level call func NewAccountTouchTracer() *AccountTouchTracer { return &AccountTouchTracer{ - touched: map[common.Address]struct{}{}, + touched: make(map[common.Address]struct{}), } } +func (t *AccountTouchTracer) TouchedAddressesSet() map[common.Address]struct{} { + return t.touched +} + func (t *AccountTouchTracer) TouchedAddresses() []common.Address { result := make([]common.Address, 0, len(t.touched)) diff --git a/miner/algo_common.go b/miner/algo_common.go index 84b6bb0080..e3bad88745 100644 --- a/miner/algo_common.go +++ b/miner/algo_common.go @@ -292,25 +292,25 @@ func estimatePayoutTxGas(env *environment, sender, receiver common.Address, prv return receipt.GasUsed, false, nil } -func insertPayoutTx(env *environment, sender, receiver common.Address, gas uint64, isEOA bool, availableFunds *big.Int, prv *ecdsa.PrivateKey, chData chainData) (*types.Receipt, error) { - applyTx := func(envDiff *environmentDiff, gas uint64) (*types.Receipt, error) { - fee := new(big.Int).Mul(env.header.BaseFee, new(big.Int).SetUint64(gas)) - amount := new(big.Int).Sub(availableFunds, fee) - if amount.Sign() < 0 { - return nil, errors.New("not enough funds available") - } - rec, err := envDiff.commitPayoutTx(amount, sender, receiver, gas, prv, chData) - if err != nil { - return nil, fmt.Errorf("failed to commit payment tx: %w", err) - } else if rec.Status != types.ReceiptStatusSuccessful { - return nil, fmt.Errorf("payment tx failed") - } - return rec, nil +func applyPayoutTx(envDiff *environmentDiff, sender, receiver common.Address, gas uint64, amountWithFees *big.Int, prv *ecdsa.PrivateKey, chData chainData) (*types.Receipt, error) { + amount := new(big.Int).Sub(amountWithFees, new(big.Int).Mul(envDiff.header.BaseFee, big.NewInt(int64(gas)))) + + if amount.Sign() < 0 { + return nil, errors.New("not enough funds available") + } + rec, err := envDiff.commitPayoutTx(amount, sender, receiver, gas, prv, chData) + if err != nil { + return nil, fmt.Errorf("failed to commit payment tx: %w", err) + } else if rec.Status != types.ReceiptStatusSuccessful { + return nil, fmt.Errorf("payment tx failed") } + return rec, nil +} +func insertPayoutTx(env *environment, sender, receiver common.Address, gas uint64, isEOA bool, availableFunds *big.Int, prv *ecdsa.PrivateKey, chData chainData) (*types.Receipt, error) { if isEOA { diff := newEnvironmentDiff(env) - rec, err := applyTx(diff, gas) + rec, err := applyPayoutTx(diff, sender, receiver, gas, availableFunds, prv, chData) if err != nil { return nil, err } @@ -322,7 +322,7 @@ func insertPayoutTx(env *environment, sender, receiver common.Address, gas uint6 for i := 0; i < 6; i++ { diff := newEnvironmentDiff(env) var rec *types.Receipt - rec, err = applyTx(diff, gas) + rec, err = applyPayoutTx(diff, sender, receiver, gas, availableFunds, prv, chData) if err != nil { gas += 1000 continue @@ -334,7 +334,7 @@ func insertPayoutTx(env *environment, sender, receiver common.Address, gas uint6 } exactEnvDiff := newEnvironmentDiff(env) - exactRec, err := applyTx(exactEnvDiff, rec.GasUsed) + exactRec, err := applyPayoutTx(exactEnvDiff, sender, receiver, rec.GasUsed, availableFunds, prv, chData) if err != nil { diff.applyToBaseEnv() return rec, nil diff --git a/miner/algo_common_test.go b/miner/algo_common_test.go index 2dd43e62ef..79ae2b75c8 100644 --- a/miner/algo_common_test.go +++ b/miner/algo_common_test.go @@ -186,14 +186,19 @@ func genGenesisAlloc(sign signerList, contractAddr []common.Address, contractCod func genTestSetup() (*state.StateDB, chainData, signerList) { config := params.AllEthashProtocolChanges - db := rawdb.NewMemoryDatabase() - signerList := genSignerList(10, config) - + signerList := genSignerList(10, params.AllEthashProtocolChanges) genesisAlloc := genGenesisAlloc(signerList, []common.Address{payProxyAddress, logContractAddress}, [][]byte{payProxyCode, logContractCode}) + stateDB, chainData := genTestSetupWithAlloc(config, genesisAlloc) + return stateDB, chainData, signerList +} + +func genTestSetupWithAlloc(config *params.ChainConfig, alloc core.GenesisAlloc) (*state.StateDB, chainData) { + db := rawdb.NewMemoryDatabase() + gspec := &core.Genesis{ Config: config, - Alloc: genesisAlloc, + Alloc: alloc, } _ = gspec.MustCommit(db) @@ -201,7 +206,7 @@ func genTestSetup() (*state.StateDB, chainData, signerList) { stateDB, _ := state.New(chain.CurrentHeader().Root, state.NewDatabase(db), nil) - return stateDB, chainData{config, chain, nil}, signerList + return stateDB, chainData{config, chain, nil} } func newEnvironment(data chainData, state *state.StateDB, coinbase common.Address, gasLimit uint64, baseFee *big.Int) *environment { diff --git a/miner/algo_contracts_test.go b/miner/algo_contracts_test.go new file mode 100644 index 0000000000..dbffb56c36 --- /dev/null +++ b/miner/algo_contracts_test.go @@ -0,0 +1,47 @@ +package miner + +import ( + "encoding/hex" +) + +// Contracts used for testing. +var ( + // Always revert and consume all gas. + // + // pc op bytecode + // 0x00 INVALID 0xfe + contractRevert = parseCode("0xfe") + + // Send the entire balance of the contract to the caller or revert and + // consume all gas, if the contracts balance is zero. + // + // pc op stack bytecode + // 0x00 SELFBALANCE bal 0x47 + // 0x01 PUSH1 0x05 0x05 bal 0x6005 + // 0x03 JUMPI . 0x57 + // 0x04 INVALID . 0xfe + // 0x05 JUMPDEST . 0x5b + // + // 0x06 MSIZE 0 0x59 + // 0x07 MSIZE 0 0 0x59 + // 0x08 MSIZE 0 0 0 0x59 + // 0x09 MSIZE 0 0 0 0 0x59 + // 0x0a SELFBALANCE bal 0 0 0 0 0 0x47 + // 0x0b CALLER clr bal 0 0 0 0 0 0x33 + // 0x0c GAS gas clr bal 0 0 0 0 0 0x5a + // 0x0d CALL . 0xf1 + contractSendBalance = parseCode("0x47600557fe5b5959595947335af100") +) + +// parseCode converts a hex bytecode to a byte slice, or panics if the hex +// bytecode is invalid. +func parseCode(hexStr string) []byte { + if hexStr[0] == '0' && (hexStr[1] == 'x' || hexStr[1] == 'X') { + hexStr = hexStr[2:] + } + data, err := hex.DecodeString(hexStr) + if err != nil { + panic(err) + } + return data +} diff --git a/miner/algo_greedy.go b/miner/algo_greedy.go index 51b76a76cc..396df03e70 100644 --- a/miner/algo_greedy.go +++ b/miner/algo_greedy.go @@ -36,8 +36,8 @@ func (b *greedyBuilder) mergeOrdersIntoEnvDiff(envDiff *environmentDiff, orders break } - if order.Tx != nil { - receipt, skip, err := envDiff.commitTx(order.Tx, b.chainData) + if tx := order.Tx(); tx != nil { + receipt, skip, err := envDiff.commitTx(tx, b.chainData) switch skip { case shiftTx: orders.Shift() @@ -46,15 +46,14 @@ func (b *greedyBuilder) mergeOrdersIntoEnvDiff(envDiff *environmentDiff, orders } if err != nil { - log.Trace("could not apply tx", "hash", order.Tx.Hash(), "err", err) + log.Trace("could not apply tx", "hash", tx.Hash(), "err", err) continue } - effGapPrice, err := order.Tx.EffectiveGasTip(envDiff.baseEnvironment.header.BaseFee) + effGapPrice, err := tx.EffectiveGasTip(envDiff.baseEnvironment.header.BaseFee) if err == nil { log.Trace("Included tx", "EGP", effGapPrice.String(), "gasUsed", receipt.GasUsed) } - } else if order.Bundle != nil { - bundle := order.Bundle + } else if bundle := order.Bundle(); bundle != nil { //log.Debug("buildBlock considering bundle", "egp", bundle.MevGasPrice.String(), "hash", bundle.OriginalBundle.Hash) err := envDiff.commitBundle(bundle, b.chainData, b.interrupt) orders.Pop() diff --git a/miner/algo_greedy_test.go b/miner/algo_greedy_test.go index 8f7f99d7ba..de866dc3c8 100644 --- a/miner/algo_greedy_test.go +++ b/miner/algo_greedy_test.go @@ -58,11 +58,11 @@ func TestTxWithMinerFeeHeap(t *testing.T) { return } - if order.Tx != nil { - fmt.Println("tx", order.Tx.Hash()) + if order.Tx() != nil { + fmt.Println("tx", order.Tx().Hash()) orders.Shift() - } else if order.Bundle != nil { - fmt.Println("bundle", order.Bundle.OriginalBundle.Hash) + } else if order.Bundle() != nil { + fmt.Println("bundle", order.Bundle().OriginalBundle.Hash) orders.Pop() } } diff --git a/miner/algo_test.go b/miner/algo_test.go new file mode 100644 index 0000000000..013aecd0f0 --- /dev/null +++ b/miner/algo_test.go @@ -0,0 +1,421 @@ +package miner + +import ( + "crypto/ecdsa" + "crypto/rand" + "fmt" + "math/big" + "sync" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" +) + +var algoTests = []*algoTest{ + { + // Trivial tx pool with 2 txs by two accounts and a block gas limit that only allows one tx + // to be included. + // + // The tx paying the highest gas price should be included. + Name: "simple", + Header: &types.Header{GasLimit: 21_000}, + Alloc: []core.GenesisAccount{ + {Balance: big.NewInt(21_000)}, + {Balance: big.NewInt(2 * 21_000)}, + }, + TxPool: func(acc accByIndex) map[int][]types.TxData { + return map[int][]types.TxData{ + 0: { + &types.LegacyTx{Nonce: 0, To: acc(0), Gas: 21_000, GasPrice: big.NewInt(1)}, + }, + 1: { + &types.LegacyTx{Nonce: 0, To: acc(1), Gas: 21_000, GasPrice: big.NewInt(2)}, + }, + } + }, + WantProfit: big.NewInt(2 * 21_000), + }, + { + // Trivial tx pool with 3 txs by two accounts and a block gas limit that only allows two txs + // to be included. Account 1 has two pending txs of which the second one has a higher gas + // price than the first one. + // + // Both txs by account 1 should be included, as they maximize the miners profit. + Name: "lookahead", + Header: &types.Header{GasLimit: 63_000}, + Alloc: []core.GenesisAccount{ + {Balance: big.NewInt(21_000)}, + {Balance: big.NewInt(3 * 21_000)}, + }, + TxPool: func(acc accByIndex) map[int][]types.TxData { + return map[int][]types.TxData{ + 0: { + &types.LegacyTx{Nonce: 0, Gas: 21_000, To: acc(0), GasPrice: big.NewInt(1)}, + }, + 1: { + &types.LegacyTx{Nonce: 0, Gas: 21_000, To: acc(1), GasPrice: big.NewInt(1)}, + &types.LegacyTx{Nonce: 1, Gas: 21_000, To: acc(1), GasPrice: big.NewInt(2)}, + }, + } + }, + WantProfit: big.NewInt(4 * 21_000), + }, + { + // Trivial bundle with one tx that reverts but is not allowed to revert. + // + // Bundle should not be included. + Name: "atomic-bundle-no-revert", + Header: &types.Header{GasLimit: 50_000}, + Alloc: []core.GenesisAccount{ + {Balance: big.NewInt(50_000)}, + {Code: contractRevert}, + }, + Bundles: func(acc accByIndex, sign signByIndex, txs txByAccIndexAndNonce) []*bundle { + return []*bundle{ + {Txs: types.Transactions{sign(0, &types.LegacyTx{Nonce: 0, Gas: 50_000, To: acc(1), GasPrice: big.NewInt(1)})}}, + } + }, + WantProfit: big.NewInt(0), + }, + { + // Trivial bundle with one tx that reverts and is allowed to revert. + // + // Bundle should be included. + Name: "atomic-bundle-revert", + Header: &types.Header{GasLimit: 50_000}, + Alloc: []core.GenesisAccount{ + {Balance: big.NewInt(50_000)}, + {Code: contractRevert}, + }, + Bundles: func(acc accByIndex, sign signByIndex, txs txByAccIndexAndNonce) []*bundle { + return []*bundle{ + { + Txs: types.Transactions{sign(0, &types.LegacyTx{Nonce: 0, Gas: 50_000, To: acc(1), GasPrice: big.NewInt(1)})}, + RevertingTxIndices: []int{0}, + }, + } + }, + WantProfit: big.NewInt(50_000), + }, + { + // Single failing tx that is included in the tx pool and in a bundle that is not allowed to + // revert. + // + // Tx should be included. + Name: "simple-contradiction", + Header: &types.Header{GasLimit: 50_000}, + Alloc: []core.GenesisAccount{ + {Balance: big.NewInt(50_000)}, + {Code: contractRevert}, + }, + TxPool: func(acc accByIndex) map[int][]types.TxData { + return map[int][]types.TxData{ + 0: { + &types.LegacyTx{Nonce: 0, Gas: 50_000, To: acc(1), GasPrice: big.NewInt(1)}, + }, + } + }, + Bundles: func(acc accByIndex, sign signByIndex, txs txByAccIndexAndNonce) []*bundle { + return []*bundle{ + {Txs: types.Transactions{txs(0, 0)}}, + } + }, + WantProfit: big.NewInt(50_000), + }, +} + +func TestAlgo(t *testing.T) { + var ( + config = params.AllEthashProtocolChanges + signer = types.LatestSigner(config) + ) + + for _, test := range algoTests { + t.Run(test.Name, func(t *testing.T) { + alloc, txPool, bundles, err := test.build(signer, 1) + if err != nil { + t.Fatalf("Build: %v", err) + } + simBundles, err := simulateBundles(config, test.Header, alloc, bundles) + if err != nil { + t.Fatalf("Simulate Bundles: %v", err) + } + + gotProfit, err := runAlgoTest(config, alloc, txPool, simBundles, test.Header, 1) + if err != nil { + t.Fatal(err) + } + if test.WantProfit.Cmp(gotProfit) != 0 { + t.Fatalf("Profit: want %v, got %v", test.WantProfit, gotProfit) + } + }) + } +} + +func BenchmarkAlgo(b *testing.B) { + var ( + config = params.AllEthashProtocolChanges + signer = types.LatestSigner(config) + scales = []int{1, 10, 100} + ) + + for _, test := range algoTests { + for _, scale := range scales { + wantScaledProfit := new(big.Int).Mul( + big.NewInt(int64(scale)), + test.WantProfit, + ) + + b.Run(fmt.Sprintf("%s_%d", test.Name, scale), func(b *testing.B) { + alloc, txPool, bundles, err := test.build(signer, scale) + if err != nil { + b.Fatalf("Build: %v", err) + } + simBundles, err := simulateBundles(config, test.Header, alloc, bundles) + if err != nil { + b.Fatalf("Simulate Bundles: %v", err) + } + + b.ResetTimer() + var txPoolCopy map[common.Address]types.Transactions + for i := 0; i < b.N; i++ { + // Note: copy is needed as the greedyAlgo modifies the txPool. + func() { + b.StopTimer() + defer b.StartTimer() + + txPoolCopy = make(map[common.Address]types.Transactions, len(txPool)) + for addr, txs := range txPool { + txPoolCopy[addr] = txs + } + }() + + gotProfit, err := runAlgoTest(config, alloc, txPoolCopy, simBundles, test.Header, scale) + if err != nil { + b.Fatal(err) + } + if wantScaledProfit.Cmp(gotProfit) != 0 { + b.Fatalf("Profit: want %v, got %v", wantScaledProfit, gotProfit) + } + } + }) + } + } +} + +// runAlgo executes a single algoTest case and returns the profit. +func runAlgoTest(config *params.ChainConfig, alloc core.GenesisAlloc, txPool map[common.Address]types.Transactions, bundles []types.SimulatedBundle, header *types.Header, scale int) (gotProfit *big.Int, err error) { + var ( + statedb, chData = genTestSetupWithAlloc(config, alloc) + env = newEnvironment(chData, statedb, header.Coinbase, header.GasLimit*uint64(scale), header.BaseFee) + builder = newGreedyBuilder(chData.chain, chData.chainConfig, nil, env, nil) + ) + + // build block + resultEnv, _ := builder.buildBlock(bundles, txPool) + return resultEnv.profit, nil +} + +// simulateBundles simulates bundles and returns the simulated bundles. +func simulateBundles(config *params.ChainConfig, header *types.Header, alloc core.GenesisAlloc, bundles []types.MevBundle) ([]types.SimulatedBundle, error) { + var ( + statedb, chData = genTestSetupWithAlloc(config, alloc) + env = newEnvironment(chData, statedb, header.Coinbase, header.GasLimit, header.BaseFee) + + simBundles = make([]types.SimulatedBundle, 0) + ) + + for _, bundle := range bundles { + simBundle, err := simulateBundle(env, bundle, chData, nil) + if err != nil { + continue + } + simBundles = append(simBundles, simBundle) + } + return simBundles, nil +} + +// algoTest represents a block builder algorithm test case. +type algoTest struct { + once sync.Once + + Name string // Name of the test + Header *types.Header // Header of the block to build + + // Genesis accounts as slice. + Alloc []core.GenesisAccount + + // TxPool creation function. The returned tx pool maps from accounts (by + // index, referencing the Alloc slice index) to a slice of transactions. + // + // The function takes an accByIndex function that returns the address + // of the GenesisAccount in the Alloc slice at the given index. + TxPool func(accByIndex) map[int][]types.TxData + + // Bundles creation function. + Bundles func(accByIndex, signByIndex, txByAccIndexAndNonce) []*bundle + + WantProfit *big.Int // Expected block profit +} + +// setDefaults sets default values for the algoTest. +func (test *algoTest) setDefaults() { + // set header defaults + if test.Header == nil { + test.Header = &types.Header{} + } + if test.Header.Coinbase == (common.Address{}) { + test.Header.Coinbase = randAddr() + } + if test.Header.Number == nil { + test.Header.Number = big.NewInt(0) + } + if test.Header.BaseFee == nil { + test.Header.BaseFee = big.NewInt(0) + } +} + +// build builds the genesis alloc and tx pool from the given algoTest. +// +// The scale parameter can be used to scale up the number of the provided scenario +// of the algoTest inside the returned genesis alloc and tx pool. +func (test *algoTest) build(signer types.Signer, scale int) (alloc core.GenesisAlloc, txPool map[common.Address]types.Transactions, bundles []types.MevBundle, err error) { + test.once.Do(test.setDefaults) + + // generate accounts + n := len(test.Alloc) // number of accounts + addrs, prvs := genRandAccs(n * scale) + + // build alloc + alloc = make(core.GenesisAlloc, n*scale) + txPool = make(map[common.Address]types.Transactions) + bundles = make([]types.MevBundle, 0) + + for s := 0; s < scale; s++ { + for i, acc := range test.Alloc { + if acc.Balance == nil { + acc.Balance = new(big.Int) // balance must be non-nil + } + alloc[addrs[s*n+i]] = acc + } + + // build tx pool + accByIndexFn := accByIndexFunc(addrs[s*n : (s+1)*n]) + if test.TxPool != nil { + preTxPool := test.TxPool(accByIndexFn) + for i, txs := range preTxPool { + if i < 0 || i >= n { + panic(fmt.Sprintf("invalid account %d, should be in [0, %d]", i, n-1)) + } + + signedTxs := make(types.Transactions, len(txs)) + for j, tx := range txs { + signedTxs[j] = types.MustSignNewTx(prvs[s*n+i], signer, tx) + } + txPool[addrs[s*n+i]] = signedTxs + } + } + + // build bundles + if test.Bundles != nil { + signByIndexFn := signByIndexFunc(prvs[s*n:(s+1)*n], signer) + txByAccIndexAndNonceFn := txByAccIndexAndNonceFunc(addrs[s*n:(s+1)*n], txPool) + preBundles := test.Bundles(accByIndexFn, signByIndexFn, txByAccIndexAndNonceFn) + + for _, bundle := range preBundles { + b := bundle.toMevBundle() + bundles = append(bundles, b) + } + } + } + return +} + +// accByIndex returns the address of the genesis account with the given index. +type accByIndex func(int) *common.Address + +func accByIndexFunc(accs []common.Address) accByIndex { + return func(i int) *common.Address { + if 0 > i || i >= len(accs) { + panic(fmt.Sprintf("invalid account %d, should be in [0, %d]", i, len(accs)-1)) + } + return &accs[i] + } +} + +// signByIndex signs the given transaction with the private key of the genesis +// account with the given index. +type signByIndex func(int, types.TxData) *types.Transaction + +func signByIndexFunc(prvs []*ecdsa.PrivateKey, signer types.Signer) signByIndex { + return func(i int, tx types.TxData) *types.Transaction { + if 0 > i || i >= len(prvs) { + panic(fmt.Sprintf("invalid private key %d, should be in [0, %d]", i, len(prvs)-1)) + } + return types.MustSignNewTx(prvs[i], signer, tx) + } +} + +// txByAccIndexAndNonce returns the transaction with the given nonce of the +// genesis account with the given index. +type txByAccIndexAndNonce func(int, uint64) *types.Transaction + +func txByAccIndexAndNonceFunc(accs []common.Address, txPool map[common.Address]types.Transactions) txByAccIndexAndNonce { + return func(i int, nonce uint64) *types.Transaction { + if 0 > i || i >= len(accs) { + panic(fmt.Sprintf("invalid account %d, should be in [0, %d]", i, len(accs)-1)) + } + addr := accs[i] + txs := txPool[addr] + + // q&d: iterate to find nonce + for _, tx := range txs { + if tx.Nonce() == nonce { + return tx + } + } + panic(fmt.Sprintf("tx for account %d with nonce %d does not exist", i, nonce)) + } +} + +type bundle struct { + Txs types.Transactions + RevertingTxIndices []int +} + +func (b *bundle) toMevBundle() types.MevBundle { + revertingHashes := make([]common.Hash, len(b.RevertingTxIndices)) + for i, idx := range b.RevertingTxIndices { + if 0 > idx || idx >= len(b.Txs) { + panic(fmt.Sprintf("invalid tx index %d, should be in [0, %d]", idx, len(b.Txs)-1)) + } + revertingHashes[i] = b.Txs[idx].Hash() + } + return types.MevBundle{Txs: b.Txs, RevertingTxHashes: revertingHashes} +} + +// randAddr returns a random address. +func randAddr() (addr common.Address) { + rand.Read(addr[:]) + return addr +} + +// genRandAccs generates n random accounts. +func genRandAccs(n int) ([]common.Address, []*ecdsa.PrivateKey) { + addrs := make([]common.Address, n) + prvs := make([]*ecdsa.PrivateKey, n) + + for i := 0; i < n; i++ { + prv, err := crypto.GenerateKey() + if err != nil { + panic(fmt.Sprintf("genRandAccs: %v", err)) + } + prvs[i] = prv + addrs[i] = crypto.PubkeyToAddress(prv.PublicKey) + } + return addrs, prvs +} diff --git a/miner/contract_simulator_test.go b/miner/contract_simulator_test.go new file mode 100644 index 0000000000..a36cc335a1 --- /dev/null +++ b/miner/contract_simulator_test.go @@ -0,0 +1,307 @@ +package miner + +import ( + "context" + "crypto/ecdsa" + "encoding/json" + "math/big" + "math/rand" + "os" + "testing" + "time" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + ethmath "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/params" + tu "github.com/ethereum/go-ethereum/test_utils" + "github.com/stretchr/testify/require" +) + +var ( + wethAddress = common.HexToAddress("0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512") + daiAddress = common.HexToAddress("0x5FbDB2315678afecb367f032d93F642f64180aa3") + univ2FactoryA_Address = common.HexToAddress("0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0") + univ2FactoryB_Address = common.HexToAddress("0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9") + atomicSwapAddress = common.HexToAddress("0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9") + + bigEther = big.NewInt(params.Ether) +) + +func enableLogging() { + log.Root().SetHandler(log.LvlFilterHandler(log.LvlDebug, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) +} + +func deployAllContracts(t *testing.T, key *ecdsa.PrivateKey, gasPrice *big.Int) []*types.Transaction { + allContractsData, err := os.ReadFile("testdata/allcontracts.signeddata") + require.NoError(t, err) + + var signedTxsBytes []hexutil.Bytes + err = json.Unmarshal(allContractsData, &signedTxsBytes) + require.NoError(t, err) + + var signedTxs []*types.Transaction + for _, signedTxBytes := range signedTxsBytes { + signedTx := types.Transaction{} + err = signedTx.UnmarshalBinary(signedTxBytes) + require.NoError(t, err) + signedTxs = append(signedTxs, &signedTx) + } + + return signedTxs +} + +type TestParticipant struct { + key *ecdsa.PrivateKey + address common.Address +} + +func NewParticipant() TestParticipant { + pk, _ := crypto.GenerateKey() + address := crypto.PubkeyToAddress(pk.PublicKey) + return TestParticipant{pk, address} +} + +type TestParticipants struct { + searchers []TestParticipant + users []TestParticipant +} + +func NewTestParticipants(nSearchers int, nUsers int) TestParticipants { + opa := TestParticipants{} + + for i := 0; i < nSearchers; i++ { + opa.searchers = append(opa.searchers, NewParticipant()) + } + + for i := 0; i < nUsers; i++ { + opa.users = append(opa.users, NewParticipant()) + } + + return opa +} + +func (o *TestParticipants) AppendToGenesisAlloc(genesis core.GenesisAlloc) core.GenesisAlloc { + for _, searcher := range o.searchers { + genesis[searcher.address] = core.GenesisAccount{Balance: new(big.Int).Mul(big.NewInt(10000), bigEther)} + } + + for _, user := range o.users { + genesis[user.address] = core.GenesisAccount{Balance: new(big.Int).Mul(big.NewInt(10000), bigEther)} + } + + return genesis +} + +func parseAbi(t *testing.T, filename string) *abi.ABI { + abiData, err := os.ReadFile(filename) + require.NoError(t, err) + + resAbi := new(abi.ABI) + err = resAbi.UnmarshalJSON(abiData) + require.NoError(t, err) + + return resAbi +} + +func TestSimulatorState(t *testing.T) { + // enableLogging() + + t.Cleanup(func() { + testConfig.AlgoType = ALGO_MEV_GETH + testConfig.BuilderTxSigningKey = nil + testConfig.Etherbase = common.Address{} + }) + + testConfig.AlgoType = ALGO_GREEDY + var err error + testConfig.BuilderTxSigningKey, err = crypto.GenerateKey() + require.NoError(t, err) + testConfig.Etherbase = crypto.PubkeyToAddress(testConfig.BuilderTxSigningKey.PublicKey) + + db := rawdb.NewMemoryDatabase() + chainConfig := *params.AllEthashProtocolChanges + chainConfig.ChainID = big.NewInt(31337) + engine := ethash.NewFaker() + + // (not needed I think) chainConfig.LondonBlock = big.NewInt(0) + deployerKey, err := crypto.ToECDSA(hexutil.MustDecode("0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80")) + deployerAddress := crypto.PubkeyToAddress(deployerKey.PublicKey) + deployerTestAddress := common.HexToAddress("0x70997970C51812dc3A010C7d01b50e0d17dc79C8") + alloc := core.GenesisAlloc{deployerAddress: {Balance: new(big.Int).Mul(big.NewInt(10000), bigEther)}, deployerTestAddress: {Balance: new(big.Int).Mul(big.NewInt(10000), bigEther)}} + + testParticipants := NewTestParticipants(5, 5) + alloc = testParticipants.AppendToGenesisAlloc(alloc) + + var genesis = core.Genesis{ + Config: &chainConfig, + Alloc: alloc, + GasLimit: 30000000, + } + + w, b := newTestWorkerGenesis(t, &chainConfig, engine, db, genesis, 0) + w.setEtherbase(crypto.PubkeyToAddress(testConfig.BuilderTxSigningKey.PublicKey)) + + simBackend := backends.NewSimulatedBackendChain(db, b.chain) + + univ2FactoryA := NewTContract(t, simBackend, "testdata/univ2factory.abi", univ2FactoryA_Address) + univ2FactoryB := NewTContract(t, simBackend, "testdata/univ2factory.abi", univ2FactoryB_Address) + + wethContract := NewTContract(t, simBackend, "testdata/weth.abi", wethAddress) + daiContract := NewTContract(t, simBackend, "testdata/dai.abi", daiAddress) + atomicSwapContract := NewTContract(t, simBackend, "testdata/swap.abi", atomicSwapAddress) + + testAddress1Key, _ := crypto.GenerateKey() + testAddress1 := crypto.PubkeyToAddress(testAddress1Key.PublicKey) + + rand.Seed(10) + + deploymentTxs := deployAllContracts(t, deployerKey, b.chain.CurrentHeader().BaseFee) + + getBaseFee := func() *big.Int { + return new(big.Int).Mul(big.NewInt(2), b.chain.CurrentHeader().BaseFee) + } + + nonceModFor := big.NewInt(0) + nonceMod := make(map[common.Address]uint64) + getNonce := func(addr common.Address) uint64 { + if nonceModFor.Cmp(b.chain.CurrentHeader().Number) != 0 { + nonceMod = make(map[common.Address]uint64) + nonceModFor.Set(b.chain.CurrentHeader().Number) + } + + cm, _ := nonceMod[addr] + nonceMod[addr] = cm + 1 + return b.txPool.Nonce(addr) + cm + } + + prepareContractCallTx := func(contract tConctract, signerKey *ecdsa.PrivateKey, method string, args ...interface{}) *types.Transaction { + callData, err := contract.abi.Pack(method, args...) + require.NoError(t, err) + + fromAddress := crypto.PubkeyToAddress(signerKey.PublicKey) + + callRes, err := contract.doCall(fromAddress, method, args...) + if err != nil { + t.Errorf("Prepared smart contract call error %s with result %s", err.Error(), string(callRes)) + } + + tx, err := types.SignTx(types.NewTransaction(getNonce(fromAddress), contract.address, new(big.Int), 9000000, getBaseFee(), callData), types.HomesteadSigner{}, signerKey) + require.NoError(t, err) + + return tx + } + + buildBlock := func(txs []*types.Transaction, requireTx int) *types.Block { + errs := b.txPool.AddLocals(txs) + for _, err := range errs { + require.NoError(t, err) + } + + blockCh, errCh, err := w.getSealingBlock(b.chain.CurrentBlock().Hash(), b.chain.CurrentHeader().Time+12, testAddress1, 0, common.Hash{}, false, false, nil) + require.NoError(t, err) + require.Equal(t, tu.ChanResult[error]{nil, false}, tu.RequireChan[error](errCh, 100*time.Millisecond)) + + blockChRes := tu.RequireChan[*types.Block](blockCh, 100*time.Millisecond) + block := blockChRes.Value + require.False(t, blockChRes.Timeout) + require.NotNil(t, block) + if requireTx != -1 { + require.Equal(t, requireTx, len(block.Transactions())) + } + _, err = b.chain.InsertChain([]*types.Block{block}) + require.NoError(t, err) + return block + } + + buildBlock(deploymentTxs, len(deploymentTxs)+1) + require.Equal(t, uint64(18), b.txPool.Nonce(deployerAddress)) + require.Equal(t, uint64(3), b.txPool.Nonce(deployerTestAddress)) + + // Mint tokens + require.NoError(t, err) + + approveTxs := []*types.Transaction{} + + adminApproveTxWeth := prepareContractCallTx(wethContract, deployerKey, "approve", atomicSwapContract.address, ethmath.MaxBig256) + approveTxs = append(approveTxs, adminApproveTxWeth) + adminApproveTxDai := prepareContractCallTx(daiContract, deployerKey, "approve", atomicSwapContract.address, ethmath.MaxBig256) + approveTxs = append(approveTxs, adminApproveTxDai) + + for _, spender := range []TestParticipant{testParticipants.users[0], testParticipants.searchers[0]} { + + mintTx := prepareContractCallTx(daiContract, deployerKey, "mint", spender.address, new(big.Int).Mul(bigEther, big.NewInt(50000))) + approveTxs = append(approveTxs, mintTx) + + depositTx, err := types.SignTx(types.NewTransaction(getNonce(spender.address), wethContract.address, new(big.Int).Mul(bigEther, big.NewInt(1000)), 9000000, getBaseFee(), hexutil.MustDecode("0xd0e30db0")), types.HomesteadSigner{}, spender.key) + require.NoError(t, err) + approveTxs = append(approveTxs, depositTx) + + spenderApproveTxWeth := prepareContractCallTx(wethContract, spender.key, "approve", atomicSwapContract.address, ethmath.MaxBig256) + approveTxs = append(approveTxs, spenderApproveTxWeth) + + spenderApproveTxDai := prepareContractCallTx(daiContract, spender.key, "approve", atomicSwapContract.address, ethmath.MaxBig256) + approveTxs = append(approveTxs, spenderApproveTxDai) + } + + buildBlock(approveTxs, len(approveTxs)+1) + + amtIn := new(big.Int).Mul(bigEther, big.NewInt(50)) + + userSwapTx := prepareContractCallTx(atomicSwapContract, testParticipants.users[0].key, "swap", []common.Address{wethContract.address, daiContract.address}, amtIn, univ2FactoryA.address, testParticipants.users[0].address, false) + + backrunTxData, err := atomicSwapContract.abi.Pack("backrun", daiContract.address, univ2FactoryB.address, univ2FactoryA.address, new(big.Int).Div(amtIn, big.NewInt(2))) + require.NoError(t, err) + + backrunTx, err := types.SignTx(types.NewTransaction(getNonce(testParticipants.searchers[0].address), atomicSwapContract.address, new(big.Int), 9000000, getBaseFee(), backrunTxData), types.HomesteadSigner{}, testParticipants.searchers[0].key) + + targetBlockNumber := new(big.Int).Set(b.chain.CurrentHeader().Number) + targetBlockNumber.Add(targetBlockNumber, big.NewInt(1)) + b.txPool.AddMevBundle(types.Transactions{userSwapTx, backrunTx}, targetBlockNumber, 0, 0, nil) + + buildBlock([]*types.Transaction{}, 3) +} + +type tConctract struct { + t *testing.T + simBackend *backends.SimulatedBackend + abi *abi.ABI + address common.Address +} + +func NewTContract(t *testing.T, simBackend *backends.SimulatedBackend, abiFile string, address common.Address) tConctract { + return tConctract{ + t: t, + simBackend: simBackend, + abi: parseAbi(t, abiFile), + address: address, + } +} + +func (c *tConctract) doCall(fromAddress common.Address, method string, args ...interface{}) ([]byte, error) { + callData, err := c.abi.Pack(method, args...) + if err != nil { + return nil, err + } + + simRes, err := c.simBackend.CallContract(context.Background(), ethereum.CallMsg{ + From: fromAddress, + To: &c.address, + GasPrice: new(big.Int), + Data: callData, + }, c.simBackend.Blockchain().CurrentHeader().Number) + if err != nil { + return nil, err + } + + return simRes, nil +} diff --git a/miner/testdata/allcontracts.signeddata b/miner/testdata/allcontracts.signeddata new file mode 100644 index 0000000000..b55a3a7ad4 --- /dev/null +++ b/miner/testdata/allcontracts.signeddata @@ -0,0 +1 @@ +["0x02f912c9827a698084b2d05e008509c7652400838954408080b9126d608060405234801561001057600080fd5b5060405161124d38038061124d8339818101604052602081101561003357600080fd5b5051336000908152602081905260409081902060019055518060526111fb8239604080519182900360520182208282018252600e83527f44616920537461626c65636f696e00000000000000000000000000000000000060209384015281518083018352600181527f3100000000000000000000000000000000000000000000000000000000000000908401528151808401919091527f0b1461ddc0c1d5ded79a1db0f74dae949050a7c0b28728c724b24958c27a328b818301527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6606082015260808101949094523060a0808601919091528151808603909101815260c090940190528251920191909120600555506110a9806101526000396000f3fe608060405234801561001057600080fd5b50600436106101425760003560e01c80637ecebe00116100b8578063a9059cbb1161007c578063a9059cbb146103e0578063b753a98c1461040c578063bb35783b14610438578063bf353dbb1461046e578063dd62ed3e14610494578063f2d5d56b146104c257610142565b80637ecebe00146103065780638fcbaf0c1461032c57806395d89b41146103865780639c52a7f11461038e5780639dc29fac146103b457610142565b8063313ce5671161010a578063313ce5671461025e5780633644e5151461027c57806340c10f191461028457806354fd4d50146102b257806365fae35e146102ba57806370a08231146102e057610142565b806306fdde0314610147578063095ea7b3146101c657806318160ddd1461020657806323b872dd1461022057806330adf81f14610256575b600080fd5b61014f6104ee565b60405160208082528190810183818151815260200191508051906020019080838360005b8381101561018b578082015183820152602001610173565b50505050905090810190601f1680156101b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101f2600480360360408110156101dc57600080fd5b506001600160a01b038135169060200135610516565b604051901515815260200160405180910390f35b61020e610588565b60405190815260200160405180910390f35b6101f26004803603606081101561023657600080fd5b506001600160a01b0381358116916020810135909116906040013561058e565b61020e6107db565b6102666107ff565b60405160ff909116815260200160405180910390f35b61020e610804565b6102b06004803603604081101561029a57600080fd5b506001600160a01b03813516906020013561080a565b005b61014f6108f1565b6102b0600480360360208110156102d057600080fd5b50356001600160a01b031661090c565b61020e600480360360208110156102f657600080fd5b50356001600160a01b03166109ba565b61020e6004803603602081101561031c57600080fd5b50356001600160a01b03166109ce565b6102b0600480360361010081101561034357600080fd5b506001600160a01b038135811691602081013590911690604081013590606081013590608081013515159060ff60a0820135169060c08101359060e001356109e2565b61014f610cfc565b6102b0600480360360208110156103a457600080fd5b50356001600160a01b0316610d19565b6102b0600480360360408110156103ca57600080fd5b506001600160a01b038135169060200135610dc4565b6101f2600480360360408110156103f657600080fd5b506001600160a01b038135169060200135610fde565b6102b06004803603604081101561042257600080fd5b506001600160a01b038135169060200135610ff2565b6102b06004803603606081101561044e57600080fd5b506001600160a01b03813581169160208101359091169060400135611002565b61020e6004803603602081101561048457600080fd5b50356001600160a01b0316611013565b61020e600480360360408110156104aa57600080fd5b506001600160a01b0381358116916020013516611027565b6102b0600480360360408110156104d857600080fd5b506001600160a01b038135169060200135611049565b60405160408082019052600e81526d2230b49029ba30b13632b1b7b4b760911b602082015281565b336000908152600360205281604082206001600160a01b038516600090815260209190915260409020556001600160a01b038316337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405190815260200160405180910390a35060015b92915050565b60015481565b6001600160a01b0383166000908152600260205281604082205410156105f55760405162461bcd60e51b81526020600482015260186024820152774461692f696e73756666696369656e742d62616c616e636560401b604482015260640160405180910390fd5b6001600160a01b038416331480159061063957506001600160a01b038416600090815260036020526000199060409020336000908152602091909152604090205414155b15610718576001600160a01b03841660009081526003602052829060409020336000908152602091909152604090205410156106bb5760405162461bcd60e51b815260206004820152601a60248201527f4461692f696e73756666696369656e742d616c6c6f77616e6365000000000000604482015260640160405180910390fd5b6001600160a01b038416600090815260036020526106ee9060409020336000908152602091909152604090205483611054565b6001600160a01b038516600090815260036020526040902033600090815260209190915260409020555b6001600160a01b0384166000908152600260205261073b90604090205483611054565b6001600160a01b0385166000908152600260205260409020556001600160a01b0383166000908152600260205261077790604090205483611064565b6001600160a01b0384166000908152600260205260409020556001600160a01b038084169085167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405190815260200160405180910390a35060019392505050565b7fea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb81565b601281565b60055481565b336000908152602081905260409020546001146108625760405162461bcd60e51b815260206004820152601260248201527111185a4bdb9bdd0b585d5d1a1bdc9a5e995960721b604482015260640160405180910390fd5b6001600160a01b0382166000908152600260205261088590604090205482611064565b6001600160a01b0383166000908152600260205260409020556001546108ab9082611064565b6001556001600160a01b03821660007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405190815260200160405180910390a35050565b6040516040808201905260018152603160f81b602082015281565b336000908152602081905260409020546001146109645760405162461bcd60e51b815260206004820152601260248201527111185a4bdb9bdd0b585d5d1a1bdc9a5e995960721b604482015260640160405180910390fd5b6001600160a01b0381166000908152602081905260019060409020555961012081016040526020815260e0602082015260e060006040830137602435600435336001600160e01b03196000351661012085a45050565b600260205280600052604060002054905081565b600460205280600052604060002054905081565b6005546000907fea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb8a8a8a8a8a60405160208101969096526001600160a01b03948516604080880191909152939094166060860152608085019190915260a084015290151560c083015260e090910190516020818303038152906040528051906020012060405161190160f01b6020820152602281019290925260428201526062016040516020818303038152906040528051906020012090506001600160a01b038916610aed5760405162461bcd60e51b815260206004820152601560248201527404461692f696e76616c69642d616464726573732d3605c1b604482015260640160405180910390fd5b60018185858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015610b4a573d6000803e3d6000fd5b505050602060405103516001600160a01b0316896001600160a01b031614610bad5760405162461bcd60e51b815260206004820152601260248201527111185a4bda5b9d985b1a590b5c195c9b5a5d60721b604482015260640160405180910390fd5b851580610bba5750854211155b610bff5760405162461bcd60e51b815260206004820152601260248201527111185a4bdc195c9b5a5d0b595e1c1a5c995960721b604482015260640160405180910390fd5b6001600160a01b03891660009081526004602052604090208054600181019091558714610c665760405162461bcd60e51b81526020600482015260116024820152704461692f696e76616c69642d6e6f6e636560781b604482015260640160405180910390fd5b600085610c74576000610c78565b6000195b6001600160a01b038b16600090815260036020529091508190604090206001600160a01b038b16600090815260209190915260409020556001600160a01b03808a16908b167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258360405190815260200160405180910390a350505050505050505050565b60405160408082019052600381526244414960e81b602082015281565b33600090815260208190526040902054600114610d715760405162461bcd60e51b815260206004820152601260248201527111185a4bdb9bdd0b585d5d1a1bdc9a5e995960721b604482015260640160405180910390fd5b6001600160a01b0381166000908152602081905260408120555961012081016040526020815260e0602082015260e060006040830137602435600435336001600160e01b03196000351661012085a45050565b6001600160a01b03821660009081526002602052819060409020541015610e2c5760405162461bcd60e51b81526020600482015260186024820152774461692f696e73756666696369656e742d62616c616e636560401b604482015260640160405180910390fd5b6001600160a01b0382163314801590610e7057506001600160a01b038216600090815260036020526000199060409020336000908152602091909152604090205414155b15610f4f576001600160a01b0382166000908152600360205281906040902033600090815260209190915260409020541015610ef25760405162461bcd60e51b815260206004820152601a60248201527f4461692f696e73756666696369656e742d616c6c6f77616e6365000000000000604482015260640160405180910390fd5b6001600160a01b03821660009081526003602052610f259060409020336000908152602091909152604090205482611054565b6001600160a01b038316600090815260036020526040902033600090815260209190915260409020555b6001600160a01b03821660009081526002602052610f7290604090205482611054565b6001600160a01b038316600090815260026020526040902055600154610f989082611054565b60015560006001600160a01b0383167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405190815260200160405180910390a35050565b6000610feb33848461058e565b9392505050565b610ffd33838361058e565b505050565b61100d83838361058e565b50505050565b600060205280600052604060002054905081565b6003602052816000526040600020602052806000526040600020549150829050565b610ffd82338361058e565b8082038281111561058257600080fd5b8082018281101561058257600080fdfea265627a7a72315820d670b7dc276d39d169b5192a7d4fac20cfb44486987d854f4d394d78918e0b3a64736f6c634300050c0032454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e7472616374290000000000000000000000000000000000000000000000000000000000007a69c080a01cd675d4d7c3abc92268c8a70fbdcde1a8751290205a6ac0e8ee7cc626e93149a04f720684be3c3dc506815ceb829d0f200f8688bc74342dfb8534fca40646b28f","0x02f907ff827a690184b2d05e008509c7652400838954408080b907a360c0604052600d60808190527f577261707065642045746865720000000000000000000000000000000000000060a090815261003e91600091906100a3565b506040805180820190915260048082527f57455448000000000000000000000000000000000000000000000000000000006020909201918252610083916001916100a3565b506002805460ff1916601217905534801561009d57600080fd5b5061013e565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100e457805160ff1916838001178555610111565b82800160010185558215610111579182015b828111156101115782518255916020019190600101906100f6565b5061011d929150610121565b5090565b61013b91905b8082111561011d5760008155600101610127565b90565b6106568061014d6000396000f3006080604052600436106100925760003560e01c63ffffffff16806306fdde031461009c578063095ea7b31461012657806318160ddd1461015e57806323b872dd146101855780632e1a7d4d146101af578063313ce567146101c757806370a08231146101f257806395d89b4114610213578063a9059cbb14610228578063d0e30db014610092578063dd62ed3e1461024c575b61009a610273565b005b3480156100a857600080fd5b506100b16102c2565b6040805160208082528351818301528351919283929083019185019080838360005b838110156100eb5781810151838201526020016100d3565b50505050905090810190601f1680156101185780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561013257600080fd5b5061014a600160a060020a0360043516602435610350565b604080519115158252519081900360200190f35b34801561016a57600080fd5b506101736103b6565b60408051918252519081900360200190f35b34801561019157600080fd5b5061014a600160a060020a03600435811690602435166044356103bb565b3480156101bb57600080fd5b5061009a6004356104ef565b3480156101d357600080fd5b506101dc610584565b6040805160ff9092168252519081900360200190f35b3480156101fe57600080fd5b50610173600160a060020a036004351661058d565b34801561021f57600080fd5b506100b161059f565b34801561023457600080fd5b5061014a600160a060020a03600435166024356105f9565b34801561025857600080fd5b50610173600160a060020a036004358116906024351661060d565b33600081815260036020908152604091829020805434908101909155825190815291517fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c9281900390910190a2565b6000805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156103485780601f1061031d57610100808354040283529160200191610348565b820191906000526020600020905b81548152906001019060200180831161032b57829003601f168201915b505050505081565b336000818152600460209081526040808320600160a060020a038716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a350600192915050565b303190565b600160a060020a0383166000908152600360205260408120548211156103e057600080fd5b600160a060020a038416331480159061041e5750600160a060020a038416600090815260046020908152604080832033845290915290205460001914155b1561047e57600160a060020a038416600090815260046020908152604080832033845290915290205482111561045357600080fd5b600160a060020a03841660009081526004602090815260408083203384529091529020805483900390555b600160a060020a03808516600081815260036020908152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a35060019392505050565b3360009081526003602052604090205481111561050b57600080fd5b33600081815260036020526040808220805485900390555183156108fc0291849190818181858888f1935050505015801561054a573d6000803e3d6000fd5b5060408051828152905133917f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65919081900360200190a250565b60025460ff1681565b60036020526000908152604090205481565b60018054604080516020600284861615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156103485780601f1061031d57610100808354040283529160200191610348565b60006106063384846103bb565b9392505050565b6004602090815260009283526040808420909152908252902054815600a165627a7a7230582001c5bfe9ec4c6d446b01537f87db92275608d83ff931e343a863bc98bd9efc930029c001a08060c4c7c280ad346bdf342fb01fd0e2e8cd55c58c98f7182e435468287c0498a0559e06131f076a306a9c049ec0b672d3ed26e6f9212948a210c5a5471a2a39e4","0x02f92a81827a690284b2d05e008509c7652400838954408080b92a25608060405234801561001057600080fd5b50604051612a05380380612a058339818101604052602081101561003357600080fd5b5051600180546001600160a01b0319166001600160a01b039092169190911790556129a2806100636000396000f3fe608060405234801561001057600080fd5b50600436106100785760003560e01c8063017e7e581461007d578063094b7415146100a15780631e3dd18b146100a9578063574f2ba3146100c6578063a2e74af6146100e0578063c9c6539614610108578063e6a4390514610136578063f46901ed14610164575b600080fd5b61008561018a565b604080516001600160a01b039092168252519081900360200190f35b610085610199565b610085600480360360208110156100bf57600080fd5b50356101a8565b6100ce6101cf565b60408051918252519081900360200190f35b610106600480360360208110156100f657600080fd5b50356001600160a01b03166101d5565b005b6100856004803603604081101561011e57600080fd5b506001600160a01b038135811691602001351661024d565b6100856004803603604081101561014c57600080fd5b506001600160a01b0381358116916020013516610578565b6101066004803603602081101561017a57600080fd5b50356001600160a01b031661059e565b6000546001600160a01b031681565b6001546001600160a01b031681565b600381815481106101b557fe5b6000918252602090912001546001600160a01b0316905081565b60035490565b6001546001600160a01b0316331461022b576040805162461bcd60e51b81526020600482015260146024820152732ab734b9bbb0b82b191d102327a92124a22222a760611b604482015290519081900360640190fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000816001600160a01b0316836001600160a01b031614156102b6576040805162461bcd60e51b815260206004820152601e60248201527f556e697377617056323a204944454e544943414c5f4144445245535345530000604482015290519081900360640190fd5b600080836001600160a01b0316856001600160a01b0316106102d95783856102dc565b84845b90925090506001600160a01b038216610336576040805162461bcd60e51b8152602060048201526017602482015276556e697377617056323a205a45524f5f4144445245535360481b604482015290519081900360640190fd5b6001600160a01b038281166000908152600260209081526040808320858516845290915290205416156103a9576040805162461bcd60e51b8152602060048201526016602482015275556e697377617056323a20504149525f45584953545360501b604482015290519081900360640190fd5b6060604051806020016103bb90610616565b6020820181038252601f19601f8201166040525090506000838360405160200180836001600160a01b03166001600160a01b031660601b8152601401826001600160a01b03166001600160a01b031660601b815260140192505050604051602081830303815290604052805190602001209050808251602084016000f56040805163485cc95560e01b81526001600160a01b038781166004830152868116602483015291519297509087169163485cc9559160448082019260009290919082900301818387803b15801561048e57600080fd5b505af11580156104a2573d6000803e3d6000fd5b505050506001600160a01b0384811660008181526002602081815260408084208987168086529083528185208054978d166001600160a01b031998891681179091559383528185208686528352818520805488168517905560038054600181018255958190527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b90950180549097168417909655925483519283529082015281517f0d3648bd0f6ba80134a33ba9275ac585d9d315f0ad8355cddefde31afa28d0e9929181900390910190a35050505092915050565b60026020908152600092835260408084209091529082529020546001600160a01b031681565b6001546001600160a01b031633146105f4576040805162461bcd60e51b81526020600482015260146024820152732ab734b9bbb0b82b191d102327a92124a22222a760611b604482015290519081900360640190fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b61234a806106248339019056fe60806040526001600c5534801561001557600080fd5b5060405146908060526122f88239604080519182900360520182208282018252600a8352692ab734b9bbb0b8102b1960b11b6020938401528151808301835260018152603160f81b908401528151808401919091527fbfcc8ef98ffbf7b6c3fec7bf5185b566b9863e35a9d83acd49ad6824b5969738818301527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6606082015260808101949094523060a0808601919091528151808603909101815260c09094019052825192019190912060035550600580546001600160a01b031916331790556121f3806101056000396000f3fe608060405234801561001057600080fd5b50600436106101495760003560e01c8063022c0d9f1461014e57806306fdde03146101da5780630902f1ac14610257578063095ea7b31461028f5780630dfe1681146102cf57806318160ddd146102f357806323b872dd1461030d57806330adf81f14610343578063313ce5671461034b5780633644e51514610369578063485cc955146103715780635909c0d51461039f5780635a3d5493146103a75780636a627842146103af57806370a08231146103d55780637464fc3d146103fb5780637ecebe001461040357806389afcb441461042957806395d89b4114610468578063a9059cbb14610470578063ba9a7a561461049c578063bc25cf77146104a4578063c45a0155146104ca578063d21220a7146104d2578063d505accf146104da578063dd62ed3e1461052b578063fff6cae914610559575b600080fd5b6101d86004803603608081101561016457600080fd5b8135916020810135916001600160a01b036040830135169190810190608081016060820135600160201b81111561019a57600080fd5b8201836020820111156101ac57600080fd5b803590602001918460018302840111600160201b831117156101cd57600080fd5b509092509050610561565b005b6101e2610a9c565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561021c578181015183820152602001610204565b50505050905090810190601f1680156102495780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61025f610ac2565b604080516001600160701b03948516815292909316602083015263ffffffff168183015290519081900360600190f35b6102bb600480360360408110156102a557600080fd5b506001600160a01b038135169060200135610aec565b604080519115158252519081900360200190f35b6102d7610b03565b604080516001600160a01b039092168252519081900360200190f35b6102fb610b12565b60408051918252519081900360200190f35b6102bb6004803603606081101561032357600080fd5b506001600160a01b03813581169160208101359091169060400135610b18565b6102fb610bb2565b610353610bd6565b6040805160ff9092168252519081900360200190f35b6102fb610bdb565b6101d86004803603604081101561038757600080fd5b506001600160a01b0381358116916020013516610be1565b6102fb610c65565b6102fb610c6b565b6102fb600480360360208110156103c557600080fd5b50356001600160a01b0316610c71565b6102fb600480360360208110156103eb57600080fd5b50356001600160a01b0316610f71565b6102fb610f83565b6102fb6004803603602081101561041957600080fd5b50356001600160a01b0316610f89565b61044f6004803603602081101561043f57600080fd5b50356001600160a01b0316610f9b565b6040805192835260208301919091528051918290030190f35b6101e2611341565b6102bb6004803603604081101561048657600080fd5b506001600160a01b038135169060200135611363565b6102fb611370565b6101d8600480360360208110156104ba57600080fd5b50356001600160a01b0316611376565b6102d76114e1565b6102d76114f0565b6101d8600480360360e08110156104f057600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c001356114ff565b6102fb6004803603604081101561054157600080fd5b506001600160a01b0381358116916020013516611700565b6101d861171d565b600c546001146105ac576040805162461bcd60e51b8152602060048201526011602482015270155b9a5cddd85c158c8e881313d0d2d151607a1b604482015290519081900360640190fd5b6000600c55841515806105bf5750600084115b6105fa5760405162461bcd60e51b81526004018080602001828103825260258152602001806120e56025913960400191505060405180910390fd5b600080610605610ac2565b5091509150816001600160701b03168710801561062a5750806001600160701b031686105b6106655760405162461bcd60e51b815260040180806020018281038252602181526020018061212e6021913960400191505060405180910390fd5b60065460075460009182916001600160a01b039182169190811690891682148015906106a35750806001600160a01b0316896001600160a01b031614155b6106ec576040805162461bcd60e51b8152602060048201526015602482015274556e697377617056323a20494e56414c49445f544f60581b604482015290519081900360640190fd5b8a156106fd576106fd828a8d61187f565b891561070e5761070e818a8c61187f565b86156107c957886001600160a01b03166310d1e85c338d8d8c8c6040518663ffffffff1660e01b815260040180866001600160a01b03166001600160a01b03168152602001858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509650505050505050600060405180830381600087803b1580156107b057600080fd5b505af11580156107c4573d6000803e3d6000fd5b505050505b604080516370a0823160e01b815230600482015290516001600160a01b038416916370a08231916024808301926020929190829003018186803b15801561080f57600080fd5b505afa158015610823573d6000803e3d6000fd5b505050506040513d602081101561083957600080fd5b5051604080516370a0823160e01b815230600482015290519195506001600160a01b038316916370a0823191602480820192602092909190829003018186803b15801561088557600080fd5b505afa158015610899573d6000803e3d6000fd5b505050506040513d60208110156108af57600080fd5b5051925060009150506001600160701b0385168a900383116108d25760006108e1565b89856001600160701b03160383035b9050600089856001600160701b03160383116108fe57600061090d565b89856001600160701b03160383035b9050600082118061091e5750600081115b6109595760405162461bcd60e51b815260040180806020018281038252602481526020018061210a6024913960400191505060405180910390fd5b600061098d61096f84600363ffffffff611a1216565b610981876103e863ffffffff611a1216565b9063ffffffff611a7516565b905060006109a561096f84600363ffffffff611a1216565b90506109d6620f42406109ca6001600160701b038b8116908b1663ffffffff611a1216565b9063ffffffff611a1216565b6109e6838363ffffffff611a1216565b1015610a28576040805162461bcd60e51b815260206004820152600c60248201526b556e697377617056323a204b60a01b604482015290519081900360640190fd5b5050610a3684848888611ac5565b60408051838152602081018390528082018d9052606081018c905290516001600160a01b038b169133917fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229181900360800190a350506001600c55505050505050505050565b6040518060400160405280600a8152602001692ab734b9bbb0b8102b1960b11b81525081565b6008546001600160701b0380821692600160701b830490911691600160e01b900463ffffffff1690565b6000610af9338484611c7c565b5060015b92915050565b6006546001600160a01b031681565b60005481565b6001600160a01b038316600090815260026020908152604080832033845290915281205460001914610b9d576001600160a01b0384166000908152600260209081526040808320338452909152902054610b78908363ffffffff611a7516565b6001600160a01b03851660009081526002602090815260408083203384529091529020555b610ba8848484611cde565b5060019392505050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b601281565b60035481565b6005546001600160a01b03163314610c37576040805162461bcd60e51b81526020600482015260146024820152732ab734b9bbb0b82b191d102327a92124a22222a760611b604482015290519081900360640190fd5b600680546001600160a01b039384166001600160a01b03199182161790915560078054929093169116179055565b60095481565b600a5481565b6000600c54600114610cbe576040805162461bcd60e51b8152602060048201526011602482015270155b9a5cddd85c158c8e881313d0d2d151607a1b604482015290519081900360640190fd5b6000600c81905580610cce610ac2565b50600654604080516370a0823160e01b815230600482015290519395509193506000926001600160a01b03909116916370a08231916024808301926020929190829003018186803b158015610d2257600080fd5b505afa158015610d36573d6000803e3d6000fd5b505050506040513d6020811015610d4c57600080fd5b5051600754604080516370a0823160e01b815230600482015290519293506000926001600160a01b03909216916370a0823191602480820192602092909190829003018186803b158015610d9f57600080fd5b505afa158015610db3573d6000803e3d6000fd5b505050506040513d6020811015610dc957600080fd5b505190506000610de8836001600160701b03871663ffffffff611a7516565b90506000610e05836001600160701b03871663ffffffff611a7516565b90506000610e138787611d86565b60005490915080610e5057610e3c6103e8610981610e37878763ffffffff611a1216565b611ee4565b9850610e4b60006103e8611f36565b610e9f565b610e9c6001600160701b038916610e6d868463ffffffff611a1216565b81610e7457fe5b046001600160701b038916610e8f868563ffffffff611a1216565b81610e9657fe5b04611fba565b98505b60008911610ede5760405162461bcd60e51b81526004018080602001828103825260288152602001806121776028913960400191505060405180910390fd5b610ee88a8a611f36565b610ef486868a8a611ac5565b8115610f2457600854610f20906001600160701b0380821691600160701b90041663ffffffff611a1216565b600b555b6040805185815260208101859052815133927f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f928290030190a250506001600c5550949695505050505050565b60016020526000908152604090205481565b600b5481565b60046020526000908152604090205481565b600080600c54600114610fe9576040805162461bcd60e51b8152602060048201526011602482015270155b9a5cddd85c158c8e881313d0d2d151607a1b604482015290519081900360640190fd5b6000600c81905580610ff9610ac2565b50600654600754604080516370a0823160e01b815230600482015290519496509294506001600160a01b039182169391169160009184916370a08231916024808301926020929190829003018186803b15801561105557600080fd5b505afa158015611069573d6000803e3d6000fd5b505050506040513d602081101561107f57600080fd5b5051604080516370a0823160e01b815230600482015290519192506000916001600160a01b038516916370a08231916024808301926020929190829003018186803b1580156110cd57600080fd5b505afa1580156110e1573d6000803e3d6000fd5b505050506040513d60208110156110f757600080fd5b5051306000908152600160205260408120549192506111168888611d86565b6000549091508061112d848763ffffffff611a1216565b8161113457fe5b049a5080611148848663ffffffff611a1216565b8161114f57fe5b04995060008b118015611162575060008a115b61119d5760405162461bcd60e51b815260040180806020018281038252602881526020018061214f6028913960400191505060405180910390fd5b6111a73084611fd2565b6111b2878d8d61187f565b6111bd868d8c61187f565b604080516370a0823160e01b815230600482015290516001600160a01b038916916370a08231916024808301926020929190829003018186803b15801561120357600080fd5b505afa158015611217573d6000803e3d6000fd5b505050506040513d602081101561122d57600080fd5b5051604080516370a0823160e01b815230600482015290519196506001600160a01b038816916370a0823191602480820192602092909190829003018186803b15801561127957600080fd5b505afa15801561128d573d6000803e3d6000fd5b505050506040513d60208110156112a357600080fd5b505193506112b385858b8b611ac5565b81156112e3576008546112df906001600160701b0380821691600160701b90041663ffffffff611a1216565b600b555b604080518c8152602081018c905281516001600160a01b038f169233927fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496929081900390910190a35050505050505050506001600c81905550915091565b604051806040016040528060068152602001652aa72496ab1960d11b81525081565b6000610af9338484611cde565b6103e881565b600c546001146113c1576040805162461bcd60e51b8152602060048201526011602482015270155b9a5cddd85c158c8e881313d0d2d151607a1b604482015290519081900360640190fd5b6000600c55600654600754600854604080516370a0823160e01b815230600482015290516001600160a01b039485169490931692611470928592879261146b926001600160701b03169185916370a0823191602480820192602092909190829003018186803b15801561143357600080fd5b505afa158015611447573d6000803e3d6000fd5b505050506040513d602081101561145d57600080fd5b50519063ffffffff611a7516565b61187f565b600854604080516370a0823160e01b815230600482015290516114d7928492879261146b92600160701b90046001600160701b0316916001600160a01b038616916370a0823191602480820192602092909190829003018186803b15801561143357600080fd5b50506001600c5550565b6005546001600160a01b031681565b6007546001600160a01b031681565b42841015611549576040805162461bcd60e51b8152602060048201526012602482015271155b9a5cddd85c158c8e881156141254915160721b604482015290519081900360640190fd5b6003546001600160a01b0380891660008181526004602090815260408083208054600180820190925582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98186015280840196909652958d166060860152608085018c905260a085019590955260c08085018b90528151808603909101815260e08501825280519083012061190160f01b6101008601526101028501969096526101228085019690965280518085039096018652610142840180825286519683019690962095839052610162840180825286905260ff89166101828501526101a284018890526101c28401879052519193926101e280820193601f1981019281900390910190855afa158015611664573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381161580159061169a5750886001600160a01b0316816001600160a01b0316145b6116ea576040805162461bcd60e51b815260206004820152601c60248201527b556e697377617056323a20494e56414c49445f5349474e415455524560201b604482015290519081900360640190fd5b6116f5898989611c7c565b505050505050505050565b600260209081526000928352604080842090915290825290205481565b600c54600114611768576040805162461bcd60e51b8152602060048201526011602482015270155b9a5cddd85c158c8e881313d0d2d151607a1b604482015290519081900360640190fd5b6000600c55600654604080516370a0823160e01b81523060048201529051611878926001600160a01b0316916370a08231916024808301926020929190829003018186803b1580156117b957600080fd5b505afa1580156117cd573d6000803e3d6000fd5b505050506040513d60208110156117e357600080fd5b5051600754604080516370a0823160e01b815230600482015290516001600160a01b03909216916370a0823191602480820192602092909190829003018186803b15801561183057600080fd5b505afa158015611844573d6000803e3d6000fd5b505050506040513d602081101561185a57600080fd5b50516008546001600160701b0380821691600160701b900416611ac5565b6001600c55565b60408051808201825260198152787472616e7366657228616464726573732c75696e743235362960381b60209182015281516001600160a01b0385811660248301526044808301869052845180840390910181526064909201845291810180516001600160e01b031663a9059cbb60e01b1781529251815160009460609489169392918291908083835b602083106119285780518252601f199092019160209182019101611909565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811461198a576040519150601f19603f3d011682016040523d82523d6000602084013e61198f565b606091505b50915091508180156119bd5750805115806119bd57508080602001905160208110156119ba57600080fd5b50515b611a0b576040805162461bcd60e51b815260206004820152601a602482015279155b9a5cddd85c158c8e881514905394d1915497d1905253115160321b604482015290519081900360640190fd5b5050505050565b6000811580611a2d57505080820282828281611a2a57fe5b04145b610afd576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604482015290519081900360640190fd5b80820382811115610afd576040805162461bcd60e51b815260206004820152601560248201527464732d6d6174682d7375622d756e646572666c6f7760581b604482015290519081900360640190fd5b6001600160701b038411801590611ae357506001600160701b038311155b611b2a576040805162461bcd60e51b8152602060048201526013602482015272556e697377617056323a204f564552464c4f5760681b604482015290519081900360640190fd5b60085463ffffffff42811691600160e01b90048116820390811615801590611b5a57506001600160701b03841615155b8015611b6e57506001600160701b03831615155b15611bdf578063ffffffff16611b9c85611b878661205e565b6001600160e01b03169063ffffffff61207016565b600980546001600160e01b03929092169290920201905563ffffffff8116611bc784611b878761205e565b600a80546001600160e01b0392909216929092020190555b600880546001600160701b0319166001600160701b0388811691909117600160701b600160e01b031916600160701b8883168102919091176001600160e01b0316600160e01b63ffffffff871602179283905560408051848416815291909304909116602082015281517f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1929181900390910190a1505050505050565b6001600160a01b03808416600081815260026020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6001600160a01b038316600090815260016020526040902054611d07908263ffffffff611a7516565b6001600160a01b038085166000908152600160205260408082209390935590841681522054611d3c908263ffffffff61209516565b6001600160a01b03808416600081815260016020908152604091829020949094558051858152905191939287169260008051602061219f83398151915292918290030190a3505050565b600080600560009054906101000a90046001600160a01b03166001600160a01b031663017e7e586040518163ffffffff1660e01b815260040160206040518083038186803b158015611dd757600080fd5b505afa158015611deb573d6000803e3d6000fd5b505050506040513d6020811015611e0157600080fd5b5051600b546001600160a01b038216158015945091925090611ed0578015611ecb576000611e44610e376001600160701b0388811690881663ffffffff611a1216565b90506000611e5183611ee4565b905080821115611ec8576000611e7f611e70848463ffffffff611a7516565b6000549063ffffffff611a1216565b90506000611ea483611e9886600563ffffffff611a1216565b9063ffffffff61209516565b90506000818381611eb157fe5b0490508015611ec457611ec48782611f36565b5050505b50505b611edc565b8015611edc576000600b555b505092915050565b60006003821115611f27575080600160028204015b81811015611f2157809150600281828581611f1057fe5b040181611f1957fe5b049050611ef9565b50611f31565b8115611f31575060015b919050565b600054611f49908263ffffffff61209516565b60009081556001600160a01b038316815260016020526040902054611f74908263ffffffff61209516565b6001600160a01b038316600081815260016020908152604080832094909455835185815293519293919260008051602061219f8339815191529281900390910190a35050565b6000818310611fc95781611fcb565b825b9392505050565b6001600160a01b038216600090815260016020526040902054611ffb908263ffffffff611a7516565b6001600160a01b03831660009081526001602052604081209190915554612028908263ffffffff611a7516565b60009081556040805183815290516001600160a01b0385169160008051602061219f833981519152919081900360200190a35050565b6001600160701b0316600160701b0290565b60006001600160701b0382166001600160e01b0384168161208d57fe5b049392505050565b80820182811015610afd576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6164642d6f766572666c6f7760601b604482015290519081900360640190fdfe556e697377617056323a20494e53554646494349454e545f4f55545055545f414d4f554e54556e697377617056323a20494e53554646494349454e545f494e5055545f414d4f554e54556e697377617056323a20494e53554646494349454e545f4c4951554944495459556e697377617056323a20494e53554646494349454e545f4c49515549444954595f4255524e4544556e697377617056323a20494e53554646494349454e545f4c49515549444954595f4d494e544544ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa265627a7a72315820d1325da065d459a6b690a73bb78bff8905bbb02ca590c2d032d22e0acf7005b364736f6c63430005100032454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429a265627a7a72315820b7a30f541a46ac26196b0a24a93826fbfeb0c2cb66dc0f377b40d1c93ec210e164736f6c63430005100032000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266c080a0358ba65e0265b024ef0c4665f140dd5d8074d4d2eb8b19e6e815696e5f0bc566a030281095e6d59ce0727770971a53771c7ef9fb46c80a721b2773c363aecd82fb","0x02f92a81827a690384b2d05e008509c7652400838954408080b92a25608060405234801561001057600080fd5b50604051612a05380380612a058339818101604052602081101561003357600080fd5b5051600180546001600160a01b0319166001600160a01b039092169190911790556129a2806100636000396000f3fe608060405234801561001057600080fd5b50600436106100785760003560e01c8063017e7e581461007d578063094b7415146100a15780631e3dd18b146100a9578063574f2ba3146100c6578063a2e74af6146100e0578063c9c6539614610108578063e6a4390514610136578063f46901ed14610164575b600080fd5b61008561018a565b604080516001600160a01b039092168252519081900360200190f35b610085610199565b610085600480360360208110156100bf57600080fd5b50356101a8565b6100ce6101cf565b60408051918252519081900360200190f35b610106600480360360208110156100f657600080fd5b50356001600160a01b03166101d5565b005b6100856004803603604081101561011e57600080fd5b506001600160a01b038135811691602001351661024d565b6100856004803603604081101561014c57600080fd5b506001600160a01b0381358116916020013516610578565b6101066004803603602081101561017a57600080fd5b50356001600160a01b031661059e565b6000546001600160a01b031681565b6001546001600160a01b031681565b600381815481106101b557fe5b6000918252602090912001546001600160a01b0316905081565b60035490565b6001546001600160a01b0316331461022b576040805162461bcd60e51b81526020600482015260146024820152732ab734b9bbb0b82b191d102327a92124a22222a760611b604482015290519081900360640190fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000816001600160a01b0316836001600160a01b031614156102b6576040805162461bcd60e51b815260206004820152601e60248201527f556e697377617056323a204944454e544943414c5f4144445245535345530000604482015290519081900360640190fd5b600080836001600160a01b0316856001600160a01b0316106102d95783856102dc565b84845b90925090506001600160a01b038216610336576040805162461bcd60e51b8152602060048201526017602482015276556e697377617056323a205a45524f5f4144445245535360481b604482015290519081900360640190fd5b6001600160a01b038281166000908152600260209081526040808320858516845290915290205416156103a9576040805162461bcd60e51b8152602060048201526016602482015275556e697377617056323a20504149525f45584953545360501b604482015290519081900360640190fd5b6060604051806020016103bb90610616565b6020820181038252601f19601f8201166040525090506000838360405160200180836001600160a01b03166001600160a01b031660601b8152601401826001600160a01b03166001600160a01b031660601b815260140192505050604051602081830303815290604052805190602001209050808251602084016000f56040805163485cc95560e01b81526001600160a01b038781166004830152868116602483015291519297509087169163485cc9559160448082019260009290919082900301818387803b15801561048e57600080fd5b505af11580156104a2573d6000803e3d6000fd5b505050506001600160a01b0384811660008181526002602081815260408084208987168086529083528185208054978d166001600160a01b031998891681179091559383528185208686528352818520805488168517905560038054600181018255958190527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b90950180549097168417909655925483519283529082015281517f0d3648bd0f6ba80134a33ba9275ac585d9d315f0ad8355cddefde31afa28d0e9929181900390910190a35050505092915050565b60026020908152600092835260408084209091529082529020546001600160a01b031681565b6001546001600160a01b031633146105f4576040805162461bcd60e51b81526020600482015260146024820152732ab734b9bbb0b82b191d102327a92124a22222a760611b604482015290519081900360640190fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b61234a806106248339019056fe60806040526001600c5534801561001557600080fd5b5060405146908060526122f88239604080519182900360520182208282018252600a8352692ab734b9bbb0b8102b1960b11b6020938401528151808301835260018152603160f81b908401528151808401919091527fbfcc8ef98ffbf7b6c3fec7bf5185b566b9863e35a9d83acd49ad6824b5969738818301527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6606082015260808101949094523060a0808601919091528151808603909101815260c09094019052825192019190912060035550600580546001600160a01b031916331790556121f3806101056000396000f3fe608060405234801561001057600080fd5b50600436106101495760003560e01c8063022c0d9f1461014e57806306fdde03146101da5780630902f1ac14610257578063095ea7b31461028f5780630dfe1681146102cf57806318160ddd146102f357806323b872dd1461030d57806330adf81f14610343578063313ce5671461034b5780633644e51514610369578063485cc955146103715780635909c0d51461039f5780635a3d5493146103a75780636a627842146103af57806370a08231146103d55780637464fc3d146103fb5780637ecebe001461040357806389afcb441461042957806395d89b4114610468578063a9059cbb14610470578063ba9a7a561461049c578063bc25cf77146104a4578063c45a0155146104ca578063d21220a7146104d2578063d505accf146104da578063dd62ed3e1461052b578063fff6cae914610559575b600080fd5b6101d86004803603608081101561016457600080fd5b8135916020810135916001600160a01b036040830135169190810190608081016060820135600160201b81111561019a57600080fd5b8201836020820111156101ac57600080fd5b803590602001918460018302840111600160201b831117156101cd57600080fd5b509092509050610561565b005b6101e2610a9c565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561021c578181015183820152602001610204565b50505050905090810190601f1680156102495780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61025f610ac2565b604080516001600160701b03948516815292909316602083015263ffffffff168183015290519081900360600190f35b6102bb600480360360408110156102a557600080fd5b506001600160a01b038135169060200135610aec565b604080519115158252519081900360200190f35b6102d7610b03565b604080516001600160a01b039092168252519081900360200190f35b6102fb610b12565b60408051918252519081900360200190f35b6102bb6004803603606081101561032357600080fd5b506001600160a01b03813581169160208101359091169060400135610b18565b6102fb610bb2565b610353610bd6565b6040805160ff9092168252519081900360200190f35b6102fb610bdb565b6101d86004803603604081101561038757600080fd5b506001600160a01b0381358116916020013516610be1565b6102fb610c65565b6102fb610c6b565b6102fb600480360360208110156103c557600080fd5b50356001600160a01b0316610c71565b6102fb600480360360208110156103eb57600080fd5b50356001600160a01b0316610f71565b6102fb610f83565b6102fb6004803603602081101561041957600080fd5b50356001600160a01b0316610f89565b61044f6004803603602081101561043f57600080fd5b50356001600160a01b0316610f9b565b6040805192835260208301919091528051918290030190f35b6101e2611341565b6102bb6004803603604081101561048657600080fd5b506001600160a01b038135169060200135611363565b6102fb611370565b6101d8600480360360208110156104ba57600080fd5b50356001600160a01b0316611376565b6102d76114e1565b6102d76114f0565b6101d8600480360360e08110156104f057600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c001356114ff565b6102fb6004803603604081101561054157600080fd5b506001600160a01b0381358116916020013516611700565b6101d861171d565b600c546001146105ac576040805162461bcd60e51b8152602060048201526011602482015270155b9a5cddd85c158c8e881313d0d2d151607a1b604482015290519081900360640190fd5b6000600c55841515806105bf5750600084115b6105fa5760405162461bcd60e51b81526004018080602001828103825260258152602001806120e56025913960400191505060405180910390fd5b600080610605610ac2565b5091509150816001600160701b03168710801561062a5750806001600160701b031686105b6106655760405162461bcd60e51b815260040180806020018281038252602181526020018061212e6021913960400191505060405180910390fd5b60065460075460009182916001600160a01b039182169190811690891682148015906106a35750806001600160a01b0316896001600160a01b031614155b6106ec576040805162461bcd60e51b8152602060048201526015602482015274556e697377617056323a20494e56414c49445f544f60581b604482015290519081900360640190fd5b8a156106fd576106fd828a8d61187f565b891561070e5761070e818a8c61187f565b86156107c957886001600160a01b03166310d1e85c338d8d8c8c6040518663ffffffff1660e01b815260040180866001600160a01b03166001600160a01b03168152602001858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509650505050505050600060405180830381600087803b1580156107b057600080fd5b505af11580156107c4573d6000803e3d6000fd5b505050505b604080516370a0823160e01b815230600482015290516001600160a01b038416916370a08231916024808301926020929190829003018186803b15801561080f57600080fd5b505afa158015610823573d6000803e3d6000fd5b505050506040513d602081101561083957600080fd5b5051604080516370a0823160e01b815230600482015290519195506001600160a01b038316916370a0823191602480820192602092909190829003018186803b15801561088557600080fd5b505afa158015610899573d6000803e3d6000fd5b505050506040513d60208110156108af57600080fd5b5051925060009150506001600160701b0385168a900383116108d25760006108e1565b89856001600160701b03160383035b9050600089856001600160701b03160383116108fe57600061090d565b89856001600160701b03160383035b9050600082118061091e5750600081115b6109595760405162461bcd60e51b815260040180806020018281038252602481526020018061210a6024913960400191505060405180910390fd5b600061098d61096f84600363ffffffff611a1216565b610981876103e863ffffffff611a1216565b9063ffffffff611a7516565b905060006109a561096f84600363ffffffff611a1216565b90506109d6620f42406109ca6001600160701b038b8116908b1663ffffffff611a1216565b9063ffffffff611a1216565b6109e6838363ffffffff611a1216565b1015610a28576040805162461bcd60e51b815260206004820152600c60248201526b556e697377617056323a204b60a01b604482015290519081900360640190fd5b5050610a3684848888611ac5565b60408051838152602081018390528082018d9052606081018c905290516001600160a01b038b169133917fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229181900360800190a350506001600c55505050505050505050565b6040518060400160405280600a8152602001692ab734b9bbb0b8102b1960b11b81525081565b6008546001600160701b0380821692600160701b830490911691600160e01b900463ffffffff1690565b6000610af9338484611c7c565b5060015b92915050565b6006546001600160a01b031681565b60005481565b6001600160a01b038316600090815260026020908152604080832033845290915281205460001914610b9d576001600160a01b0384166000908152600260209081526040808320338452909152902054610b78908363ffffffff611a7516565b6001600160a01b03851660009081526002602090815260408083203384529091529020555b610ba8848484611cde565b5060019392505050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b601281565b60035481565b6005546001600160a01b03163314610c37576040805162461bcd60e51b81526020600482015260146024820152732ab734b9bbb0b82b191d102327a92124a22222a760611b604482015290519081900360640190fd5b600680546001600160a01b039384166001600160a01b03199182161790915560078054929093169116179055565b60095481565b600a5481565b6000600c54600114610cbe576040805162461bcd60e51b8152602060048201526011602482015270155b9a5cddd85c158c8e881313d0d2d151607a1b604482015290519081900360640190fd5b6000600c81905580610cce610ac2565b50600654604080516370a0823160e01b815230600482015290519395509193506000926001600160a01b03909116916370a08231916024808301926020929190829003018186803b158015610d2257600080fd5b505afa158015610d36573d6000803e3d6000fd5b505050506040513d6020811015610d4c57600080fd5b5051600754604080516370a0823160e01b815230600482015290519293506000926001600160a01b03909216916370a0823191602480820192602092909190829003018186803b158015610d9f57600080fd5b505afa158015610db3573d6000803e3d6000fd5b505050506040513d6020811015610dc957600080fd5b505190506000610de8836001600160701b03871663ffffffff611a7516565b90506000610e05836001600160701b03871663ffffffff611a7516565b90506000610e138787611d86565b60005490915080610e5057610e3c6103e8610981610e37878763ffffffff611a1216565b611ee4565b9850610e4b60006103e8611f36565b610e9f565b610e9c6001600160701b038916610e6d868463ffffffff611a1216565b81610e7457fe5b046001600160701b038916610e8f868563ffffffff611a1216565b81610e9657fe5b04611fba565b98505b60008911610ede5760405162461bcd60e51b81526004018080602001828103825260288152602001806121776028913960400191505060405180910390fd5b610ee88a8a611f36565b610ef486868a8a611ac5565b8115610f2457600854610f20906001600160701b0380821691600160701b90041663ffffffff611a1216565b600b555b6040805185815260208101859052815133927f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f928290030190a250506001600c5550949695505050505050565b60016020526000908152604090205481565b600b5481565b60046020526000908152604090205481565b600080600c54600114610fe9576040805162461bcd60e51b8152602060048201526011602482015270155b9a5cddd85c158c8e881313d0d2d151607a1b604482015290519081900360640190fd5b6000600c81905580610ff9610ac2565b50600654600754604080516370a0823160e01b815230600482015290519496509294506001600160a01b039182169391169160009184916370a08231916024808301926020929190829003018186803b15801561105557600080fd5b505afa158015611069573d6000803e3d6000fd5b505050506040513d602081101561107f57600080fd5b5051604080516370a0823160e01b815230600482015290519192506000916001600160a01b038516916370a08231916024808301926020929190829003018186803b1580156110cd57600080fd5b505afa1580156110e1573d6000803e3d6000fd5b505050506040513d60208110156110f757600080fd5b5051306000908152600160205260408120549192506111168888611d86565b6000549091508061112d848763ffffffff611a1216565b8161113457fe5b049a5080611148848663ffffffff611a1216565b8161114f57fe5b04995060008b118015611162575060008a115b61119d5760405162461bcd60e51b815260040180806020018281038252602881526020018061214f6028913960400191505060405180910390fd5b6111a73084611fd2565b6111b2878d8d61187f565b6111bd868d8c61187f565b604080516370a0823160e01b815230600482015290516001600160a01b038916916370a08231916024808301926020929190829003018186803b15801561120357600080fd5b505afa158015611217573d6000803e3d6000fd5b505050506040513d602081101561122d57600080fd5b5051604080516370a0823160e01b815230600482015290519196506001600160a01b038816916370a0823191602480820192602092909190829003018186803b15801561127957600080fd5b505afa15801561128d573d6000803e3d6000fd5b505050506040513d60208110156112a357600080fd5b505193506112b385858b8b611ac5565b81156112e3576008546112df906001600160701b0380821691600160701b90041663ffffffff611a1216565b600b555b604080518c8152602081018c905281516001600160a01b038f169233927fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496929081900390910190a35050505050505050506001600c81905550915091565b604051806040016040528060068152602001652aa72496ab1960d11b81525081565b6000610af9338484611cde565b6103e881565b600c546001146113c1576040805162461bcd60e51b8152602060048201526011602482015270155b9a5cddd85c158c8e881313d0d2d151607a1b604482015290519081900360640190fd5b6000600c55600654600754600854604080516370a0823160e01b815230600482015290516001600160a01b039485169490931692611470928592879261146b926001600160701b03169185916370a0823191602480820192602092909190829003018186803b15801561143357600080fd5b505afa158015611447573d6000803e3d6000fd5b505050506040513d602081101561145d57600080fd5b50519063ffffffff611a7516565b61187f565b600854604080516370a0823160e01b815230600482015290516114d7928492879261146b92600160701b90046001600160701b0316916001600160a01b038616916370a0823191602480820192602092909190829003018186803b15801561143357600080fd5b50506001600c5550565b6005546001600160a01b031681565b6007546001600160a01b031681565b42841015611549576040805162461bcd60e51b8152602060048201526012602482015271155b9a5cddd85c158c8e881156141254915160721b604482015290519081900360640190fd5b6003546001600160a01b0380891660008181526004602090815260408083208054600180820190925582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98186015280840196909652958d166060860152608085018c905260a085019590955260c08085018b90528151808603909101815260e08501825280519083012061190160f01b6101008601526101028501969096526101228085019690965280518085039096018652610142840180825286519683019690962095839052610162840180825286905260ff89166101828501526101a284018890526101c28401879052519193926101e280820193601f1981019281900390910190855afa158015611664573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381161580159061169a5750886001600160a01b0316816001600160a01b0316145b6116ea576040805162461bcd60e51b815260206004820152601c60248201527b556e697377617056323a20494e56414c49445f5349474e415455524560201b604482015290519081900360640190fd5b6116f5898989611c7c565b505050505050505050565b600260209081526000928352604080842090915290825290205481565b600c54600114611768576040805162461bcd60e51b8152602060048201526011602482015270155b9a5cddd85c158c8e881313d0d2d151607a1b604482015290519081900360640190fd5b6000600c55600654604080516370a0823160e01b81523060048201529051611878926001600160a01b0316916370a08231916024808301926020929190829003018186803b1580156117b957600080fd5b505afa1580156117cd573d6000803e3d6000fd5b505050506040513d60208110156117e357600080fd5b5051600754604080516370a0823160e01b815230600482015290516001600160a01b03909216916370a0823191602480820192602092909190829003018186803b15801561183057600080fd5b505afa158015611844573d6000803e3d6000fd5b505050506040513d602081101561185a57600080fd5b50516008546001600160701b0380821691600160701b900416611ac5565b6001600c55565b60408051808201825260198152787472616e7366657228616464726573732c75696e743235362960381b60209182015281516001600160a01b0385811660248301526044808301869052845180840390910181526064909201845291810180516001600160e01b031663a9059cbb60e01b1781529251815160009460609489169392918291908083835b602083106119285780518252601f199092019160209182019101611909565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811461198a576040519150601f19603f3d011682016040523d82523d6000602084013e61198f565b606091505b50915091508180156119bd5750805115806119bd57508080602001905160208110156119ba57600080fd5b50515b611a0b576040805162461bcd60e51b815260206004820152601a602482015279155b9a5cddd85c158c8e881514905394d1915497d1905253115160321b604482015290519081900360640190fd5b5050505050565b6000811580611a2d57505080820282828281611a2a57fe5b04145b610afd576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604482015290519081900360640190fd5b80820382811115610afd576040805162461bcd60e51b815260206004820152601560248201527464732d6d6174682d7375622d756e646572666c6f7760581b604482015290519081900360640190fd5b6001600160701b038411801590611ae357506001600160701b038311155b611b2a576040805162461bcd60e51b8152602060048201526013602482015272556e697377617056323a204f564552464c4f5760681b604482015290519081900360640190fd5b60085463ffffffff42811691600160e01b90048116820390811615801590611b5a57506001600160701b03841615155b8015611b6e57506001600160701b03831615155b15611bdf578063ffffffff16611b9c85611b878661205e565b6001600160e01b03169063ffffffff61207016565b600980546001600160e01b03929092169290920201905563ffffffff8116611bc784611b878761205e565b600a80546001600160e01b0392909216929092020190555b600880546001600160701b0319166001600160701b0388811691909117600160701b600160e01b031916600160701b8883168102919091176001600160e01b0316600160e01b63ffffffff871602179283905560408051848416815291909304909116602082015281517f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1929181900390910190a1505050505050565b6001600160a01b03808416600081815260026020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6001600160a01b038316600090815260016020526040902054611d07908263ffffffff611a7516565b6001600160a01b038085166000908152600160205260408082209390935590841681522054611d3c908263ffffffff61209516565b6001600160a01b03808416600081815260016020908152604091829020949094558051858152905191939287169260008051602061219f83398151915292918290030190a3505050565b600080600560009054906101000a90046001600160a01b03166001600160a01b031663017e7e586040518163ffffffff1660e01b815260040160206040518083038186803b158015611dd757600080fd5b505afa158015611deb573d6000803e3d6000fd5b505050506040513d6020811015611e0157600080fd5b5051600b546001600160a01b038216158015945091925090611ed0578015611ecb576000611e44610e376001600160701b0388811690881663ffffffff611a1216565b90506000611e5183611ee4565b905080821115611ec8576000611e7f611e70848463ffffffff611a7516565b6000549063ffffffff611a1216565b90506000611ea483611e9886600563ffffffff611a1216565b9063ffffffff61209516565b90506000818381611eb157fe5b0490508015611ec457611ec48782611f36565b5050505b50505b611edc565b8015611edc576000600b555b505092915050565b60006003821115611f27575080600160028204015b81811015611f2157809150600281828581611f1057fe5b040181611f1957fe5b049050611ef9565b50611f31565b8115611f31575060015b919050565b600054611f49908263ffffffff61209516565b60009081556001600160a01b038316815260016020526040902054611f74908263ffffffff61209516565b6001600160a01b038316600081815260016020908152604080832094909455835185815293519293919260008051602061219f8339815191529281900390910190a35050565b6000818310611fc95781611fcb565b825b9392505050565b6001600160a01b038216600090815260016020526040902054611ffb908263ffffffff611a7516565b6001600160a01b03831660009081526001602052604081209190915554612028908263ffffffff611a7516565b60009081556040805183815290516001600160a01b0385169160008051602061219f833981519152919081900360200190a35050565b6001600160701b0316600160701b0290565b60006001600160701b0382166001600160e01b0384168161208d57fe5b049392505050565b80820182811015610afd576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6164642d6f766572666c6f7760601b604482015290519081900360640190fdfe556e697377617056323a20494e53554646494349454e545f4f55545055545f414d4f554e54556e697377617056323a20494e53554646494349454e545f494e5055545f414d4f554e54556e697377617056323a20494e53554646494349454e545f4c4951554944495459556e697377617056323a20494e53554646494349454e545f4c49515549444954595f4255524e4544556e697377617056323a20494e53554646494349454e545f4c49515549444954595f4d494e544544ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa265627a7a72315820d1325da065d459a6b690a73bb78bff8905bbb02ca590c2d032d22e0acf7005b364736f6c63430005100032454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429a265627a7a72315820b7a30f541a46ac26196b0a24a93826fbfeb0c2cb66dc0f377b40d1c93ec210e164736f6c63430005100032000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266c001a0a02481bb11c30807a97e229de965fb91be02e015016c8067f86f1a66e376711aa06f31f2adb32253f977724ae7b80c559e76c684e2c0cb1fc7c0bf77dfc4269ed3","0x02f91649827a690484b2d05e008509c7652400838954408080b915ed608060405234801561001057600080fd5b506040516115cd3803806115cd83398101604081905261002f9161006a565b600080546001600160a01b039092166001600160a01b031992831681179091556002805483169091179055600180549091163317905561009a565b60006020828403121561007c57600080fd5b81516001600160a01b038116811461009357600080fd5b9392505050565b611524806100a96000396000f3fe60806040526004361061003f5760003560e01c80630cc732631461004157806328a070251461006157806386f89bd214610076578063ad5c464814610096575b005b34801561004d57600080fd5b5061003f61005c36600461116d565b6100cc565b34801561006d57600080fd5b5061003f610351565b34801561008257600080fd5b5061003f61009136600461126d565b610432565b3480156100a257600080fd5b506000546100b6906001600160a01b031681565b6040516100c391906112be565b60405180910390f35b6000836001600160a01b031663e6a43905876000815181106100f0576100f06112d2565b60200260200101518860018151811061010b5761010b6112d2565b60200260200101516040518363ffffffff1660e01b81526004016101309291906112e8565b602060405180830381865afa15801561014d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101719190611302565b90506000610180858789610928565b905061034887600081518110610198576101986112d2565b60200260200101516001600160a01b0316836001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061020b9190611302565b6001600160a01b031614610239578160018151811061022c5761022c6112d2565b6020026020010151610255565b8160008151811061024c5761024c6112d2565b60200260200101515b88600081518110610268576102686112d2565b60200260200101516001600160a01b0316846001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102db9190611302565b6001600160a01b03161461030957826000815181106102fc576102fc6112d2565b6020026020010151610325565b8260018151811061031c5761031c6112d2565b60200260200101515b89600081518110610338576103386112d2565b6020026020010151858888610ab2565b50505050505050565b6002546001546040516370a0823160e01b81526001600160a01b039283169263a9059cbb92169083906370a082319061038e9030906004016112be565b602060405180830381865afa1580156103ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103cf9190611326565b6040518363ffffffff1660e01b81526004016103ec92919061133f565b6020604051808303816000875af115801561040b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061042f9190611358565b50565b6002546040516370a0823160e01b81526000916001600160a01b0316906370a08231906104639030906004016112be565b602060405180830381865afa158015610480573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a49190611326565b604080516002808252606082018352929350600092909160208301908036833750506040805160028082526060820183529394506000939092509060208301908036833750506000805485519394506001600160a01b03169285925061050c5761050c6112d2565b60200260200101906001600160a01b031690816001600160a01b0316815250508682600181518110610540576105406112d2565b60200260200101906001600160a01b031690816001600160a01b0316815250508681600081518110610574576105746112d2565b6001600160a01b0392831660209182029290920101526000548251911690829060019081106105a5576105a56112d2565b60200260200101906001600160a01b031690816001600160a01b0316815250506105d38285883060006100cc565b61064d81886001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161060391906112be565b602060405180830381865afa158015610620573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106449190611326565b873060016100cc565b610657848461138b565b6002546040516370a0823160e01b81526001600160a01b03909116906370a08231906106879030906004016112be565b602060405180830381865afa1580156106a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106c89190611326565b1161070f5760405162461bcd60e51b8152602060048201526012602482015271617262206e6f742070726f66697461626c6560701b60448201526064015b60405180910390fd5b6002546040516370a0823160e01b815260009161271091879187916001600160a01b03909116906370a082319061074a9030906004016112be565b602060405180830381865afa158015610767573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078b9190611326565b61079591906113a3565b61079f91906113a3565b6107ab906123286113ba565b6107b591906113d9565b600254604051632e1a7d4d60e01b8152600481018390529192506001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156107fc57600080fd5b505af1158015610810573d6000803e3d6000fd5b505060405141925083156108fc02915083906000818181858888f19350505050158015610841573d6000803e3d6000fd5b506002546040516370a0823160e01b81526001600160a01b039091169063a9059cbb90339083906370a082319061087c9030906004016112be565b602060405180830381865afa158015610899573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108bd9190611326565b6040518363ffffffff1660e01b81526004016108da92919061133f565b6020604051808303816000875af11580156108f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061091d9190611358565b505050505050505050565b606060028251101561097c5760405162461bcd60e51b815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f5041544800006044820152606401610706565b81516001600160401b0381111561099557610995611119565b6040519080825280602002602001820160405280156109be578160200160208202803683370190505b50905082816000815181106109d5576109d56112d2565b60200260200101818152505060005b600183516109f291906113a3565b811015610aaa57600080610a4587868581518110610a1257610a126112d2565b602002602001015187866001610a28919061138b565b81518110610a3857610a386112d2565b6020026020010151610d13565b91509150610a6d848481518110610a5e57610a5e6112d2565b60200260200101518383610e41565b84610a7985600161138b565b81518110610a8957610a896112d2565b60200260200101818152505050508080610aa2906113fb565b9150506109e4565b509392505050565b600083905060008590506000866001600160a01b0316836001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2a9190611302565b6001600160a01b031614610b3e5787610b40565b885b905083610bc5576040516323b872dd60e01b81523360048201526001600160a01b038781166024830152604482018390528316906323b872dd906064016020604051808303816000875af1158015610b9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc09190611358565b610c36565b60405163a9059cbb60e01b81526001600160a01b0383169063a9059cbb90610bf3908990859060040161133f565b6020604051808303816000875af1158015610c12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c369190611358565b610c745760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b6044820152606401610706565b826001600160a01b031663022c0d9f828b14610c90578a610c93565b60005b838b14610ca0578a610ca3565b60005b604080516000815260208101918290526001600160e01b031960e086901b16909152610cd69291908a9060248101611414565b600060405180830381600087803b158015610cf057600080fd5b505af1158015610d04573d6000803e3d6000fd5b50505050505050505050505050565b6000806000610d228585610f60565b509050600080876001600160a01b031663e6a4390588886040518363ffffffff1660e01b8152600401610d569291906112e8565b602060405180830381865afa158015610d73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d979190611302565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610dd4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df8919061149e565b506001600160701b031691506001600160701b03169150826001600160a01b0316876001600160a01b031614610e2f578082610e32565b81815b90999098509650505050505050565b6000808411610ea65760405162461bcd60e51b815260206004820152602b60248201527f556e697377617056324c6962726172793a20494e53554646494349454e545f4960448201526a1394155517d05353d5539560aa1b6064820152608401610706565b600083118015610eb65750600082115b610f135760405162461bcd60e51b815260206004820152602860248201527f556e697377617056324c6962726172793a20494e53554646494349454e545f4c604482015267495155494449545960c01b6064820152608401610706565b6000610f21856103e5611057565b90506000610f2f8285611057565b90506000610f4983610f43886103e8611057565b906110c4565b9050610f5581836113d9565b979650505050505050565b600080826001600160a01b0316846001600160a01b031603610fd25760405162461bcd60e51b815260206004820152602560248201527f556e697377617056324c6962726172793a204944454e544943414c5f41444452604482015264455353455360d81b6064820152608401610706565b826001600160a01b0316846001600160a01b031610610ff2578284610ff5565b83835b90925090506001600160a01b0382166110505760405162461bcd60e51b815260206004820152601e60248201527f556e697377617056324c6962726172793a205a45524f5f4144445245535300006044820152606401610706565b9250929050565b600081158061107b5750828261106d81836113ba565b925061107990836113d9565b145b6110be5760405162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6d756c2d6f766572666c6f7760601b6044820152606401610706565b92915050565b6000826110d1838261138b565b91508110156110be5760405162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6164642d6f766572666c6f7760601b6044820152606401610706565b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461042f57600080fd5b803561114f8161112f565b919050565b801515811461042f57600080fd5b803561114f81611154565b600080600080600060a0868803121561118557600080fd5b85356001600160401b038082111561119c57600080fd5b818801915088601f8301126111b057600080fd5b81356020828211156111c4576111c4611119565b8160051b604051601f19603f830116810181811086821117156111e9576111e9611119565b60405292835281830193508481018201928c84111561120757600080fd5b948201945b8386101561122c5761121d86611144565b8552948201949382019361120c565b9950508901359650611245925050604088019050611144565b925061125360608701611144565b915061126160808701611162565b90509295509295909350565b6000806000806080858703121561128357600080fd5b843561128e8161112f565b9350602085013561129e8161112f565b925060408501356112ae8161112f565b9396929550929360600135925050565b6001600160a01b0391909116815260200190565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b0392831681529116602082015260400190565b60006020828403121561131457600080fd5b815161131f8161112f565b9392505050565b60006020828403121561133857600080fd5b5051919050565b6001600160a01b03929092168252602082015260400190565b60006020828403121561136a57600080fd5b815161131f81611154565b634e487b7160e01b600052601160045260246000fd5b6000821982111561139e5761139e611375565b500190565b6000828210156113b5576113b5611375565b500390565b60008160001904831182151516156113d4576113d4611375565b500290565b6000826113f657634e487b7160e01b600052601260045260246000fd5b500490565b60006001820161140d5761140d611375565b5060010190565b84815260006020858184015260018060a01b038516604084015260806060840152835180608085015260005b8181101561145c5785810183015185820160a001528201611440565b8181111561146e57600060a083870101525b50601f01601f19169290920160a0019695505050505050565b80516001600160701b038116811461114f57600080fd5b6000806000606084860312156114b357600080fd5b6114bc84611487565b92506114ca60208501611487565b9150604084015163ffffffff811681146114e357600080fd5b80915050925092509256fea264697066735822122056de7304a31d183a3dfa9b25652c4207ed22159820ff00ce0cc54a296dfb156464736f6c634300080f0033000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f0512c080a03fef6a6fad9d78f0aa9b2f7a9b854c023ab4bf2f253193fb66d0ed77b294d39aa034f4563fc6b11078091231342cdd5a147a398a7f697c99f398cfd91f2856cb2d","0x02f8b3827a690584b2d05e008509c765240083895440949fe46736679d2d9a65f0992f2272de9f3c7fa6e080b844c9c653960000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa3000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f0512c001a059afa1cc6b422e154868aef2b79a8fb03daf2182fd2ffdca6b123dc9a458c486a01544836a08b02d909a2c5de37c4bf7df20214f0240d57042d1cabf90118d5a62","0x02f8b3827a690684b2d05e008509c76524008389544094cf7ed3acca5a467e9e704c703e8d87f634fb0fc980b844c9c653960000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa3000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f0512c001a0f64818aea2512ba52c78528e790d7bc43b4796dc85f000407325966c1c234f10a0322edb7af2319f751500af1a207d069fbee151241c068eec93d4811897e5620d","0x02f8b3827a690784b2d05e008509c765240083895440945fbdb2315678afecb367f032d93f642f64180aa380b84440c10f19000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266000000000000000000000000000000000000000000023128c9b0d24284400000c001a0d8f76c611d0397d7791cfb5c331bddbf4332c5e784550005e6d33d1535c49081a014af8dff5ec5eb22d23802d5c376163307f175a7c75a48cfc01719ad0dba26a0","0x02f8b3827a690884b2d05e008509c765240083895440945fbdb2315678afecb367f032d93f642f64180aa380b84440c10f1900000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000a968163f0a57b400000c080a03b69fdf945e81304e9181898255d8ff7b85f27fa6ec1bb91054f6e77b071c974a01fa58b301b0d54c956818ee7800b63c679b874b86e0a09347837547e307382e9","0x02f87c827a690984b2d05e008509c76524008389544094e7f1725e7734ce288f8367e1bb143e90bb3f05128a01e7e4171bf4d3a0000084d0e30db0c001a0ffd7930ad56e4c2e1b6c1a128519260eaf7bcad571642c644a74e05a41a1bab7a06865fad86dba9e0ce1e485ec7ec6d0a4045c6102da7705a622da9212842e50df","0x02f87b827a698084b2d05e008509c76524008389544094e7f1725e7734ce288f8367e1bb143e90bb3f0512893635c9adc5dea0000084d0e30db0c080a02dc99c950c03b837be13608b7fbf0fd23492e034b2006f914aaa61280f097a7ba00428acbd13736c8fe30057a2d90aedd830b194f2a0ab72d0ce74e09ae73c8c2b","0x02f8b3827a690a84b2d05e008509c765240083895440945fbdb2315678afecb367f032d93f642f64180aa380b844095ea7b3000000000000000000000000dc64a140aa3e981100a9beca4e685f962f0cf6c9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc080a085d0f76d75f7980ebc8d2a3175d5b0843bf68e848e5ab73a00f322a3e09ed50da04c140f61d2f66b910a929daba6cc9060d9f4e56af24be81ed608b37b80b6864a","0x02f8b3827a690b84b2d05e008509c76524008389544094e7f1725e7734ce288f8367e1bb143e90bb3f051280b844095ea7b3000000000000000000000000dc64a140aa3e981100a9beca4e685f962f0cf6c9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a03be1762b9f24775147255eeba30c4dcdc884af36b2038e7498cf3a5d7dafd07ba00c33242be6246bb12363ff493a038a3d427102287372599c0aebdfb72d6fa603","0x02f8b3827a690184b2d05e008509c765240083895440945fbdb2315678afecb367f032d93f642f64180aa380b844095ea7b3000000000000000000000000dc64a140aa3e981100a9beca4e685f962f0cf6c9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a03eb9dfb46dfcdbb8493e5cc45d689fc7644c6d34da396741ffb8bcd4df40c13aa03100fd36a2e52021091b71b2e47d4a4b6cc3741464d3e805ec0ce450488b2ed0","0x02f8b3827a690284b2d05e008509c76524008389544094e7f1725e7734ce288f8367e1bb143e90bb3f051280b844095ea7b3000000000000000000000000dc64a140aa3e981100a9beca4e685f962f0cf6c9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a0087fa5c3f2aacec062b7a3b83588141c4010b4878ae40c5d1593325142d34f6ba009cf9af1da675d62bef97906aadc91db9cf414fdbc9f4c8f370a839a066f3964","0x02f8b3827a690c84b2d05e008509c76524008389544094e7f1725e7734ce288f8367e1bb143e90bb3f051280b844a9059cbb000000000000000000000000aa444ecdc1f8b16a936afdd4a3de6c7bead164f200000000000000000000000000000000000000000000003635c9adc5dea00000c080a0a2379ebd083250c697675c7fc9c8b3c46512bcc3f9c38767d7307d749bde0d25a0648ede7dcf77686a244174cb4d58d1eda3431c77e73118034481defb970cd0b7","0x02f8b3827a690d84b2d05e008509c765240083895440945fbdb2315678afecb367f032d93f642f64180aa380b844a9059cbb000000000000000000000000aa444ecdc1f8b16a936afdd4a3de6c7bead164f2000000000000000000000000000000000000000000011349242670ce84800000c080a0f71c7786e4d4069908faee6f68685c77ac0b596d59456cece0c24038f1b8244fa015a5cf97ae1a3a0d3a46f169ea818cec32f959b72142fb968b03e68d01f9d88b","0x02f892827a690e84b2d05e008509c76524008389544094aa444ecdc1f8b16a936afdd4a3de6c7bead164f280a46a627842000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266c001a06b37a02e0eb1b941c4415ba3521655592039045830e5570224fae1897214f270a066b4ab829361210433578476d67d2e07c205c8980dc4ddd505813b7cb9a375ec","0x02f8b3827a690f84b2d05e008509c76524008389544094e7f1725e7734ce288f8367e1bb143e90bb3f051280b844a9059cbb00000000000000000000000054739aea3e0a4307c4cd6a8f4d9dbef3e7e2b9ea00000000000000000000000000000000000000000000003635c9adc5dea00000c001a0c86f767964d399e1cd403e11066df0bff47a12377be0b1ce5184060070be158fa06eb1e11f61350193eae3e70f17e74f89aefaf694bb4f2641b0289e268a61ada0","0x02f8b3827a691084b2d05e008509c765240083895440945fbdb2315678afecb367f032d93f642f64180aa380b844a9059cbb00000000000000000000000054739aea3e0a4307c4cd6a8f4d9dbef3e7e2b9ea000000000000000000000000000000000000000000011349242670ce84800000c080a09257dc3b1e2bd30932594d85c3beb61b7b27f240b3b13c4a72d660f0184e64c2a06a491d8ba96c9fe51fa776fca47cf5dec1f4e87af20dbe6f38d1a49cfb14af4e","0x02f892827a691184b2d05e008509c7652400838954409454739aea3e0a4307c4cd6a8f4d9dbef3e7e2b9ea80a46a627842000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266c080a0a2df34d06d0f238866cffe3fa88f36b3d8b3bdc0d2a772bbbfa1e411508c6e55a04fb327b4084104147dccc27a14ceda3890288540b3106c1bffd0aa4a34e0f148"] diff --git a/miner/testdata/dai.abi b/miner/testdata/dai.abi new file mode 100644 index 0000000000..3cdd67f036 --- /dev/null +++ b/miner/testdata/dai.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"uint256","name":"chainId_","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":true,"internalType":"address","name":"guy","type":"address"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":true,"inputs":[{"indexed":true,"internalType":"bytes4","name":"sig","type":"bytes4"},{"indexed":true,"internalType":"address","name":"usr","type":"address"},{"indexed":true,"internalType":"bytes32","name":"arg1","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"arg2","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"LogNote","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":true,"internalType":"address","name":"dst","type":"address"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"}],"name":"Transfer","type":"event"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"usr","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"usr","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"burn","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"guy","type":"address"}],"name":"deny","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"usr","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"mint","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"move","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"bool","name":"allowed","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"usr","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"pull","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"usr","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"push","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"guy","type":"address"}],"name":"rely","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"wards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}] diff --git a/miner/testdata/swap.abi b/miner/testdata/swap.abi new file mode 100644 index 0000000000..a29fa69c16 --- /dev/null +++ b/miner/testdata/swap.abi @@ -0,0 +1,98 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "_weth", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "WETH", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "address", + "name": "_startFactory", + "type": "address" + }, + { + "internalType": "address", + "name": "_endFactory", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amountIn", + "type": "uint256" + } + ], + "name": "backrun", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "liquidate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "address", + "name": "factory", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "bool", + "name": "fromThis", + "type": "bool" + } + ], + "name": "swap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] diff --git a/miner/testdata/univ2factory.abi b/miner/testdata/univ2factory.abi new file mode 100644 index 0000000000..3ae79e0a25 --- /dev/null +++ b/miner/testdata/univ2factory.abi @@ -0,0 +1,193 @@ +[ +{ + "inputs": [ + { + "internalType": "address", + "name": "_feeToSetter", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" +}, +{ + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token0", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "token1", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "pair", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "PairCreated", + "type": "event" +}, +{ + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "allPairs", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" +}, +{ + "constant": true, + "inputs": [], + "name": "allPairsLength", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" +}, +{ + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + } + ], + "name": "createPair", + "outputs": [ + { + "internalType": "address", + "name": "pair", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" +}, +{ + "constant": true, + "inputs": [], + "name": "feeTo", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" +}, +{ + "constant": true, + "inputs": [], + "name": "feeToSetter", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" +}, +{ + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "getPair", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" +}, +{ + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "_feeTo", + "type": "address" + } + ], + "name": "setFeeTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" +}, +{ + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "_feeToSetter", + "type": "address" + } + ], + "name": "setFeeToSetter", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" +} +] diff --git a/miner/testdata/univ2pair.abi b/miner/testdata/univ2pair.abi new file mode 100644 index 0000000000..d55b88644d --- /dev/null +++ b/miner/testdata/univ2pair.abi @@ -0,0 +1,713 @@ +[ + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "Burn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0In", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1In", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount0Out", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount1Out", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "Swap", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint112", + "name": "reserve0", + "type": "uint112" + }, + { + "indexed": false, + "internalType": "uint112", + "name": "reserve1", + "type": "uint112" + } + ], + "name": "Sync", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "constant": true, + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MINIMUM_LIQUIDITY", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "PERMIT_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "burn", + "outputs": [ + { + "internalType": "uint256", + "name": "amount0", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getReserves", + "outputs": [ + { + "internalType": "uint112", + "name": "_reserve0", + "type": "uint112" + }, + { + "internalType": "uint112", + "name": "_reserve1", + "type": "uint112" + }, + { + "internalType": "uint32", + "name": "_blockTimestampLast", + "type": "uint32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "_token0", + "type": "address" + }, + { + "internalType": "address", + "name": "_token1", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "kLast", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "mint", + "outputs": [ + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "permit", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "price0CumulativeLast", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "price1CumulativeLast", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "skim", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "amount0Out", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount1Out", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "swap", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "sync", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "token0", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "token1", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/miner/testdata/univ2router.abi b/miner/testdata/univ2router.abi new file mode 100644 index 0000000000..f6581c8a4b --- /dev/null +++ b/miner/testdata/univ2router.abi @@ -0,0 +1,973 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "_factory", + "type": "address" + }, + { + "internalType": "address", + "name": "_WETH", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "WETH", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountADesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountTokenDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidityETH", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveOut", + "type": "uint256" + } + ], + "name": "getAmountIn", + "outputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveOut", + "type": "uint256" + } + ], + "name": "getAmountOut", + "outputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + } + ], + "name": "getAmountsIn", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + } + ], + "name": "getAmountsOut", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveB", + "type": "uint256" + } + ], + "name": "quote", + "outputs": [ + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidityETH", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidityETHSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityETHWithPermit", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityETHWithPermitSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityWithPermit", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapETHForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactETHForTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactETHForTokensSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForETH", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForETHSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForTokensSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactETH", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/miner/testdata/weth.abi b/miner/testdata/weth.abi new file mode 100644 index 0000000000..68e6e23ff1 --- /dev/null +++ b/miner/testdata/weth.abi @@ -0,0 +1 @@ +[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"},{"name":"wad","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"wad","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"deposit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"guy","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Withdrawal","type":"event"}] diff --git a/miner/worker.go b/miner/worker.go index 9472f4f4c7..e8b99e9d6c 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1113,7 +1113,7 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP if order == nil { break } - tx := order.Tx + tx := order.Tx() if tx == nil { continue } @@ -1204,34 +1204,28 @@ type generateParams struct { onBlock BlockHookFn // Callback to call for each produced block } -// prepareWork constructs the sealing task according to the given parameters, -// either based on the last chain head or specified parent. In this function -// the pending transactions are not filled yet, only the empty task returned. -func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { - w.mu.RLock() - defer w.mu.RUnlock() - +func doPrepareHeader(genParams *generateParams, chain *core.BlockChain, config *Config, chainConfig *params.ChainConfig, extra []byte, engine consensus.Engine) (*types.Header, *types.Block, error) { // Find the parent block for sealing task - parent := w.chain.CurrentBlock() + parent := chain.CurrentBlock() if genParams.parentHash != (common.Hash{}) { - parent = w.chain.GetBlockByHash(genParams.parentHash) + parent = chain.GetBlockByHash(genParams.parentHash) } if parent == nil { - return nil, fmt.Errorf("missing parent") + return nil, nil, fmt.Errorf("missing parent") } // Sanity check the timestamp correctness, recap the timestamp // to parent+1 if the mutation is allowed. timestamp := genParams.timestamp if parent.Time() >= timestamp { if genParams.forceTime { - return nil, fmt.Errorf("invalid timestamp, parent %d given %d", parent.Time(), timestamp) + return nil, nil, fmt.Errorf("invalid timestamp, parent %d given %d", parent.Time(), timestamp) } timestamp = parent.Time() + 1 } // Construct the sealing block header, set the extra field if it's allowed gasTarget := genParams.gasLimit if gasTarget == 0 { - gasTarget = w.config.GasCeil + gasTarget = config.GasCeil } num := parent.Number() header := &types.Header{ @@ -1241,26 +1235,42 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { Time: timestamp, Coinbase: genParams.coinbase, } - if !genParams.noExtra && len(w.extra) != 0 { - header.Extra = w.extra + if !genParams.noExtra && len(extra) != 0 { + header.Extra = extra } // Set the randomness field from the beacon chain if it's available. if genParams.random != (common.Hash{}) { header.MixDigest = genParams.random } // Set baseFee and GasLimit if we are on an EIP-1559 chain - if w.chainConfig.IsLondon(header.Number) { - header.BaseFee = misc.CalcBaseFee(w.chainConfig, parent.Header()) - if !w.chainConfig.IsLondon(parent.Number()) { + if chainConfig.IsLondon(header.Number) { + header.BaseFee = misc.CalcBaseFee(chainConfig, parent.Header()) + if !chainConfig.IsLondon(parent.Number()) { parentGasLimit := parent.GasLimit() * params.ElasticityMultiplier header.GasLimit = core.CalcGasLimit(parentGasLimit, gasTarget) } } // Run the consensus preparation with the default or customized consensus engine. - if err := w.engine.Prepare(w.chain, header); err != nil { + if err := engine.Prepare(chain, header); err != nil { log.Error("Failed to prepare header for sealing", "err", err) + return nil, nil, err + } + + return header, parent, nil +} + +// prepareWork constructs the sealing task according to the given parameters, +// either based on the last chain head or specified parent. In this function +// the pending transactions are not filled yet, only the empty task returned. +func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { + w.mu.RLock() + defer w.mu.RUnlock() + + header, parent, err := doPrepareHeader(genParams, w.chain, w.config, w.chainConfig, w.extra, w.engine) + if err != nil { return nil, err } + // Could potentially happen if starting to mine in an odd state. // Note genParams.coinbase can be different with header.Coinbase // since clique algorithm can modify the coinbase field in header. diff --git a/miner/worker_test.go b/miner/worker_test.go index 6baeea4b86..1d0805a7c3 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -128,16 +128,11 @@ type testWorkerBackend struct { uncleBlock *types.Block } -func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, alloc core.GenesisAlloc, n int) *testWorkerBackend { - var gspec = core.Genesis{ - Config: chainConfig, - Alloc: alloc, - } - +func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, genesis core.Genesis, n int) *testWorkerBackend { switch e := engine.(type) { case *clique.Clique: - gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength) - copy(gspec.ExtraData[32:32+common.AddressLength], testBankAddress.Bytes()) + genesis.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength) + copy(genesis.ExtraData[32:32+common.AddressLength], testBankAddress.Bytes()) e.Authorize(testBankAddress, func(account accounts.Account, s string, data []byte) ([]byte, error) { return crypto.Sign(crypto.Keccak256(data), testBankKey) }) @@ -145,21 +140,21 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine default: t.Fatalf("unexpected consensus engine type: %T", engine) } - genesis := gspec.MustCommit(db) + genesisBlock := genesis.MustCommit(db) - chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec.Config, engine, vm.Config{}, nil, nil) + chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, genesis.Config, engine, vm.Config{}, nil, nil) txpool := core.NewTxPool(testTxPoolConfig, chainConfig, chain) // Generate a small n-block chain and an uncle block for it if n > 0 { - blocks, _ := core.GenerateChain(chainConfig, genesis, engine, db, n, func(i int, gen *core.BlockGen) { + blocks, _ := core.GenerateChain(chainConfig, genesisBlock, engine, db, n, func(i int, gen *core.BlockGen) { gen.SetCoinbase(testBankAddress) }) if _, err := chain.InsertChain(blocks); err != nil { t.Fatalf("failed to insert origin chain: %v", err) } } - parent := genesis + parent := genesisBlock if n > 0 { parent = chain.GetBlockByHash(chain.CurrentBlock().ParentHash()) } @@ -171,7 +166,7 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine db: db, chain: chain, txPool: txpool, - genesis: &gspec, + genesis: &genesis, uncleBlock: blocks[0], } } @@ -208,8 +203,8 @@ func (b *testWorkerBackend) newRandomTx(creation bool, to common.Address, amt in return tx } -func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, alloc core.GenesisAlloc, blocks int) (*worker, *testWorkerBackend) { - backend := newTestWorkerBackend(t, chainConfig, engine, db, alloc, blocks) +func newTestWorkerGenesis(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, genesis core.Genesis, blocks int) (*worker, *testWorkerBackend) { + backend := newTestWorkerBackend(t, chainConfig, engine, db, genesis, blocks) backend.txPool.AddLocals(pendingTxs) w := newWorker(testConfig, chainConfig, engine, backend, new(event.TypeMux), nil, false, &flashbotsData{ isFlashbots: testConfig.AlgoType != ALGO_MEV_GETH, @@ -217,10 +212,21 @@ func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consens bundleCache: NewBundleCache(), algoType: testConfig.AlgoType, }) - w.setEtherbase(testBankAddress) + if testConfig.BuilderTxSigningKey == nil { + w.setEtherbase(testBankAddress) + } return w, backend } +func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, alloc core.GenesisAlloc, blocks int) (*worker, *testWorkerBackend) { + var genesis = core.Genesis{ + Config: chainConfig, + Alloc: alloc, + } + + return newTestWorkerGenesis(t, chainConfig, engine, db, genesis, blocks) +} + func TestGenerateBlockAndImportEthash(t *testing.T) { testGenerateBlockAndImport(t, false) } @@ -770,21 +776,11 @@ func testBundles(t *testing.T) { w.setEtherbase(crypto.PubkeyToAddress(testConfig.BuilderTxSigningKey.PublicKey)) defer w.close() - // This test chain imports the mined blocks. - db2 := rawdb.NewMemoryDatabase() - b.genesis.MustCommit(db2) - chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{}, nil, nil) - defer chain.Stop() - // Ignore empty commit here for less noise. w.skipSealHook = func(task *task) bool { return len(task.receipts) == 0 } - // Wait for mined blocks. - sub := w.mux.Subscribe(core.NewMinedBlockEvent{}) - defer sub.Unsubscribe() - rand.Seed(10) for i := 0; i < 2; i++ { @@ -822,23 +818,23 @@ func testBundles(t *testing.T) { bundles[randomBundleIndex].Txs = append(bundles[randomBundleIndex].Txs, tx) } - blockNumber := big.NewInt(0).Add(chain.CurrentBlock().Number(), big.NewInt(1)) + blockNumber := big.NewInt(0).Add(w.chain.CurrentBlock().Number(), big.NewInt(1)) for _, bundle := range bundles { err := b.txPool.AddMevBundle(bundle.Txs, blockNumber, 0, 0, nil) require.NoError(t, err) } - blockCh, errCh, err := w.getSealingBlock(chain.CurrentBlock().Hash(), chain.CurrentHeader().Time+12, testUserAddress, 0, common.Hash{}, false, false, nil) + blockCh, errCh, err := w.getSealingBlock(w.chain.CurrentBlock().Hash(), w.chain.CurrentHeader().Time+12, testUserAddress, 0, common.Hash{}, false, false, nil) require.NoError(t, err) select { case block := <-blockCh: - state, err := chain.State() + state, err := w.chain.State() require.NoError(t, err) balancePre := state.GetBalance(testUserAddress) - if _, err := chain.InsertChain([]*types.Block{block}); err != nil { + if _, err := w.chain.InsertChain([]*types.Block{block}); err != nil { t.Fatalf("failed to insert new mined block %d: %v", block.NumberU64(), err) } - state, err = chain.StateAt(block.Root()) + state, err = w.chain.StateAt(block.Root()) require.NoError(t, err) balancePost := state.GetBalance(testUserAddress) t.Log("Balances", balancePre, balancePost) diff --git a/test_utils/chan.go b/test_utils/chan.go new file mode 100644 index 0000000000..41be95a805 --- /dev/null +++ b/test_utils/chan.go @@ -0,0 +1,20 @@ +package test_utils + +import "time" + +type ChanResult[V any] struct { + Value V + Timeout bool +} + +func RequireChan[V any](ch chan V, timeout time.Duration) ChanResult[V] { + var v V + select { + case v = <-ch: + return ChanResult[V]{v, false} + case <-time.After(timeout): + return ChanResult[V]{v, true} + } + + return ChanResult[V]{v, true} +}