diff --git a/core/message_handler.go b/core/message_handler.go index 6a4f4f963..d0a4ebf15 100644 --- a/core/message_handler.go +++ b/core/message_handler.go @@ -94,9 +94,9 @@ func (app *App) HandleMessages(ctx context.Context, messages []*p2p.Message) err "from": msg.From.String(), }).Trace("not storing rejected order received from peer") switch rejectedOrderInfo.Status { - case ordervalidator.ROInternalError, ordervalidator.ROEthRPCRequestFailed, ordervalidator.ROCoordinatorRequestFailed, ordervalidator.RODatabaseFullOfOrders: - // Don't incur a negative score for these status types (it might not be - // their fault). + case ordervalidator.ROInternalError, ordervalidator.ROEthRPCRequestFailed, ordervalidator.RODatabaseFullOfOrders: + // Don't incur a negative score for these status types + // (it might not be their fault). default: // For other status types, we need to update the peer's score app.handlePeerScoreEvent(msg.From, psInvalidMessage) diff --git a/docs/db_syncing.md b/docs/db_syncing.md index 5fede2bfa..8d16368d3 100644 --- a/docs/db_syncing.md +++ b/docs/db_syncing.md @@ -39,7 +39,7 @@ Since there might also be orders added to the database that Mesh doesn't know ab | Code | Reason | Should be retried? | | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | ------------------ | -| EthRPCRequestFailed, CoordinatorRequestFailed, CoordinatorEndpointNotFound, InternalError | Failure to validate the order | Yes | +| EthRPCRequestFailed, InternalError | Failure to validate the order | Yes | | MaxOrderSizeExceeded, OrderMaxExpirationExceeded, OrderForIncorrectChain, SenderAddressNotAllowed | Failed Mesh-specific criteria | No | | OrderHasInvalidMakerAssetData, OrderHasInvalidTakerAssetData, OrderHasInvalidSignature, OrderUnfunded, OrderCancelled, OrderFullyFilled, OrderHasInvalidMakerAssetAmount, OrderHasInvalidTakerAssetAmount, OrderExpired | Invalid or unfillable order | No | diff --git a/ethereum/contract_addresses.go b/ethereum/contract_addresses.go index 030e0afb4..56861631b 100644 --- a/ethereum/contract_addresses.go +++ b/ethereum/contract_addresses.go @@ -9,18 +9,16 @@ import ( // ContractAddresses maps a contract's name to it's Ethereum address type ContractAddresses struct { - ERC20Proxy common.Address `json:"erc20Proxy"` - ERC721Proxy common.Address `json:"erc721Proxy"` - ERC1155Proxy common.Address `json:"erc1155Proxy"` - Exchange common.Address `json:"exchange"` - Coordinator common.Address `json:"coordinator"` - CoordinatorRegistry common.Address `json:"coordinatorRegistry"` - DevUtils common.Address `json:"devUtils"` - WETH9 common.Address `json:"weth9"` - ZRXToken common.Address `json:"zrxToken"` - ChaiBridge common.Address `json:"chaiBridge"` - ChaiToken common.Address `json:"chaiToken"` - MaximumGasPrice common.Address `json:"maximumGasPrice"` + ERC20Proxy common.Address `json:"erc20Proxy"` + ERC721Proxy common.Address `json:"erc721Proxy"` + ERC1155Proxy common.Address `json:"erc1155Proxy"` + Exchange common.Address `json:"exchange"` + DevUtils common.Address `json:"devUtils"` + WETH9 common.Address `json:"weth9"` + ZRXToken common.Address `json:"zrxToken"` + ChaiBridge common.Address `json:"chaiBridge"` + ChaiToken common.Address `json:"chaiToken"` + MaximumGasPrice common.Address `json:"maximumGasPrice"` } // GanacheAddresses The addresses that the 0x contracts were deployed to on the Ganache snapshot (chainID = 1337). @@ -31,63 +29,55 @@ func NewContractAddressesForChainID(chainID int) (ContractAddresses, error) { switch chainID { case 1: return ContractAddresses{ - ERC20Proxy: common.HexToAddress("0x95e6f48254609a6ee006f7d493c8e5fb97094cef"), - ERC721Proxy: common.HexToAddress("0xefc70a1b18c432bdc64b596838b4d138f6bc6cad"), - Exchange: common.HexToAddress("0x61935cbdd02287b511119ddb11aeb42f1593b7ef"), - ERC1155Proxy: common.HexToAddress("0x7eefbd48fd63d441ec7435d024ec7c5131019add"), - Coordinator: common.HexToAddress("0x38a795580d0f687e399913a00ddef6a17612c722"), - CoordinatorRegistry: common.HexToAddress("0x45797531b873fd5e519477a070a955764c1a5b07"), - DevUtils: common.HexToAddress("0xb1a3d901bad1df7d710fc8d008db7cdd6bbbffe6"), - WETH9: common.HexToAddress("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"), - ZRXToken: common.HexToAddress("0xe41d2489571d322189246dafa5ebde1f4699f498"), - ChaiBridge: common.HexToAddress("0x77c31eba23043b9a72d13470f3a3a311344d7438"), - ChaiToken: common.HexToAddress("0x06af07097c9eeb7fd685c692751d5c66db49c215"), - MaximumGasPrice: common.HexToAddress("0xe2bfd35306495d11e3c9db0d8de390cda24563cf"), + ERC20Proxy: common.HexToAddress("0x95e6f48254609a6ee006f7d493c8e5fb97094cef"), + ERC721Proxy: common.HexToAddress("0xefc70a1b18c432bdc64b596838b4d138f6bc6cad"), + Exchange: common.HexToAddress("0x61935cbdd02287b511119ddb11aeb42f1593b7ef"), + ERC1155Proxy: common.HexToAddress("0x7eefbd48fd63d441ec7435d024ec7c5131019add"), + DevUtils: common.HexToAddress("0xb1a3d901bad1df7d710fc8d008db7cdd6bbbffe6"), + WETH9: common.HexToAddress("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"), + ZRXToken: common.HexToAddress("0xe41d2489571d322189246dafa5ebde1f4699f498"), + ChaiBridge: common.HexToAddress("0x77c31eba23043b9a72d13470f3a3a311344d7438"), + ChaiToken: common.HexToAddress("0x06af07097c9eeb7fd685c692751d5c66db49c215"), + MaximumGasPrice: common.HexToAddress("0xe2bfd35306495d11e3c9db0d8de390cda24563cf"), }, nil case 3: return ContractAddresses{ - ERC20Proxy: common.HexToAddress("0xb1408f4c245a23c31b98d2c626777d4c0d766caa"), - ERC721Proxy: common.HexToAddress("0xe654aac058bfbf9f83fcaee7793311dd82f6ddb4"), - Exchange: common.HexToAddress("0xfb2dd2a1366de37f7241c83d47da58fd503e2c64"), - ERC1155Proxy: common.HexToAddress("0x19bb6caa3bc34d39e5a23cedfa3e6c7e7f3c931d"), - Coordinator: common.HexToAddress("0x6ff734d96104965c9c1b0108f83abc46e6e501df"), - CoordinatorRegistry: common.HexToAddress("0x403cc23e88c17c4652fb904784d1af640a6722d9"), - DevUtils: common.HexToAddress("0xb1a3d901bad1df7d710fc8d008db7cdd6bbbffe6"), - WETH9: common.HexToAddress("0xc778417e063141139fce010982780140aa0cd5ab"), - ZRXToken: common.HexToAddress("0xff67881f8d12f372d91baae9752eb3631ff0ed00"), - ChaiBridge: common.HexToAddress("0x0000000000000000000000000000000000000000"), - ChaiToken: common.HexToAddress("0x0000000000000000000000000000000000000000"), - MaximumGasPrice: common.HexToAddress("0x407b4128e9ecad8769b2332312a9f655cb9f5f3a"), + ERC20Proxy: common.HexToAddress("0xb1408f4c245a23c31b98d2c626777d4c0d766caa"), + ERC721Proxy: common.HexToAddress("0xe654aac058bfbf9f83fcaee7793311dd82f6ddb4"), + Exchange: common.HexToAddress("0xfb2dd2a1366de37f7241c83d47da58fd503e2c64"), + ERC1155Proxy: common.HexToAddress("0x19bb6caa3bc34d39e5a23cedfa3e6c7e7f3c931d"), + DevUtils: common.HexToAddress("0xb1a3d901bad1df7d710fc8d008db7cdd6bbbffe6"), + WETH9: common.HexToAddress("0xc778417e063141139fce010982780140aa0cd5ab"), + ZRXToken: common.HexToAddress("0xff67881f8d12f372d91baae9752eb3631ff0ed00"), + ChaiBridge: common.HexToAddress("0x0000000000000000000000000000000000000000"), + ChaiToken: common.HexToAddress("0x0000000000000000000000000000000000000000"), + MaximumGasPrice: common.HexToAddress("0x407b4128e9ecad8769b2332312a9f655cb9f5f3a"), }, nil case 4: return ContractAddresses{ - ERC20Proxy: common.HexToAddress("0x2f5ae4f6106e89b4147651688a92256885c5f410"), - ERC721Proxy: common.HexToAddress("0x7656d773e11ff7383a14dcf09a9c50990481cd10"), - ERC1155Proxy: common.HexToAddress("0x19bb6caa3bc34d39e5a23cedfa3e6c7e7f3c931d"), - Exchange: common.HexToAddress("0x198805e9682fceec29413059b68550f92868c129"), - Coordinator: common.HexToAddress("0x70c5385ee5ee4629ef72abd169e888c8b4a12238"), - CoordinatorRegistry: common.HexToAddress("0x1084b6a398e47907bae43fec3ff4b677db6e4fee"), - DevUtils: common.HexToAddress("0xb1a3d901bad1df7d710fc8d008db7cdd6bbbffe6"), - WETH9: common.HexToAddress("0xc778417e063141139fce010982780140aa0cd5ab"), - ZRXToken: common.HexToAddress("0x8080c7e4b81ecf23aa6f877cfbfd9b0c228c6ffa"), - ChaiBridge: common.HexToAddress("0x0000000000000000000000000000000000000000"), - ChaiToken: common.HexToAddress("0x0000000000000000000000000000000000000000"), - MaximumGasPrice: common.HexToAddress("0x47697b44bd89051e93b4d5857ba8e024800a74ac"), + ERC20Proxy: common.HexToAddress("0x2f5ae4f6106e89b4147651688a92256885c5f410"), + ERC721Proxy: common.HexToAddress("0x7656d773e11ff7383a14dcf09a9c50990481cd10"), + ERC1155Proxy: common.HexToAddress("0x19bb6caa3bc34d39e5a23cedfa3e6c7e7f3c931d"), + Exchange: common.HexToAddress("0x198805e9682fceec29413059b68550f92868c129"), + DevUtils: common.HexToAddress("0xb1a3d901bad1df7d710fc8d008db7cdd6bbbffe6"), + WETH9: common.HexToAddress("0xc778417e063141139fce010982780140aa0cd5ab"), + ZRXToken: common.HexToAddress("0x8080c7e4b81ecf23aa6f877cfbfd9b0c228c6ffa"), + ChaiBridge: common.HexToAddress("0x0000000000000000000000000000000000000000"), + ChaiToken: common.HexToAddress("0x0000000000000000000000000000000000000000"), + MaximumGasPrice: common.HexToAddress("0x47697b44bd89051e93b4d5857ba8e024800a74ac"), }, nil case 42: return ContractAddresses{ - ERC20Proxy: common.HexToAddress("0xf1ec01d6236d3cd881a0bf0130ea25fe4234003e"), - ERC721Proxy: common.HexToAddress("0x2a9127c745688a165106c11cd4d647d2220af821"), - Exchange: common.HexToAddress("0x4eacd0af335451709e1e7b570b8ea68edec8bc97"), - ERC1155Proxy: common.HexToAddress("0x64517fa2b480ba3678a2a3c0cf08ef7fd4fad36f"), - Coordinator: common.HexToAddress("0xd29e59e51e8ab5f94121efaeebd935ca4214e257"), - CoordinatorRegistry: common.HexToAddress("0x09fb99968c016a3ff537bf58fb3d9fe55a7975d5"), - DevUtils: common.HexToAddress("0xb1a3d901bad1df7d710fc8d008db7cdd6bbbffe6"), - WETH9: common.HexToAddress("0xd0a1e359811322d97991e03f863a0c30c2cf029c"), - ZRXToken: common.HexToAddress("0x2002d3812f58e35f0ea1ffbf80a75a38c32175fa"), - ChaiBridge: common.HexToAddress("0x0000000000000000000000000000000000000000"), - ChaiToken: common.HexToAddress("0x0000000000000000000000000000000000000000"), - MaximumGasPrice: common.HexToAddress("0x67a094cf028221ffdd93fc658f963151d05e2a74"), + ERC20Proxy: common.HexToAddress("0xf1ec01d6236d3cd881a0bf0130ea25fe4234003e"), + ERC721Proxy: common.HexToAddress("0x2a9127c745688a165106c11cd4d647d2220af821"), + Exchange: common.HexToAddress("0x4eacd0af335451709e1e7b570b8ea68edec8bc97"), + ERC1155Proxy: common.HexToAddress("0x64517fa2b480ba3678a2a3c0cf08ef7fd4fad36f"), + DevUtils: common.HexToAddress("0xb1a3d901bad1df7d710fc8d008db7cdd6bbbffe6"), + WETH9: common.HexToAddress("0xd0a1e359811322d97991e03f863a0c30c2cf029c"), + ZRXToken: common.HexToAddress("0x2002d3812f58e35f0ea1ffbf80a75a38c32175fa"), + ChaiBridge: common.HexToAddress("0x0000000000000000000000000000000000000000"), + ChaiToken: common.HexToAddress("0x0000000000000000000000000000000000000000"), + MaximumGasPrice: common.HexToAddress("0x67a094cf028221ffdd93fc658f963151d05e2a74"), }, nil case 1337: return ganacheAddresses(), nil @@ -115,10 +105,6 @@ func ValidateContractAddressesForChainID(chainID int, addresses ContractAddresse if addresses.ERC1155Proxy == constants.NullAddress { return fmt.Errorf("cannot add contract addresses for chain ID %d: ERC1155Proxy address is required", chainID) } - // TODO(albrow): Uncomment this if we re-add coordinator support. - // if addresses.CoordinatorRegistry == constants.NullAddress { - // return fmt.Errorf("cannot add contract addresses for chain ID %d: CoordinatorRegistry address is required", chainID) - // } return nil } @@ -126,17 +112,15 @@ func ValidateContractAddressesForChainID(chainID int, addresses ContractAddresse // function allows these addresses to only be defined in one place. func ganacheAddresses() ContractAddresses { return ContractAddresses{ - ERC20Proxy: common.HexToAddress("0x1dc4c1cefef38a777b15aa20260a54e584b16c48"), - ERC721Proxy: common.HexToAddress("0x1d7022f5b17d2f8b695918fb48fa1089c9f85401"), - ERC1155Proxy: common.HexToAddress("0x6a4a62e5a7ed13c361b176a5f62c2ee620ac0df8"), - Exchange: common.HexToAddress("0x48bacb9266a570d521063ef5dd96e61686dbe788"), - Coordinator: common.HexToAddress("0x4d3d5c850dd5bd9d6f4adda3dd039a3c8054ca29"), - CoordinatorRegistry: common.HexToAddress("0xaa86dda78e9434aca114b6676fc742a18d15a1cc"), - DevUtils: common.HexToAddress("0xb23672f74749bf7916ba6827c64111a4d6de7f11"), - WETH9: common.HexToAddress("0x0b1ba0af832d7c05fd64161e0db78e85978e8082"), - ZRXToken: common.HexToAddress("0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c"), - ChaiBridge: common.HexToAddress("0x0000000000000000000000000000000000000000"), - ChaiToken: common.HexToAddress("0x0000000000000000000000000000000000000000"), - MaximumGasPrice: common.HexToAddress("0x2c530e4ecc573f11bd72cf5fdf580d134d25f15f"), + ERC20Proxy: common.HexToAddress("0x1dc4c1cefef38a777b15aa20260a54e584b16c48"), + ERC721Proxy: common.HexToAddress("0x1d7022f5b17d2f8b695918fb48fa1089c9f85401"), + ERC1155Proxy: common.HexToAddress("0x6a4a62e5a7ed13c361b176a5f62c2ee620ac0df8"), + Exchange: common.HexToAddress("0x48bacb9266a570d521063ef5dd96e61686dbe788"), + DevUtils: common.HexToAddress("0xb23672f74749bf7916ba6827c64111a4d6de7f11"), + WETH9: common.HexToAddress("0x0b1ba0af832d7c05fd64161e0db78e85978e8082"), + ZRXToken: common.HexToAddress("0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c"), + ChaiBridge: common.HexToAddress("0x0000000000000000000000000000000000000000"), + ChaiToken: common.HexToAddress("0x0000000000000000000000000000000000000000"), + MaximumGasPrice: common.HexToAddress("0x2c530e4ecc573f11bd72cf5fdf580d134d25f15f"), } } diff --git a/ethereum/wrappers/coordinator_registry.go b/ethereum/wrappers/coordinator_registry.go deleted file mode 100644 index a1e7f91c5..000000000 --- a/ethereum/wrappers/coordinator_registry.go +++ /dev/null @@ -1,353 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package wrappers - -import ( - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription -) - -// CoordinatorRegistryABI is the input ABI used to generate the binding from. -const CoordinatorRegistryABI = "[{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorOperator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"coordinatorEndpoint\",\"type\":\"string\"}],\"name\":\"CoordinatorEndpointSet\",\"type\":\"event\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorOperator\",\"type\":\"address\"}],\"name\":\"getCoordinatorEndpoint\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"coordinatorEndpoint\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"string\",\"name\":\"coordinatorEndpoint\",\"type\":\"string\"}],\"name\":\"setCoordinatorEndpoint\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" - -// CoordinatorRegistry is an auto generated Go binding around an Ethereum contract. -type CoordinatorRegistry struct { - CoordinatorRegistryCaller // Read-only binding to the contract - CoordinatorRegistryTransactor // Write-only binding to the contract - CoordinatorRegistryFilterer // Log filterer for contract events -} - -// CoordinatorRegistryCaller is an auto generated read-only Go binding around an Ethereum contract. -type CoordinatorRegistryCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// CoordinatorRegistryTransactor is an auto generated write-only Go binding around an Ethereum contract. -type CoordinatorRegistryTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// CoordinatorRegistryFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type CoordinatorRegistryFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// CoordinatorRegistrySession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type CoordinatorRegistrySession struct { - Contract *CoordinatorRegistry // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// CoordinatorRegistryCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type CoordinatorRegistryCallerSession struct { - Contract *CoordinatorRegistryCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// CoordinatorRegistryTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type CoordinatorRegistryTransactorSession struct { - Contract *CoordinatorRegistryTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// CoordinatorRegistryRaw is an auto generated low-level Go binding around an Ethereum contract. -type CoordinatorRegistryRaw struct { - Contract *CoordinatorRegistry // Generic contract binding to access the raw methods on -} - -// CoordinatorRegistryCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type CoordinatorRegistryCallerRaw struct { - Contract *CoordinatorRegistryCaller // Generic read-only contract binding to access the raw methods on -} - -// CoordinatorRegistryTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type CoordinatorRegistryTransactorRaw struct { - Contract *CoordinatorRegistryTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewCoordinatorRegistry creates a new instance of CoordinatorRegistry, bound to a specific deployed contract. -func NewCoordinatorRegistry(address common.Address, backend bind.ContractBackend) (*CoordinatorRegistry, error) { - contract, err := bindCoordinatorRegistry(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &CoordinatorRegistry{CoordinatorRegistryCaller: CoordinatorRegistryCaller{contract: contract}, CoordinatorRegistryTransactor: CoordinatorRegistryTransactor{contract: contract}, CoordinatorRegistryFilterer: CoordinatorRegistryFilterer{contract: contract}}, nil -} - -// NewCoordinatorRegistryCaller creates a new read-only instance of CoordinatorRegistry, bound to a specific deployed contract. -func NewCoordinatorRegistryCaller(address common.Address, caller bind.ContractCaller) (*CoordinatorRegistryCaller, error) { - contract, err := bindCoordinatorRegistry(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &CoordinatorRegistryCaller{contract: contract}, nil -} - -// NewCoordinatorRegistryTransactor creates a new write-only instance of CoordinatorRegistry, bound to a specific deployed contract. -func NewCoordinatorRegistryTransactor(address common.Address, transactor bind.ContractTransactor) (*CoordinatorRegistryTransactor, error) { - contract, err := bindCoordinatorRegistry(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &CoordinatorRegistryTransactor{contract: contract}, nil -} - -// NewCoordinatorRegistryFilterer creates a new log filterer instance of CoordinatorRegistry, bound to a specific deployed contract. -func NewCoordinatorRegistryFilterer(address common.Address, filterer bind.ContractFilterer) (*CoordinatorRegistryFilterer, error) { - contract, err := bindCoordinatorRegistry(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &CoordinatorRegistryFilterer{contract: contract}, nil -} - -// bindCoordinatorRegistry binds a generic wrapper to an already deployed contract. -func bindCoordinatorRegistry(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(CoordinatorRegistryABI)) - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_CoordinatorRegistry *CoordinatorRegistryRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _CoordinatorRegistry.Contract.CoordinatorRegistryCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_CoordinatorRegistry *CoordinatorRegistryRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _CoordinatorRegistry.Contract.CoordinatorRegistryTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_CoordinatorRegistry *CoordinatorRegistryRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _CoordinatorRegistry.Contract.CoordinatorRegistryTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_CoordinatorRegistry *CoordinatorRegistryCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _CoordinatorRegistry.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_CoordinatorRegistry *CoordinatorRegistryTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _CoordinatorRegistry.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_CoordinatorRegistry *CoordinatorRegistryTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _CoordinatorRegistry.Contract.contract.Transact(opts, method, params...) -} - -// GetCoordinatorEndpoint is a free data retrieval call binding the contract method 0x6c90fedb. -// -// Solidity: function getCoordinatorEndpoint(address coordinatorOperator) view returns(string coordinatorEndpoint) -func (_CoordinatorRegistry *CoordinatorRegistryCaller) GetCoordinatorEndpoint(opts *bind.CallOpts, coordinatorOperator common.Address) (string, error) { - var ( - ret0 = new(string) - ) - out := ret0 - err := _CoordinatorRegistry.contract.Call(opts, out, "getCoordinatorEndpoint", coordinatorOperator) - return *ret0, err -} - -// GetCoordinatorEndpoint is a free data retrieval call binding the contract method 0x6c90fedb. -// -// Solidity: function getCoordinatorEndpoint(address coordinatorOperator) view returns(string coordinatorEndpoint) -func (_CoordinatorRegistry *CoordinatorRegistrySession) GetCoordinatorEndpoint(coordinatorOperator common.Address) (string, error) { - return _CoordinatorRegistry.Contract.GetCoordinatorEndpoint(&_CoordinatorRegistry.CallOpts, coordinatorOperator) -} - -// GetCoordinatorEndpoint is a free data retrieval call binding the contract method 0x6c90fedb. -// -// Solidity: function getCoordinatorEndpoint(address coordinatorOperator) view returns(string coordinatorEndpoint) -func (_CoordinatorRegistry *CoordinatorRegistryCallerSession) GetCoordinatorEndpoint(coordinatorOperator common.Address) (string, error) { - return _CoordinatorRegistry.Contract.GetCoordinatorEndpoint(&_CoordinatorRegistry.CallOpts, coordinatorOperator) -} - -// SetCoordinatorEndpoint is a paid mutator transaction binding the contract method 0x5b2388be. -// -// Solidity: function setCoordinatorEndpoint(string coordinatorEndpoint) returns() -func (_CoordinatorRegistry *CoordinatorRegistryTransactor) SetCoordinatorEndpoint(opts *bind.TransactOpts, coordinatorEndpoint string) (*types.Transaction, error) { - return _CoordinatorRegistry.contract.Transact(opts, "setCoordinatorEndpoint", coordinatorEndpoint) -} - -// SetCoordinatorEndpoint is a paid mutator transaction binding the contract method 0x5b2388be. -// -// Solidity: function setCoordinatorEndpoint(string coordinatorEndpoint) returns() -func (_CoordinatorRegistry *CoordinatorRegistrySession) SetCoordinatorEndpoint(coordinatorEndpoint string) (*types.Transaction, error) { - return _CoordinatorRegistry.Contract.SetCoordinatorEndpoint(&_CoordinatorRegistry.TransactOpts, coordinatorEndpoint) -} - -// SetCoordinatorEndpoint is a paid mutator transaction binding the contract method 0x5b2388be. -// -// Solidity: function setCoordinatorEndpoint(string coordinatorEndpoint) returns() -func (_CoordinatorRegistry *CoordinatorRegistryTransactorSession) SetCoordinatorEndpoint(coordinatorEndpoint string) (*types.Transaction, error) { - return _CoordinatorRegistry.Contract.SetCoordinatorEndpoint(&_CoordinatorRegistry.TransactOpts, coordinatorEndpoint) -} - -// CoordinatorRegistryCoordinatorEndpointSetIterator is returned from FilterCoordinatorEndpointSet and is used to iterate over the raw logs and unpacked data for CoordinatorEndpointSet events raised by the CoordinatorRegistry contract. -type CoordinatorRegistryCoordinatorEndpointSetIterator struct { - Event *CoordinatorRegistryCoordinatorEndpointSet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *CoordinatorRegistryCoordinatorEndpointSetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(CoordinatorRegistryCoordinatorEndpointSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(CoordinatorRegistryCoordinatorEndpointSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *CoordinatorRegistryCoordinatorEndpointSetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *CoordinatorRegistryCoordinatorEndpointSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// CoordinatorRegistryCoordinatorEndpointSet represents a CoordinatorEndpointSet event raised by the CoordinatorRegistry contract. -type CoordinatorRegistryCoordinatorEndpointSet struct { - CoordinatorOperator common.Address - CoordinatorEndpoint string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterCoordinatorEndpointSet is a free log retrieval operation binding the contract event 0xd060052768902f3eecb84b8eae9d3a2608a1a9e60811a33968b46b8d552f266e. -// -// Solidity: event CoordinatorEndpointSet(address coordinatorOperator, string coordinatorEndpoint) -func (_CoordinatorRegistry *CoordinatorRegistryFilterer) FilterCoordinatorEndpointSet(opts *bind.FilterOpts) (*CoordinatorRegistryCoordinatorEndpointSetIterator, error) { - - logs, sub, err := _CoordinatorRegistry.contract.FilterLogs(opts, "CoordinatorEndpointSet") - if err != nil { - return nil, err - } - return &CoordinatorRegistryCoordinatorEndpointSetIterator{contract: _CoordinatorRegistry.contract, event: "CoordinatorEndpointSet", logs: logs, sub: sub}, nil -} - -// WatchCoordinatorEndpointSet is a free log subscription operation binding the contract event 0xd060052768902f3eecb84b8eae9d3a2608a1a9e60811a33968b46b8d552f266e. -// -// Solidity: event CoordinatorEndpointSet(address coordinatorOperator, string coordinatorEndpoint) -func (_CoordinatorRegistry *CoordinatorRegistryFilterer) WatchCoordinatorEndpointSet(opts *bind.WatchOpts, sink chan<- *CoordinatorRegistryCoordinatorEndpointSet) (event.Subscription, error) { - - logs, sub, err := _CoordinatorRegistry.contract.WatchLogs(opts, "CoordinatorEndpointSet") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(CoordinatorRegistryCoordinatorEndpointSet) - if err := _CoordinatorRegistry.contract.UnpackLog(event, "CoordinatorEndpointSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseCoordinatorEndpointSet is a log parse operation binding the contract event 0xd060052768902f3eecb84b8eae9d3a2608a1a9e60811a33968b46b8d552f266e. -// -// Solidity: event CoordinatorEndpointSet(address coordinatorOperator, string coordinatorEndpoint) -func (_CoordinatorRegistry *CoordinatorRegistryFilterer) ParseCoordinatorEndpointSet(log types.Log) (*CoordinatorRegistryCoordinatorEndpointSet, error) { - event := new(CoordinatorRegistryCoordinatorEndpointSet) - if err := _CoordinatorRegistry.contract.UnpackLog(event, "CoordinatorEndpointSet", log); err != nil { - return nil, err - } - return event, nil -} diff --git a/packages/mesh-browser-lite/src/types.ts b/packages/mesh-browser-lite/src/types.ts index d388b0d44..8f0610c80 100644 --- a/packages/mesh-browser-lite/src/types.ts +++ b/packages/mesh-browser-lite/src/types.ts @@ -197,8 +197,6 @@ export interface ContractAddresses { erc20Proxy: string; erc721Proxy: string; erc1155Proxy: string; - coordinator?: string; - coordinatorRegistry?: string; weth9?: string; zrxToken?: string; } @@ -629,7 +627,6 @@ export enum RejectedOrderKind { ZeroExValidation = 'ZEROEX_VALIDATION', MeshError = 'MESH_ERROR', MeshValidation = 'MESH_VALIDATION', - CoordinatorError = 'COORDINATOR_ERROR', } /** diff --git a/packages/mesh-browser/conversion-tests/conversion_test.ts b/packages/mesh-browser/conversion-tests/conversion_test.ts index ff28aa827..0f7f6faa1 100644 --- a/packages/mesh-browser/conversion-tests/conversion_test.ts +++ b/packages/mesh-browser/conversion-tests/conversion_test.ts @@ -1043,11 +1043,10 @@ function testValidationResults(validationResults: WrapperValidationResults[]): v '0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33', ); printer('rejected.kind', validationResults[3].rejected[0].kind === 'MESH_ERROR'); - printer('rejected.status.code', validationResults[3].rejected[0].status.code === 'CoordinatorEndpointNotFound'); + printer('rejected.status.code', validationResults[3].rejected[0].status.code === 'EthRPCRequestFailed'); printer( 'rejected.status.message', - validationResults[3].rejected[0].status.message === - 'corresponding coordinator endpoint not found in CoordinatorRegistry contract', + validationResults[3].rejected[0].status.message === 'network request to Ethereum RPC endpoint failed', ); } diff --git a/packages/mesh-browser/go/conversion-test/main.go b/packages/mesh-browser/go/conversion-test/main.go index 787177e36..7590bba40 100644 --- a/packages/mesh-browser/go/conversion-test/main.go +++ b/packages/mesh-browser/go/conversion-test/main.go @@ -647,7 +647,7 @@ func setGlobals() { Signature: common.FromHex("0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33"), }, Kind: ordervalidator.MeshError, - Status: ordervalidator.ROCoordinatorEndpointNotFound, + Status: ordervalidator.ROEthRPCRequestFailed, }, }, }, diff --git a/zeroex/ordervalidator/order_validator.go b/zeroex/ordervalidator/order_validator.go index e1a5b5b2e..1e3024b86 100644 --- a/zeroex/ordervalidator/order_validator.go +++ b/zeroex/ordervalidator/order_validator.go @@ -1,14 +1,11 @@ package ordervalidator import ( - "bytes" "context" "encoding/json" "errors" "fmt" - "io/ioutil" "math/big" - "net/http" "regexp" "sync" "time" @@ -97,18 +94,6 @@ var ( Code: "EthRPCRequestFailed", Message: "network request to Ethereum RPC endpoint failed", } - ROCoordinatorRequestFailed = RejectedOrderStatus{ - Code: "CoordinatorRequestFailed", - Message: "network request to coordinator server endpoint failed", - } - ROCoordinatorSoftCancelled = RejectedOrderStatus{ - Code: "CoordinatorSoftCancelled", - Message: "order was soft-cancelled via the coordinator server", - } - ROCoordinatorEndpointNotFound = RejectedOrderStatus{ - Code: "CoordinatorEndpointNotFound", - Message: "corresponding coordinator endpoint not found in CoordinatorRegistry contract", - } ROInvalidMakerAssetAmount = RejectedOrderStatus{ Code: "OrderHasInvalidMakerAssetAmount", Message: "order makerAssetAmount cannot be 0", @@ -215,7 +200,6 @@ const ( ZeroExValidation = RejectedOrderKind("ZEROEX_VALIDATION") MeshError = RejectedOrderKind("MESH_ERROR") MeshValidation = RejectedOrderKind("MESH_VALIDATION") - CoordinatorError = RejectedOrderKind("COORDINATOR_ERROR") ) // ValidationResults defines the validation results returned from BatchValidate @@ -232,7 +216,6 @@ type ValidationResults struct { type OrderValidator struct { maxRequestContentLength int devUtils *wrappers.DevUtilsCaller - coordinatorRegistry *wrappers.CoordinatorRegistryCaller assetDataDecoder *zeroex.AssetDataDecoder chainID int cachedFeeRecipientToEndpoint map[common.Address]string @@ -245,16 +228,11 @@ func New(contractCaller bind.ContractCaller, chainID int, maxRequestContentLengt if err != nil { return nil, err } - coordinatorRegistry, err := wrappers.NewCoordinatorRegistryCaller(contractAddresses.CoordinatorRegistry, contractCaller) - if err != nil { - return nil, err - } assetDataDecoder := zeroex.NewAssetDataDecoder() return &OrderValidator{ maxRequestContentLength: maxRequestContentLength, devUtils: devUtils, - coordinatorRegistry: coordinatorRegistry, assetDataDecoder: assetDataDecoder, chainID: chainID, cachedFeeRecipientToEndpoint: map[common.Address]string{}, @@ -269,354 +247,48 @@ func New(contractCaller bind.ContractCaller, chainID int, maxRequestContentLengt // retrieve up until the failure. // The `validationBlock` parameter lets the caller specify a specific block at which to validate // the orders. This can be set to the `latest` block or any other historical block. -func (o *OrderValidator) BatchValidate(ctx context.Context, rawSignedOrders []*zeroex.SignedOrder, areNewOrders bool, validationBlock *types.MiniHeader) *ValidationResults { - if len(rawSignedOrders) == 0 { +func (o *OrderValidator) BatchValidate(ctx context.Context, signedOrders []*zeroex.SignedOrder, areNewOrders bool, validationBlock *types.MiniHeader) *ValidationResults { + if len(signedOrders) == 0 { return &ValidationResults{} } - offchainValidSignedOrders, rejectedOrderInfos := o.BatchOffchainValidation(rawSignedOrders) + offchainValidSignedOrders, rejectedOrderInfos := o.BatchOffchainValidation(signedOrders) validationResults := &ValidationResults{ Accepted: []*AcceptedOrderInfo{}, Rejected: rejectedOrderInfos, } - // Validate Coordinator orders for soft-cancels - signedOrders, coordinatorRejectedOrderInfos := o.batchValidateSoftCancelled(ctx, offchainValidSignedOrders) - for _, rejectedOrderInfo := range coordinatorRejectedOrderInfos { - validationResults.Rejected = append(validationResults.Rejected, rejectedOrderInfo) - } - signedOrderChunks := [][]*zeroex.SignedOrder{} - chunkSizes := o.computeOptimalChunkSizes(signedOrders) + chunkSizes := o.computeOptimalChunkSizes(offchainValidSignedOrders) for _, chunkSize := range chunkSizes { - signedOrderChunks = append(signedOrderChunks, signedOrders[:chunkSize]) - signedOrders = signedOrders[chunkSize:] + signedOrderChunks = append(signedOrderChunks, offchainValidSignedOrders[:chunkSize]) + offchainValidSignedOrders = offchainValidSignedOrders[chunkSize:] } semaphoreChan := make(chan struct{}, concurrencyLimit) defer close(semaphoreChan) wg := &sync.WaitGroup{} - for i, signedOrders := range signedOrderChunks { + for _, signedOrders := range signedOrderChunks { wg.Add(1) - go func(signedOrders []*zeroex.SignedOrder, i int) { - trimmedOrders := []wrappers.LibOrderOrder{} - for _, signedOrder := range signedOrders { - trimmedOrders = append(trimmedOrders, signedOrder.Trim()) - } - signatures := [][]byte{} - for _, signedOrder := range signedOrders { - signatures = append(signatures, signedOrder.Signature) - } - + go func(signedOrders []*zeroex.SignedOrder) { defer wg.Done() - // Add one to the semaphore chan. If it already has concurrencyLimit values, - // the request blocks here until one frees up. - semaphoreChan <- struct{}{} - - // Attempt to make the eth_call request 4 times with an exponential back-off. - maxDuration := 4 * time.Second - b := &backoff.Backoff{ - Min: 250 * time.Millisecond, // First back-off length - Max: maxDuration, // Longest back-off length - Factor: 2, // Factor to multiple each successive back-off - } - - for { - opts := &bind.CallOpts{ - // HACK(albrow): From field should not be required for eth_call but - // including it here is a workaround for a bug in Ganache. Removing - // this line causes Ganache to crash. - From: constants.GanacheDummyERC721TokenAddress, - Pending: false, - Context: ctx, - } - opts.BlockNumber = validationBlock.Number - - results, err := o.devUtils.GetOrderRelevantStates(opts, trimmedOrders, signatures) - if err != nil { - log.WithFields(log.Fields{ - "error": err.Error(), - "attempt": b.Attempt(), - "numOrders": len(trimmedOrders), - }).Info("GetOrderRelevantStates request failed") - d := b.Duration() - if d == maxDuration { - <-semaphoreChan - var fields log.Fields - match, regexpErr := regexp.MatchString("abi: improperly formatted output", err.Error()) - if regexpErr != nil { - log.WithField("error", regexpErr).Error("Unexpectedly failed to test regexp on error") - } - if err.Error() == "VM execution error." || match { - fields = log.Fields{ - "error": err.Error(), - "numOrders": len(trimmedOrders), - "orders": trimmedOrders, - } - } else { - fields = log.Fields{ - "error": err.Error(), - "numOrders": len(trimmedOrders), - } - } - log.WithFields(fields).Warning("Gave up on GetOrderRelevantStates request after backoff limit reached") - for _, signedOrder := range signedOrders { - orderHash, err := signedOrder.ComputeOrderHash() - if err != nil { - log.WithField("error", err).Error("Unexpectedly failed to generate orderHash") - continue - } - validationResults.Rejected = append(validationResults.Rejected, &RejectedOrderInfo{ - OrderHash: orderHash, - SignedOrder: signedOrder, - Kind: MeshError, - Status: ROEthRPCRequestFailed, - }) - } - return // Give up after 4 attempts - } - time.Sleep(d) - continue - } - - for j, orderInfo := range results.OrdersInfo { - isValidSignature := results.IsValidSignature[j] - fillableTakerAssetAmount := results.FillableTakerAssetAmounts[j] - orderHash := common.Hash(orderInfo.OrderHash) - signedOrder := signedOrders[j] - orderStatus := zeroex.OrderStatus(orderInfo.OrderStatus) - if !isValidSignature { - orderStatus = zeroex.OSSignatureInvalid - } - switch orderStatus { - case zeroex.OSExpired, zeroex.OSFullyFilled, zeroex.OSCancelled, zeroex.OSSignatureInvalid: - var status RejectedOrderStatus - switch orderStatus { - case zeroex.OSExpired: - status = ROExpired - case zeroex.OSFullyFilled: - status = ROFullyFilled - case zeroex.OSCancelled: - status = ROCancelled - case zeroex.OSSignatureInvalid: - status = ROInvalidSignature - } - validationResults.Rejected = append(validationResults.Rejected, &RejectedOrderInfo{ - OrderHash: orderHash, - SignedOrder: signedOrder, - Kind: ZeroExValidation, - Status: status, - }) - continue - case zeroex.OSFillable: - remainingTakerAssetAmount := big.NewInt(0).Sub(signedOrder.TakerAssetAmount, orderInfo.OrderTakerAssetFilledAmount) - // If `fillableTakerAssetAmount` != `remainingTakerAssetAmount`, the order is partially fillable. We consider - // partially fillable orders as invalid - if fillableTakerAssetAmount.Cmp(remainingTakerAssetAmount) != 0 { - validationResults.Rejected = append(validationResults.Rejected, &RejectedOrderInfo{ - OrderHash: orderHash, - SignedOrder: signedOrder, - Kind: ZeroExValidation, - Status: ROUnfunded, - }) - } else { - validationResults.Accepted = append(validationResults.Accepted, &AcceptedOrderInfo{ - OrderHash: orderHash, - SignedOrder: signedOrder, - FillableTakerAssetAmount: fillableTakerAssetAmount, - IsNew: areNewOrders, - }) - } - continue - } - } - - <-semaphoreChan - return + select { + case <-ctx.Done(): + // Blocks until a slot opens up in the semaphore. We read off of the + // semaphore whenever onchain validation completes to allow another + // goroutine to begin processing. + case semaphoreChan <- struct{}{}: + defer func() { <-semaphoreChan }() + o.batchOnchainValidation(ctx, signedOrders, validationBlock, areNewOrders, validationResults) } - }(signedOrders, i) + }(signedOrders) } wg.Wait() return validationResults } -type softCancelResponse struct { - OrderHashes []common.Hash `json:"orderHashes"` -} - -// batchValidateSoftCancelled validates any order specifying the Coordinator contract as the `senderAddress` to ensure -// that it hasn't been cancelled off-chain (soft cancellation). It does this by looking up the Coordinator server endpoint -// given the `feeRecipientAddress` specified in the order, and then hitting that endpoint to query whether the orders have -// been soft cancelled. -func (o *OrderValidator) batchValidateSoftCancelled(ctx context.Context, signedOrders []*zeroex.SignedOrder) ([]*zeroex.SignedOrder, []*RejectedOrderInfo) { - rejectedOrderInfos := []*RejectedOrderInfo{} - validSignedOrders := []*zeroex.SignedOrder{} - - endpointToSignedOrders := map[string][]*zeroex.SignedOrder{} - for _, signedOrder := range signedOrders { - if signedOrder.SenderAddress != o.contractAddresses.Coordinator { - validSignedOrders = append(validSignedOrders, signedOrder) - continue - } - - orderHash, err := signedOrder.ComputeOrderHash() - if err != nil { - log.WithError(err).WithField("signedOrder", signedOrder).Error("Computing the orderHash failed unexpectedly") - } - endpoint, ok := o.cachedFeeRecipientToEndpoint[signedOrder.FeeRecipientAddress] - if !ok { - opts := &bind.CallOpts{ - Pending: false, - Context: ctx, - } - var err error - // Look-up the coordinator endpoint in the CoordinatorRegistry by the order's `feeRecipientAddress` - endpoint, err = o.coordinatorRegistry.GetCoordinatorEndpoint(opts, signedOrder.FeeRecipientAddress) - if err != nil { - log.WithFields(log.Fields{ - "error": err.Error(), - "feeRecipientAddress": signedOrder.FeeRecipientAddress, - }).Info("GetCoordinatorEndpoint request failed") - rejectedOrderInfos = append(rejectedOrderInfos, &RejectedOrderInfo{ - OrderHash: orderHash, - SignedOrder: signedOrder, - Kind: MeshError, - Status: ROEthRPCRequestFailed, - }) - continue - } - // CoordinatorRegistry lookup returns empty string if endpoint not found for the feeRecipientAddress - if endpoint == "" { - rejectedOrderInfos = append(rejectedOrderInfos, &RejectedOrderInfo{ - OrderHash: orderHash, - SignedOrder: signedOrder, - Kind: CoordinatorError, - Status: ROCoordinatorEndpointNotFound, - }) - continue - } - } - existingOrders, ok := endpointToSignedOrders[endpoint] - if !ok { - endpointToSignedOrders[endpoint] = []*zeroex.SignedOrder{signedOrder} - } else { - endpointToSignedOrders[endpoint] = append(existingOrders, signedOrder) - } - } - - for endpoint, signedOrders := range endpointToSignedOrders { - orderHashToSignedOrder := map[common.Hash]*zeroex.SignedOrder{} - orderHashes := []common.Hash{} - for _, signedOrder := range signedOrders { - orderHash, err := signedOrder.ComputeOrderHash() - if err != nil { - log.WithError(err).WithField("signedOrder", signedOrder).Error("Computing the orderHash failed unexpectedly") - } - orderHashToSignedOrder[orderHash] = signedOrder - orderHashes = append(orderHashes, orderHash) - } - payload := &bytes.Buffer{} - err := json.NewEncoder(payload).Encode(orderHashes) - if err != nil { - log.WithError(err).WithField("orderHashes", orderHashes).Error("Unable to marshal `orderHashes` into JSON") - } - // Check if the orders have been soft-cancelled by querying the Coordinator server - requestURL := fmt.Sprintf("%s/v1/soft_cancels?networkId=%d", endpoint, o.chainID) - resp, err := http.Post(requestURL, "application/json", payload) - if err != nil { - log.WithFields(map[string]interface{}{ - "endpoint": endpoint, - "requstURL": requestURL, - "payload": orderHashes, - }).Warn("failed to send request to Coordinator server") - for orderHash, signedOrder := range orderHashToSignedOrder { - rejectedOrderInfos = append(rejectedOrderInfos, &RejectedOrderInfo{ - OrderHash: orderHash, - SignedOrder: signedOrder, - Kind: MeshError, - Status: ROCoordinatorRequestFailed, - }) - } - continue - } - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - log.WithFields(map[string]interface{}{ - "endpoint": endpoint, - "statusCode": resp.StatusCode, - "requstURL": requestURL, - }).Warn("Failed to read body received from Coordinator server") - for orderHash, signedOrder := range orderHashToSignedOrder { - rejectedOrderInfos = append(rejectedOrderInfos, &RejectedOrderInfo{ - OrderHash: orderHash, - SignedOrder: signedOrder, - Kind: MeshError, - Status: ROCoordinatorRequestFailed, - }) - } - continue - } - if resp.StatusCode != 200 { - log.WithFields(map[string]interface{}{ - "endpoint": endpoint, - "statusCode": resp.StatusCode, - "requstURL": requestURL, - "body": string(body), - }).Warn("Got non-200 status code from Coordinator server") - for orderHash, signedOrder := range orderHashToSignedOrder { - rejectedOrderInfos = append(rejectedOrderInfos, &RejectedOrderInfo{ - OrderHash: orderHash, - SignedOrder: signedOrder, - Kind: MeshError, - Status: ROCoordinatorRequestFailed, - }) - } - continue - } - var response softCancelResponse - err = json.Unmarshal(body, &response) - if err != nil { - log.WithFields(map[string]interface{}{ - "endpoint": endpoint, - "statusCode": resp.StatusCode, - "requstURL": requestURL, - "body": string(body), - }).Warn("Unable to unmarshal body returned from Coordinator server") - for orderHash, signedOrder := range orderHashToSignedOrder { - rejectedOrderInfos = append(rejectedOrderInfos, &RejectedOrderInfo{ - OrderHash: orderHash, - SignedOrder: signedOrder, - Kind: MeshError, - Status: ROCoordinatorRequestFailed, - }) - } - continue - } - softCancelledOrderHashes := response.OrderHashes - softCancelledOrderHashMap := map[common.Hash]interface{}{} - for _, orderHash := range softCancelledOrderHashes { - softCancelledOrderHashMap[orderHash] = struct{}{} - signedOrder := orderHashToSignedOrder[orderHash] - rejectedOrderInfos = append(rejectedOrderInfos, &RejectedOrderInfo{ - OrderHash: orderHash, - SignedOrder: signedOrder, - Kind: MeshError, - Status: ROCoordinatorSoftCancelled, - }) - } - for orderHash, signedOrder := range orderHashToSignedOrder { - // If order hasn't been soft-cancelled - if _, ok := softCancelledOrderHashMap[orderHash]; !ok { - validSignedOrders = append(validSignedOrders, signedOrder) - } - } - } - return validSignedOrders, rejectedOrderInfos -} - // BatchOffchainValidation performs all off-chain validation checks on a batch of 0x orders. // These checks include: // - `MakerAssetAmount` and `TakerAssetAmount` cannot be 0 @@ -683,8 +355,10 @@ func (o *OrderValidator) BatchOffchainValidation(signedOrders []*zeroex.SignedOr }) continue } - - if len(signedOrder.MakerFeeAssetData) != 0 { + // If the MakerFee is zero, the fee asset data will not affect the + // validity of the signed order. + // https://github.com/0xProject/0x-monorepo/blob/development/contracts/exchange/contracts/src/MixinAssetProxyDispatcher.sol#L90 + if signedOrder.MakerFee.Cmp(big.NewInt(0)) == 1 && len(signedOrder.MakerFeeAssetData) != 0 { isMakerFeeAssetDataSupported := o.isSupportedAssetData(signedOrder.MakerFeeAssetData) if !isMakerFeeAssetDataSupported { rejectedOrderInfos = append(rejectedOrderInfos, &RejectedOrderInfo{ @@ -696,7 +370,10 @@ func (o *OrderValidator) BatchOffchainValidation(signedOrders []*zeroex.SignedOr continue } } - if len(signedOrder.TakerFeeAssetData) != 0 { + // If the TakerFee is zero, the fee asset data will not affect the + // validity of the signed order. + // https://github.com/0xProject/0x-monorepo/blob/development/contracts/exchange/contracts/src/MixinAssetProxyDispatcher.sol#L90 + if signedOrder.TakerFee.Cmp(big.NewInt(0)) == 1 && len(signedOrder.TakerFeeAssetData) != 0 { isTakerFeeAssetDataSupported := o.isSupportedAssetData(signedOrder.TakerFeeAssetData) if !isTakerFeeAssetDataSupported { rejectedOrderInfos = append(rejectedOrderInfos, &RejectedOrderInfo{ @@ -726,6 +403,146 @@ func (o *OrderValidator) BatchOffchainValidation(signedOrders []*zeroex.SignedOr return offchainValidSignedOrders, rejectedOrderInfos } +// batchOnchainValidation validates a list of signed orders using the deployed +// DevUtils contract. This validation performs signature validation, checks balances +// and allowances, and identifies other issues in asset data (for example, DevUtils +// will invalidate MultiAssetProxy orders that contain duplicate ERC721 asset data). +func (o *OrderValidator) batchOnchainValidation( + ctx context.Context, + signedOrders []*zeroex.SignedOrder, + validationBlock *types.MiniHeader, + areNewOrders bool, + validationResults *ValidationResults, +) { + trimmedOrders := []wrappers.LibOrderOrder{} + for _, signedOrder := range signedOrders { + trimmedOrders = append(trimmedOrders, signedOrder.Trim()) + } + signatures := [][]byte{} + for _, signedOrder := range signedOrders { + signatures = append(signatures, signedOrder.Signature) + } + + // Attempt to make the eth_call request 4 times with an exponential back-off. + maxDuration := 4 * time.Second + b := &backoff.Backoff{ + Min: 250 * time.Millisecond, // First back-off length + Max: maxDuration, // Longest back-off length + Factor: 2, // Factor to multiple each successive back-off + } + + for { + opts := &bind.CallOpts{ + // HACK(albrow): From field should not be required for eth_call but + // including it here is a workaround for a bug in Ganache. Removing + // this line causes Ganache to crash. + From: constants.GanacheDummyERC721TokenAddress, + Pending: false, + Context: ctx, + } + opts.BlockNumber = validationBlock.Number + + results, err := o.devUtils.GetOrderRelevantStates(opts, trimmedOrders, signatures) + if err != nil { + log.WithFields(log.Fields{ + "error": err.Error(), + "attempt": b.Attempt(), + "numOrders": len(trimmedOrders), + }).Info("GetOrderRelevantStates request failed") + d := b.Duration() + if d == maxDuration { + var fields log.Fields + match, regexpErr := regexp.MatchString("abi: improperly formatted output", err.Error()) + if regexpErr != nil { + log.WithField("error", regexpErr).Error("Unexpectedly failed to test regexp on error") + } + if err.Error() == "VM execution error." || match { + fields = log.Fields{ + "error": err.Error(), + "numOrders": len(trimmedOrders), + "orders": trimmedOrders, + } + } else { + fields = log.Fields{ + "error": err.Error(), + "numOrders": len(trimmedOrders), + } + } + log.WithFields(fields).Warning("Gave up on GetOrderRelevantStates request after backoff limit reached") + for _, signedOrder := range signedOrders { + orderHash, err := signedOrder.ComputeOrderHash() + if err != nil { + log.WithField("error", err).Error("Unexpectedly failed to generate orderHash") + continue + } + validationResults.Rejected = append(validationResults.Rejected, &RejectedOrderInfo{ + OrderHash: orderHash, + SignedOrder: signedOrder, + Kind: MeshError, + Status: ROEthRPCRequestFailed, + }) + } + return // Give up after 4 attempts + } + time.Sleep(d) + continue + } + + for j, orderInfo := range results.OrdersInfo { + isValidSignature := results.IsValidSignature[j] + fillableTakerAssetAmount := results.FillableTakerAssetAmounts[j] + orderHash := common.Hash(orderInfo.OrderHash) + signedOrder := signedOrders[j] + orderStatus := zeroex.OrderStatus(orderInfo.OrderStatus) + if !isValidSignature { + orderStatus = zeroex.OSSignatureInvalid + } + switch orderStatus { + case zeroex.OSExpired, zeroex.OSFullyFilled, zeroex.OSCancelled, zeroex.OSSignatureInvalid: + var status RejectedOrderStatus + switch orderStatus { + case zeroex.OSExpired: + status = ROExpired + case zeroex.OSFullyFilled: + status = ROFullyFilled + case zeroex.OSCancelled: + status = ROCancelled + case zeroex.OSSignatureInvalid: + status = ROInvalidSignature + } + validationResults.Rejected = append(validationResults.Rejected, &RejectedOrderInfo{ + OrderHash: orderHash, + SignedOrder: signedOrder, + Kind: ZeroExValidation, + Status: status, + }) + continue + case zeroex.OSFillable: + remainingTakerAssetAmount := big.NewInt(0).Sub(signedOrder.TakerAssetAmount, orderInfo.OrderTakerAssetFilledAmount) + // If `fillableTakerAssetAmount` != `remainingTakerAssetAmount`, the order is partially fillable. We consider + // partially fillable orders as invalid + if fillableTakerAssetAmount.Cmp(remainingTakerAssetAmount) != 0 { + validationResults.Rejected = append(validationResults.Rejected, &RejectedOrderInfo{ + OrderHash: orderHash, + SignedOrder: signedOrder, + Kind: ZeroExValidation, + Status: ROUnfunded, + }) + } else { + validationResults.Accepted = append(validationResults.Accepted, &AcceptedOrderInfo{ + OrderHash: orderHash, + SignedOrder: signedOrder, + FillableTakerAssetAmount: fillableTakerAssetAmount, + IsNew: areNewOrders, + }) + } + continue + } + } + return + } +} + func (o *OrderValidator) isSupportedAssetData(assetData []byte) bool { assetDataName, err := o.assetDataDecoder.GetName(assetData) if err != nil { diff --git a/zeroex/ordervalidator/order_validator_test.go b/zeroex/ordervalidator/order_validator_test.go index dcdbc3513..ea2bb93d1 100644 --- a/zeroex/ordervalidator/order_validator_test.go +++ b/zeroex/ordervalidator/order_validator_test.go @@ -10,8 +10,6 @@ import ( "flag" "fmt" "math/big" - "net/http" - "net/http/httptest" "strings" "testing" "time" @@ -20,16 +18,13 @@ import ( "github.com/0xProject/0x-mesh/ethereum" "github.com/0xProject/0x-mesh/ethereum/ethrpcclient" "github.com/0xProject/0x-mesh/ethereum/ratelimit" - "github.com/0xProject/0x-mesh/ethereum/signer" "github.com/0xProject/0x-mesh/ethereum/wrappers" "github.com/0xProject/0x-mesh/scenario" "github.com/0xProject/0x-mesh/scenario/orderopts" "github.com/0xProject/0x-mesh/zeroex" "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" ethrpc "github.com/ethereum/go-ethereum/rpc" @@ -193,6 +188,39 @@ func TestBatchValidateAValidOrder(t *testing.T) { assert.Equal(t, orderHash, validationResults.Accepted[0].OrderHash) } +func TestBatchOffchainValidateZeroFeeAmount(t *testing.T) { + if !serialTestsEnabled { + t.Skip("Serial tests (tests which cannot run in parallel) are disabled. You can enable them with the --serial flag") + } + + teardownSubTest := setupSubTest(t) + defer teardownSubTest(t) + makerFeeAssetData := common.Hex2Bytes("deadbeef") + signedTestOrder := scenario.NewSignedTestOrder(t, orderopts.MakerFeeAssetData(makerFeeAssetData)) + signedOrders := []*zeroex.SignedOrder{ + signedTestOrder, + } + + rateLimiter := ratelimit.NewUnlimited() + rpcClient, err := rpc.Dial(constants.GanacheEndpoint) + require.NoError(t, err) + ethRPCClient, err := ethrpcclient.New(rpcClient, defaultEthRPCTimeout, rateLimiter) + require.NoError(t, err) + + orderValidator, err := New(ethRPCClient, constants.TestChainID, constants.TestMaxContentLength, ganacheAddresses) + require.NoError(t, err) + + accepted, rejected := orderValidator.BatchOffchainValidation(signedOrders) + assert.Len(t, accepted, 1) + require.Len(t, rejected, 0) + signedTestOrder.ResetHash() + expectedOrderHash, err := signedTestOrder.ComputeOrderHash() + require.NoError(t, err) + actualOrderHash, err := accepted[0].ComputeOrderHash() + require.NoError(t, err) + assert.Equal(t, expectedOrderHash, actualOrderHash) +} + func TestBatchOffchainValidateUnsupportedStaticCall(t *testing.T) { if !serialTestsEnabled { t.Skip("Serial tests (tests which cannot run in parallel) are disabled. You can enable them with the --serial flag") @@ -202,7 +230,11 @@ func TestBatchOffchainValidateUnsupportedStaticCall(t *testing.T) { defer teardownSubTest(t) // NOTE(jalextowle): This asset data encodes a staticcall to a function called `unsupportedStaticCall` makerFeeAssetData := common.Hex2Bytes("c339d10a000000000000000000000000692a70d2e424a56d2c6c27aa97d1a86395877b3a0000000000000000000000000000000000000000000000000000000000000060c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47000000000000000000000000000000000000000000000000000000000000000048b24020700000000000000000000000000000000000000000000000000000000") - signedTestOrder := scenario.NewSignedTestOrder(t, orderopts.MakerFeeAssetData(makerFeeAssetData)) + signedTestOrder := scenario.NewSignedTestOrder( + t, + orderopts.MakerFeeAssetData(makerFeeAssetData), + orderopts.MakerFee(big.NewInt(1)), + ) signedOrders := []*zeroex.SignedOrder{ signedTestOrder, } @@ -322,90 +354,6 @@ func TestBatchValidateSignatureInvalid(t *testing.T) { assert.Equal(t, orderHash, validationResults.Rejected[0].OrderHash) } -func TestBatchValidateUnregisteredCoordinator(t *testing.T) { - // FeeRecipientAddress is an address for which there is no entry in the Coordinator registry - signedOrder := scenario.NewSignedTestOrder(t, orderopts.SenderAddress(ganacheAddresses.Coordinator), orderopts.FeeRecipientAddress(constants.GanacheAccount4)) - signedOrder.FeeRecipientAddress = constants.GanacheAccount4 - orderHash, err := signedOrder.ComputeOrderHash() - require.NoError(t, err) - signedOrders := []*zeroex.SignedOrder{ - signedOrder, - } - - orderValidator, err := New(ethRPCClient, constants.TestChainID, constants.TestMaxContentLength, ganacheAddresses) - require.NoError(t, err) - - ctx := context.Background() - latestBlock, err := ethRPCClient.HeaderByNumber(ctx, nil) - require.NoError(t, err) - validationResults := orderValidator.BatchValidate(ctx, signedOrders, areNewOrders, latestBlock) - assert.Len(t, validationResults.Accepted, 0) - require.Len(t, validationResults.Rejected, 1) - assert.Equal(t, ROCoordinatorEndpointNotFound, validationResults.Rejected[0].Status) - assert.Equal(t, orderHash, validationResults.Rejected[0].OrderHash) -} - -func TestBatchValidateCoordinatorSoftCancels(t *testing.T) { - if !serialTestsEnabled { - t.Skip("Serial tests (tests which cannot run in parallel) are disabled. You can enable them with the --serial flag") - } - - teardownSubTest := setupSubTest(t) - defer teardownSubTest(t) - - signedOrder := scenario.NewSignedTestOrder(t, - orderopts.SenderAddress(ganacheAddresses.Coordinator), - orderopts.SetupMakerState(true), - orderopts.FeeRecipientAddress(constants.GanacheAccount3), - ) - orderHash, err := signedOrder.ComputeOrderHash() - require.NoError(t, err) - signedOrders := []*zeroex.SignedOrder{ - signedOrder, - } - - orderValidator, err := New(ethRPCClient, constants.TestChainID, constants.TestMaxContentLength, ganacheAddresses) - require.NoError(t, err) - - // generate a test server so we can capture and inspect the request - testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { - res.WriteHeader(200) - _, err := res.Write([]byte(fmt.Sprintf(`{"orderHashes": ["%s"]}`, orderHash.Hex()))) - require.NoError(t, err) - })) - defer testServer.Close() - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - opts := &bind.TransactOpts{ - From: signedOrder.FeeRecipientAddress, - Context: ctx, - Signer: func(s types.Signer, address common.Address, tx *types.Transaction) (*types.Transaction, error) { - testSigner := signer.NewTestSigner() - signature, err := testSigner.(*signer.TestSigner).SignTx(s.Hash(tx).Bytes(), address) - if err != nil { - return nil, err - } - return tx.WithSignature(s, signature) - }, - } - - coordinatorRegistryAddress := ganacheAddresses.CoordinatorRegistry - coordinatorRegistry, err := wrappers.NewCoordinatorRegistry(coordinatorRegistryAddress, ethClient) - require.NoError(t, err) - _, err = coordinatorRegistry.SetCoordinatorEndpoint(opts, testServer.URL) - require.NoError(t, err) - - ctx = context.Background() - latestBlock, err := ethRPCClient.HeaderByNumber(ctx, nil) - require.NoError(t, err) - validationResults := orderValidator.BatchValidate(ctx, signedOrders, areNewOrders, latestBlock) - assert.Len(t, validationResults.Accepted, 0) - require.Len(t, validationResults.Rejected, 1) - assert.Equal(t, ROCoordinatorSoftCancelled, validationResults.Rejected[0].Status) - assert.Equal(t, orderHash, validationResults.Rejected[0].OrderHash) -} - const singleOrderPayloadSize = 2236 func TestComputeOptimalChunkSizesMaxContentLengthTooLow(t *testing.T) { diff --git a/zeroex/orderwatch/order_watcher.go b/zeroex/orderwatch/order_watcher.go index 74c9bb2c7..696a0d145 100644 --- a/zeroex/orderwatch/order_watcher.go +++ b/zeroex/orderwatch/order_watcher.go @@ -1660,9 +1660,7 @@ func (w *Watcher) meshSpecificOrderValidation(orders []*zeroex.SignedOrder, chai // Note(albrow): Orders with a sender address can be canceled or invalidated // off-chain which is difficult to support since we need to prune // canceled/invalidated orders from the database. We can special-case some - // sender addresses over time. (For example we already have support for - // validating Coordinator orders. What we're missing is a way to effeciently - // remove orders that are soft-canceled via the Coordinator API). + // sender addresses over time. if order.SenderAddress != constants.NullAddress { results.Rejected = append(results.Rejected, &ordervalidator.RejectedOrderInfo{ OrderHash: orderHash,