From 45c44b033ad8293420bdf4a6fc80ea2934f7c9a4 Mon Sep 17 00:00:00 2001 From: Brian Stafford Date: Wed, 19 Jul 2023 13:53:36 -0500 Subject: [PATCH] update server tests and enable per-asset protocol reversion --- .gitignore | 1 + client/asset/eth/cmd/getgas/main.go | 4 +- client/asset/eth/contractor.go | 36 +- client/asset/eth/eth.go | 99 ++-- client/asset/eth/eth_test.go | 57 +- client/asset/eth/nodeclient.go | 6 +- client/asset/eth/nodeclient_harness_test.go | 154 +++--- dex/networks/erc20/contracts/ERC20SwapV1.sol | 10 +- .../erc20/contracts/v1/BinRuntimeV1.go | 2 +- dex/networks/erc20/contracts/v1/contract.go | 76 +-- dex/networks/eth/contracts/ETHSwapV1.sol | 16 +- dex/networks/eth/contracts/v1/BinRuntimeV1.go | 2 +- dex/networks/eth/contracts/v1/contract.go | 78 +-- dex/networks/eth/params.go | 122 +++-- dex/networks/eth/tokens.go | 93 ++-- dex/networks/eth/txdata.go | 6 +- dex/networks/polygon/params.go | 14 +- dex/testing/eth/harness.sh | 4 +- server/asset/eth/coiner.go | 244 ++++++--- server/asset/eth/coiner_test.go | 512 ++++++++++------- server/asset/eth/eth.go | 220 ++++---- server/asset/eth/eth_test.go | 515 ++++++++++-------- server/asset/eth/rpcclient.go | 93 +++- server/asset/eth/rpcclient_harness_test.go | 12 +- server/asset/eth/tokener.go | 199 ++++++- server/asset/polygon/polygon.go | 45 +- server/cmd/dcrdex/evm-protocol-overrides.json | 8 + 27 files changed, 1577 insertions(+), 1051 deletions(-) create mode 100644 server/cmd/dcrdex/evm-protocol-overrides.json diff --git a/.gitignore b/.gitignore index a518a7a770..eb48593d34 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,4 @@ tatanka/cmd/demo/demo server/cmd/validatemarkets client/cmd/translationsreport/translationsreport client/cmd/translationsreport/worksheets +server/cmd/dcrdex/evm-protocol-overrides.json diff --git a/client/asset/eth/cmd/getgas/main.go b/client/asset/eth/cmd/getgas/main.go index d02f3bb64e..a8667c4d80 100644 --- a/client/asset/eth/cmd/getgas/main.go +++ b/client/asset/eth/cmd/getgas/main.go @@ -48,8 +48,8 @@ func mainErr() error { flag.BoolVar(&useMainnet, "mainnet", false, "use mainnet") flag.BoolVar(&useTestnet, "testnet", false, "use testnet") flag.BoolVar(&useSimnet, "simnet", false, "use simnet") - flag.BoolVar(&trace, "trace", false, "use simnet") - flag.BoolVar(&debug, "debug", false, "use simnet") + flag.BoolVar(&trace, "trace", false, "use trace logging") + flag.BoolVar(&debug, "debug", false, "use debug logging") flag.IntVar(&maxSwaps, "n", 5, "max number of swaps per transaction. minimum is 2. test will run from 2 swap up to n swaps.") flag.StringVar(&chain, "chain", "eth", "symbol of the base chain") flag.StringVar(&token, "token", "", "symbol of the token. if token is not specified, will check gas for base chain") diff --git a/client/asset/eth/contractor.go b/client/asset/eth/contractor.go index e8f6a1b9fd..e4ee5e796c 100644 --- a/client/asset/eth/contractor.go +++ b/client/asset/eth/contractor.go @@ -223,9 +223,9 @@ func (c *contractorV0) vector(ctx context.Context, locator []byte) (*dexeth.Swap vector := &dexeth.SwapVector{ From: swap.Participant, To: swap.Initiator, - Value: dexeth.WeiToGwei(swap.Value), + Value: swap.Value, SecretHash: secretHash, - LockTime: uint64(swap.LockTime.UnixMilli()), + LockTime: uint64(swap.LockTime.Unix()), } return vector, nil } @@ -245,9 +245,9 @@ func (c *contractorV0) statusAndVector(ctx context.Context, locator []byte) (*de vector := &dexeth.SwapVector{ From: swap.Participant, To: swap.Initiator, - Value: dexeth.WeiToGwei(swap.Value), + Value: swap.Value, SecretHash: secretHash, - LockTime: uint64(swap.LockTime.UnixMilli()), + LockTime: uint64(swap.LockTime.Unix()), } status := &dexeth.SwapStatus{ Step: swap.State, @@ -452,7 +452,7 @@ func (c *erc20Contractor) balance(ctx context.Context) (*big.Int, error) { // allowance exposes the read-only allowance method of the erc20 token contract. func (c *erc20Contractor) allowance(ctx context.Context) (*big.Int, error) { callOpts := &bind.CallOpts{ - Pending: true, + // Pending: true, // Seeing errors on even simnet that say "backend does not support pending state" From: c.acct, Context: ctx, } @@ -585,8 +585,7 @@ func (c *tokenContractorV0) tokenAddress() common.Address { type contractorV1 struct { contractV1 - abi *abi.ABI - // net dex.Network + abi *abi.ABI contractAddr common.Address acctAddr common.Address cb bind.ContractBackend @@ -598,19 +597,18 @@ type contractorV1 struct { var _ contractor = (*contractorV1)(nil) func newV1Contractor(net dex.Network, contractAddr, acctAddr common.Address, cb bind.ContractBackend) (contractor, error) { - c, err := swapv1.NewETHSwap(contractAddr, cb) if err != nil { return nil, err } return &contractorV1{ - contractV1: c, - abi: dexeth.ABIs[1], - // net: net, + contractV1: c, + abi: dexeth.ABIs[1], contractAddr: contractAddr, acctAddr: acctAddr, cb: cb, atomize: dexeth.WeiToGwei, + evmify: dexeth.GweiToWei, }, nil } @@ -672,7 +670,7 @@ func (c *contractorV1) initiate(txOpts *bind.TransactOpts, contracts []*asset.Co v := &dexeth.SwapVector{ From: c.acctAddr, To: common.HexToAddress(ac.Address), - Value: ac.Value, + Value: c.evmify(ac.Value), LockTime: ac.LockTime, } copy(v.SecretHash[:], ac.SecretHash) @@ -698,7 +696,7 @@ func (c *contractorV1) redeem(txOpts *bind.TransactOpts, redeems []*asset.Redemp // Not checking version from DecodeLocator because it was already // audited and incorrect version locator would err below anyway. - _, locator, err := dexeth.DecodeLocator(r.Spends.Contract) + _, locator, err := dexeth.DecodeContractData(r.Spends.Contract) if err != nil { return nil, fmt.Errorf("error parsing locator redeem: %w", err) } @@ -732,7 +730,7 @@ func (c *contractorV1) estimateInitGas(ctx context.Context, n int) (uint64, erro SecretHash: secretHash, Initiator: c.acctAddr, Participant: common.BytesToAddress(encode.RandomBytes(20)), - Value: 1, + Value: big.NewInt(dexeth.GweiFactor), }) } @@ -807,23 +805,23 @@ func (c *contractorV1) isRefundable(locator []byte) (bool, error) { func (c *contractorV1) incomingValue(ctx context.Context, tx *types.Transaction) (uint64, error) { if redeems, err := dexeth.ParseRedeemDataV1(tx.Data()); err == nil { - var redeemed uint64 + var redeemed *big.Int for _, r := range redeems { - redeemed += r.Contract.Value + redeemed.Add(redeemed, r.Contract.Value) } - return redeemed, nil + return c.atomize(redeemed), nil } refund, err := dexeth.ParseRefundDataV1(tx.Data()) if err != nil { return 0, nil } - return refund.Value, nil + return c.atomize(refund.Value), nil } func (c *contractorV1) outgoingValue(tx *types.Transaction) (swapped uint64) { if inits, err := dexeth.ParseInitiateDataV1(tx.Data()); err == nil { for _, init := range inits { - swapped += init.Value + swapped += c.atomize(init.Value) } } return diff --git a/client/asset/eth/eth.go b/client/asset/eth/eth.go index 11338abbae..efb0ad3dc5 100644 --- a/client/asset/eth/eth.go +++ b/client/asset/eth/eth.go @@ -104,9 +104,6 @@ const ( // TODO: Find a way to ask the host about their config set max fee and // gas values. maxTxFeeGwei = 1_000_000_000 - - contractVersionERC20 = ^uint32(0) - contractVersionUnknown = contractVersionERC20 - 1 ) var ( @@ -149,7 +146,7 @@ var ( // exposed though any Driver methods or assets/driver functions. Use the // parent wallet's WalletInfo via (*Driver).Info if you need a token's // supported versions before a wallet is available. - SupportedVersions: []uint32{0}, + SupportedVersions: []uint32{0, 1}, UnitInfo: dexeth.UnitInfo, AvailableWallets: []*asset.WalletDefinition{ // { @@ -557,14 +554,7 @@ func privKeyFromSeed(seed []byte) (pk []byte, zero func(), err error) { // contractVersion converts a server version to a contract version. It applies // to both tokens and eth right now, but that may not always be the case. func contractVersion(serverVer uint32) uint32 { - switch serverVer { - case 0: - return 0 - case 1: - return 1 - default: - return contractVersionUnknown - } + return dexeth.ProtocolVersion(serverVer).ContractVersion() } func CreateEVMWallet(chainID int64, createWalletParams *asset.CreateWalletParams, compat *CompatibilityData, skipConnect bool) error { @@ -1334,9 +1324,10 @@ func (w *baseWallet) MaxFundingFees(_ uint32, _ uint64, _ map[string]string) uin // SingleLotSwapRefundFees returns the fees for a swap transaction for a single lot. func (w *assetWallet) SingleLotSwapRefundFees(serverVer uint32, feeSuggestion uint64, _ bool) (swapFees uint64, refundFees uint64, err error) { - g := w.gases(contractVersion(serverVer)) + contractVer := contractVersion(serverVer) + g := w.gases(contractVer) if g == nil { - return 0, 0, fmt.Errorf("no gases known for %d version %d", w.assetID, serverVer) + return 0, 0, fmt.Errorf("no gases known for %d, contract version %d", w.assetID, contractVer) } return g.Swap * feeSuggestion, g.Refund * feeSuggestion, nil } @@ -1998,7 +1989,7 @@ func (w *ETHWallet) Swap(swaps *asset.Swaps) ([]asset.Receipt, asset.Coin, uint6 expiration: time.Unix(int64(swap.LockTime), 0), value: swap.Value, txHash: txHash, - locator: acToLocator(contractVer, swap, w.addr), + locator: acToLocator(contractVer, swap, dexeth.GweiToWei(swap.Value), w.addr), contractVer: contractVer, contractAddr: w.versionedContracts[contractVer].String(), }) @@ -2016,7 +2007,7 @@ func (w *ETHWallet) Swap(swaps *asset.Swaps) ([]asset.Receipt, asset.Coin, uint6 } // acToLocator converts the asset.Contract to a version-specific locator. -func acToLocator(contractVer uint32, swap *asset.Contract, from common.Address) []byte { +func acToLocator(contractVer uint32, swap *asset.Contract, evmValue *big.Int, from common.Address) []byte { switch contractVer { case 0: return swap.SecretHash @@ -2026,7 +2017,7 @@ func acToLocator(contractVer uint32, swap *asset.Contract, from common.Address) return (&dexeth.SwapVector{ From: from, To: common.HexToAddress(swap.Address), - Value: swap.Value, + Value: evmValue, SecretHash: secretHash, LockTime: swap.LockTime, }).Locator() @@ -2108,7 +2099,7 @@ func (w *TokenWallet) Swap(swaps *asset.Swaps) ([]asset.Receipt, asset.Coin, uin expiration: time.Unix(int64(swap.LockTime), 0), value: swap.Value, txHash: txHash, - locator: acToLocator(contractVer, swap, w.addr), + locator: acToLocator(contractVer, swap, w.evmify(swap.Value), w.addr), contractVer: contractVer, contractAddr: contractAddr, }) @@ -2167,7 +2158,7 @@ func (w *assetWallet) Redeem(form *asset.RedeemForm, feeWallet *assetWallet, non // from redemption.Spends.Contract. Even for scriptable UTXO assets, the // redeem script in this Contract field is redundant with the SecretHash // field as ExtractSwapDetails can be applied to extract the hash. - ver, locator, err := dexeth.DecodeLocator(redemption.Spends.Contract) + ver, locator, err := dexeth.DecodeContractData(redemption.Spends.Contract) if err != nil { return fail(fmt.Errorf("Redeem: invalid versioned swap contract data: %w", err)) } @@ -2322,7 +2313,7 @@ func recoverPubkey(msgHash, sig []byte) ([]byte, error) { // tokenBalance checks the token balance of the account handled by the wallet. func (w *assetWallet) tokenBalance() (bal *big.Int, err error) { // We don't care about the version. - return bal, w.withTokenContractor(w.assetID, contractVersionERC20, func(c tokenContractor) error { + return bal, w.withTokenContractor(w.assetID, dexeth.ContractVersionERC20, func(c tokenContractor) error { bal, err = c.balance(w.ctx) return err }) @@ -2331,7 +2322,7 @@ func (w *assetWallet) tokenBalance() (bal *big.Int, err error) { // tokenAllowance checks the amount of tokens that the swap contract is approved // to spend on behalf of the account handled by the wallet. func (w *assetWallet) tokenAllowance() (allowance *big.Int, err error) { - return allowance, w.withTokenContractor(w.assetID, contractVersionERC20, func(c tokenContractor) error { + return allowance, w.withTokenContractor(w.assetID, dexeth.ContractVersionERC20, func(c tokenContractor) error { allowance, err = c.allowance(w.ctx) return err }) @@ -2701,7 +2692,7 @@ func (w *assetWallet) AuditContract(coinID, contract, serializedTx dex.Bytes, re return nil, fmt.Errorf("AuditContract: coin id != txHash - coin id: %x, txHash: %s", coinID, tx.Hash()) } - version, locator, err := dexeth.DecodeLocator(contract) + version, locator, err := dexeth.DecodeContractData(contract) if err != nil { return nil, fmt.Errorf("AuditContract: failed to decode contract data: %w", err) } @@ -2743,21 +2734,10 @@ func (w *assetWallet) AuditContract(coinID, contract, serializedTx dex.Bytes, re if !ok { return nil, errors.New("AuditContract: tx does not initiate secret hash") } - // Check vector equivalence. Secret hash equivalence is implied by the - // vectors presence in the map returned from ParseInitiateData. - if vec.Value != txVec.Value { - return nil, errors.New("tx data value doesn't match reported locator data") - } - if vec.To != txVec.To { - return nil, errors.New("tx to address doesn't match reported locator data") + if !dexeth.CompareVectors(vec, txVec) { + return nil, fmt.Errorf("tx vector doesn't match expectation. %+v != %+v", txVec, vec) } - if vec.From != txVec.From { - return nil, errors.New("tx from address doesn't match reported locator data") - } - if vec.LockTime != txVec.LockTime { - return nil, errors.New("tx lock time doesn't match reported locator data") - } - val = vec.Value + val = w.atomize(vec.Value) participant = vec.To.String() lockTime = time.Unix(int64(vec.LockTime), 0) secretHashB = vec.SecretHash[:] @@ -2804,7 +2784,7 @@ func (w *assetWallet) LockTimeExpired(ctx context.Context, lockTime time.Time) ( // ContractLockTimeExpired returns true if the specified contract's locktime has // expired, making it possible to issue a Refund. func (w *assetWallet) ContractLockTimeExpired(ctx context.Context, contract dex.Bytes) (bool, time.Time, error) { - contractVer, locator, err := dexeth.DecodeLocator(contract) + contractVer, locator, err := dexeth.DecodeContractData(contract) if err != nil { return false, time.Time{}, err } @@ -2871,7 +2851,7 @@ func (w *assetWallet) FindRedemption(ctx context.Context, _, contract dex.Bytes) // contract, so we are basically doing the next best thing here. const coinIDTmpl = coinIDTakerFoundMakerRedemption + "%s" - contractVer, locator, err := dexeth.DecodeLocator(contract) + contractVer, locator, err := dexeth.DecodeContractData(contract) if err != nil { return nil, nil, err } @@ -2950,7 +2930,7 @@ func (w *assetWallet) findSecret(locator []byte, contractVer uint32) ([]byte, st // Refund refunds a contract. This can only be used after the time lock has // expired. func (w *assetWallet) Refund(_, contract dex.Bytes, feeRate uint64) (dex.Bytes, error) { - contractVer, locator, err := dexeth.DecodeLocator(contract) + contractVer, locator, err := dexeth.DecodeContractData(contract) if err != nil { return nil, fmt.Errorf("Refund: failed to decode contract: %w", err) } @@ -2994,7 +2974,7 @@ func (w *assetWallet) Refund(_, contract dex.Bytes, feeRate uint64) (dex.Bytes, } txHash := tx.Hash() - w.addToTxHistory(tx.Nonce(), vector.Value, fees, w.assetID, txHash, asset.Refund, nil) + w.addToTxHistory(tx.Nonce(), w.atomize(vector.Value), fees, w.assetID, txHash, asset.Refund, nil) return txHash[:], nil } @@ -3048,7 +3028,7 @@ func (w *ETHWallet) EstimateRegistrationTxFee(feeRate uint64) uint64 { // EstimateRegistrationTxFee returns an estimate for the tx fee needed to // pay the registration fee using the provided feeRate. func (w *TokenWallet) EstimateRegistrationTxFee(feeRate uint64) uint64 { - g := w.gases(contractVersionERC20) + g := w.gases(dexeth.ContractVersionERC20) if g == nil { w.log.Errorf("no gas table") return math.MaxUint64 @@ -3123,7 +3103,7 @@ func (w *TokenWallet) canSend(value uint64, verifyBalance, isPreEstimate bool) ( return 0, nil, fmt.Errorf("error getting max fee rate: %w", err) } - g := w.gases(contractVersionERC20) + g := w.gases(dexeth.ContractVersionERC20) if g == nil { return 0, nil, fmt.Errorf("gas table not found") } @@ -3215,7 +3195,7 @@ func (w *ETHWallet) RestorationInfo(seed []byte) ([]*asset.WalletRestoration, er // SwapConfirmations gets the number of confirmations and the spend status // for the specified swap. func (w *assetWallet) SwapConfirmations(ctx context.Context, coinID dex.Bytes, contract dex.Bytes, _ time.Time) (confs uint32, spent bool, err error) { - contractVer, secretHash, err := dexeth.DecodeLocator(contract) + contractVer, secretHash, err := dexeth.DecodeContractData(contract) if err != nil { return 0, false, err } @@ -3405,7 +3385,7 @@ func (eth *assetWallet) DynamicRedemptionFeesPaid(ctx context.Context, coinID, c // secret hashes. func (eth *baseWallet) swapOrRedemptionFeesPaid(ctx context.Context, coinID, contractData dex.Bytes, isInit bool) (fee uint64, secretHashes [][]byte, err error) { - contractVer, locator, err := dexeth.DecodeLocator(contractData) + contractVer, locator, err := dexeth.DecodeContractData(contractData) if err != nil { return 0, nil, err } @@ -3836,7 +3816,7 @@ func (w *assetWallet) resubmitRedemption(tx *types.Transaction, contractVer uint Expiration: time.Unix(int64(vec.LockTime), 0), Coin: &coin{ // id: txHash, // Just no way. - value: vec.Value, + value: w.atomize(vec.Value), }, Contract: dexeth.EncodeContractData(contractVer, locator), SecretHash: vec.SecretHash[:], @@ -4022,7 +4002,7 @@ func (w *assetWallet) checkUnconfirmedRedemption(locator []byte, contractVer uin // entire redemption batch, a new transaction containing only the swap we are // searching for will be created. func (w *assetWallet) confirmRedemptionWithoutMonitoredTx(txHash common.Hash, redemption *asset.Redemption, feeWallet *assetWallet) (*asset.ConfirmRedemptionStatus, error) { - contractVer, locator, err := dexeth.DecodeLocator(redemption.Spends.Contract) + contractVer, locator, err := dexeth.DecodeContractData(redemption.Spends.Contract) if err != nil { return nil, fmt.Errorf("failed to decode contract data: %w", err) } @@ -4115,7 +4095,7 @@ func (w *assetWallet) confirmRedemption(coinID dex.Bytes, redemption *asset.Rede txHash = monitoredTxHash } - contractVer, locator, err := dexeth.DecodeLocator(redemption.Spends.Contract) + contractVer, locator, err := dexeth.DecodeContractData(redemption.Spends.Contract) if err != nil { return nil, fmt.Errorf("failed to decode contract data: %w", err) } @@ -4515,7 +4495,7 @@ func (w *ETHWallet) sendToAddr(addr common.Address, amt uint64, maxFeeRate *big. func (w *TokenWallet) sendToAddr(addr common.Address, amt uint64, maxFeeRate *big.Int) (tx *types.Transaction, err error) { w.baseWallet.nonceSendMtx.Lock() defer w.baseWallet.nonceSendMtx.Unlock() - g := w.gases(contractVersionERC20) + g := w.gases(dexeth.ContractVersionERC20) if g == nil { return nil, fmt.Errorf("no gas table") } @@ -4524,7 +4504,7 @@ func (w *TokenWallet) sendToAddr(addr common.Address, amt uint64, maxFeeRate *bi if err != nil { return nil, err } - return tx, w.withTokenContractor(w.assetID, contractVersionERC20, func(c tokenContractor) error { + return tx, w.withTokenContractor(w.assetID, dexeth.ContractVersionERC20, func(c tokenContractor) error { tx, err = c.transfer(txOpts, addr, w.evmify(amt)) if err != nil { c.voidUnusedNonce() @@ -4647,7 +4627,7 @@ func (w *assetWallet) loadContractors() error { // withContractor runs the provided function with the versioned contractor. func (w *assetWallet) withContractor(contractVer uint32, f func(contractor) error) error { - if contractVer == contractVersionERC20 { + if contractVer == dexeth.ContractVersionERC20 { // For ERC02 methods, use the most recent contractor version. var bestVer uint32 var bestContractor contractor @@ -4680,7 +4660,7 @@ func (w *assetWallet) withTokenContractor(assetID, ver uint32, f func(tokenContr // estimateApproveGas estimates the gas required for a transaction approving a // spender for an ERC20 contract. func (w *assetWallet) estimateApproveGas(newGas *big.Int) (gas uint64, err error) { - return gas, w.withTokenContractor(w.assetID, contractVersionERC20, func(c tokenContractor) error { + return gas, w.withTokenContractor(w.assetID, dexeth.ContractVersionERC20, func(c tokenContractor) error { gas, err = c.estimateApproveGas(w.ctx, newGas) return err }) @@ -4688,8 +4668,9 @@ func (w *assetWallet) estimateApproveGas(newGas *big.Int) (gas uint64, err error // estimateTransferGas estimates the gas needed for a token transfer call to an // ERC20 contract. +// TODO: Delete this and contractor methods. Unused. func (w *assetWallet) estimateTransferGas(val uint64) (gas uint64, err error) { - return gas, w.withTokenContractor(w.assetID, contractVersionERC20, func(c tokenContractor) error { + return gas, w.withTokenContractor(w.assetID, dexeth.ContractVersionERC20, func(c tokenContractor) error { gas, err = c.estimateTransferGas(w.ctx, w.evmify(val)) return err }) @@ -5658,8 +5639,9 @@ func (getGas) Estimate(ctx context.Context, net dex.Network, assetID, contractVe var approvalClient *multiRPCClient var approvalContractor tokenContractor + evmify := dexeth.GweiToWei if isToken { - + evmify = wParams.Token.AtomicToEVM atomicBal := wParams.Token.EVMToAtomic(tokenBal) convUnit := ui.Conventional.Unit @@ -5701,7 +5683,7 @@ func (getGas) Estimate(ctx context.Context, net dex.Network, assetID, contractVe } log.Debugf("Getting gas estimates") - return getGasEstimates(ctx, cl, approvalClient, c, approvalContractor, maxSwaps, contractVer, wParams.Gas, log) + return getGasEstimates(ctx, cl, approvalClient, c, approvalContractor, maxSwaps, contractVer, wParams.Gas, evmify, log) } // getGasEstimate is used to get a gas table for an asset's contract(s). The @@ -5716,7 +5698,7 @@ func (getGas) Estimate(ctx context.Context, net dex.Network, assetID, contractVe // gas estimate. These are only needed when the asset is a token. For eth, they // can be nil. func getGasEstimates(ctx context.Context, cl, acl ethFetcher, c contractor, ac tokenContractor, - maxSwaps int, contractVer uint32, g *dexeth.Gases, log dex.Logger) (err error) { + maxSwaps int, contractVer uint32, g *dexeth.Gases, evmify func(v uint64) *big.Int, log dex.Logger) (err error) { tc, isToken := c.(tokenContractor) @@ -5852,6 +5834,7 @@ func getGasEstimates(ctx context.Context, cl, acl ethFetcher, c contractor, ac t stats.transfers = append(stats.transfers, receipt.GasUsed) } + var v uint64 = 1 for n := 1; n <= maxSwaps; n++ { contracts := make([]*asset.Contract, 0, n) secrets := make([][32]byte, 0, n) @@ -5863,7 +5846,7 @@ func getGasEstimates(ctx context.Context, cl, acl ethFetcher, c contractor, ac t secretHash := sha256.Sum256(secretB) contracts = append(contracts, &asset.Contract{ Address: cl.address().String(), // trading with self - Value: 1, + Value: v, SecretHash: secretHash[:], LockTime: uint64(lockTime.Unix()), }) @@ -5899,7 +5882,7 @@ func getGasEstimates(ctx context.Context, cl, acl ethFetcher, c contractor, ac t stats.swaps = append(stats.swaps, receipt.GasUsed) // Estimate a refund - refundGas, err := c.estimateRefundGas(ctx, acToLocator(contractVer, contracts[0], cl.address())) + refundGas, err := c.estimateRefundGas(ctx, acToLocator(contractVer, contracts[0], evmify(v), cl.address())) if err != nil { return fmt.Errorf("error estimate refund gas: %w", err) } @@ -5912,7 +5895,7 @@ func getGasEstimates(ctx context.Context, cl, acl ethFetcher, c contractor, ac t Spends: &asset.AuditInfo{ Recipient: cl.address().String(), Expiration: lockTime, - Contract: dexeth.EncodeContractData(contractVer, acToLocator(contractVer, contract, cl.address())), + Contract: dexeth.EncodeContractData(contractVer, acToLocator(contractVer, contract, evmify(v), cl.address())), SecretHash: contract.SecretHash, }, Secret: secrets[i][:], diff --git a/client/asset/eth/eth_test.go b/client/asset/eth/eth_test.go index 8f40932df1..a2b400c7be 100644 --- a/client/asset/eth/eth_test.go +++ b/client/asset/eth/eth_test.go @@ -379,7 +379,7 @@ func (c *tContractor) vector(ctx context.Context, locator []byte) (*dexeth.SwapV v := &dexeth.SwapVector{ From: swap.Participant, To: swap.Initiator, - Value: dexeth.WeiToGwei(swap.Value), + Value: swap.Value, SecretHash: secretHash, LockTime: uint64(swap.LockTime.Unix()), } @@ -401,7 +401,7 @@ func (c *tContractor) statusAndVector(ctx context.Context, locator []byte) (*dex v := &dexeth.SwapVector{ From: swap.Participant, To: swap.Initiator, - Value: dexeth.WeiToGwei(swap.Value), + Value: swap.Value, SecretHash: vector.SecretHash, LockTime: uint64(swap.LockTime.Unix()), } @@ -1481,7 +1481,7 @@ func testRefund(t *testing.T, assetID uint32) { v1Vector := dexeth.SwapVector{ From: testAddressA, To: testAddressB, - Value: 1, + Value: dexeth.GweiToWei(1), SecretHash: secretHash, LockTime: uint64(time.Now().Unix()), } @@ -2476,14 +2476,14 @@ func testSwap(t *testing.T, assetID uint32) { testName, receipt.Coin().Value(), contract.Value) } contractData := receipt.Contract() - contractVer, locator, err := dexeth.DecodeLocator(contractData) + contractVer, locator, err := dexeth.DecodeContractData(contractData) if err != nil { t.Fatalf("failed to decode contract data: %v", err) } if swaps.Version != contractVer { t.Fatal("wrong contract version") } - chkLocator := acToLocator(contractVer, contract, node.addr) + chkLocator := acToLocator(contractVer, contract, dexeth.GweiToWei(contract.Value), node.addr) if !bytes.Equal(locator, chkLocator) { t.Fatalf("%v, contract: %x != locator in input: %x", testName, receipt.Contract(), locator) @@ -3052,7 +3052,7 @@ func testRedeem(t *testing.T, assetID uint32) { // Check that value of output coin is as axpected var totalSwapValue uint64 for _, redemption := range test.form.Redemptions { - _, locator, err := dexeth.DecodeLocator(redemption.Spends.Contract) + _, locator, err := dexeth.DecodeContractData(redemption.Spends.Contract) if err != nil { t.Fatalf("DecodeLocator: %v", err) } @@ -3307,15 +3307,6 @@ func TestMaxOrder(t *testing.T) { } } -func overMaxWei() *big.Int { - maxInt := ^uint64(0) - maxWei := new(big.Int).SetUint64(maxInt) - gweiFactorBig := big.NewInt(dexeth.GweiFactor) - maxWei.Mul(maxWei, gweiFactorBig) - overMaxWei := new(big.Int).Set(maxWei) - return overMaxWei.Add(overMaxWei, gweiFactorBig) -} - func packInitiateDataV0(initiations []*dexeth.Initiation) ([]byte, error) { abiInitiations := make([]swapv0.ETHSwapInitiation, 0, len(initiations)) for _, init := range initiations { @@ -3505,7 +3496,7 @@ func testAuditContract(t *testing.T, assetID uint32) { t.Fatalf(`"%v": expected contract %x != actual %x`, test.name, test.contract, auditInfo.Contract) } - _, expectedSecretHash, err := dexeth.DecodeLocator(test.contract) + _, expectedSecretHash, err := dexeth.DecodeContractData(test.contract) if err != nil { t.Fatalf(`"%v": failed to decode versioned bytes: %v`, test.name, err) } @@ -4092,24 +4083,14 @@ func testRefundReserves(t *testing.T, assetID uint32) { node.swapMap = map[[32]byte]*dexeth.SwapState{secretHash: {}} feeWallet := eth - gasesV0 := dexeth.VersionedGases[0] - gasesV1 := &dexeth.Gases{Refund: 1e6} + gasesV0 := eth.versionedGases[0] + gasesV1 := eth.versionedGases[1] assetV0 := *tETHV0 assetV1 := *tETHV0 - if assetID == BipID { - eth.versionedGases[1] = gasesV1 - } else { + if assetID != BipID { feeWallet = node.tokenParent assetV0 = *tTokenV0 assetV1 = *tTokenV0 - tokenContracts := dexeth.Tokens[simnetTokenID].NetTokens[dex.Simnet].SwapContracts - gasesV0 = &tokenGasesV0 - tc := *tokenContracts[0] - tc.Gas = *gasesV1 - tokenContracts[1] = &tc - defer delete(tokenContracts, 1) - eth.versionedGases[0] = gasesV0 - eth.versionedGases[1] = gasesV1 node.tokenContractor.bal = dexeth.GweiToWei(1e9) } @@ -4190,9 +4171,9 @@ func testRedemptionReserves(t *testing.T, assetID uint32) { var secretHash [32]byte node.tContractor.swapMap[secretHash] = &dexeth.SwapState{} - gasesV1 := &dexeth.Gases{Redeem: 1e6, RedeemAdd: 85e5} + gasesV0 := eth.versionedGases[0] + gasesV1 := eth.versionedGases[1] eth.versionedGases[1] = gasesV1 - gasesV0 := dexeth.VersionedGases[0] assetV0 := *tETHV0 assetV1 := *tETHV0 feeWallet := eth @@ -4201,12 +4182,6 @@ func testRedemptionReserves(t *testing.T, assetID uint32) { feeWallet = node.tokenParent assetV0 = *tTokenV0 assetV1 = *tTokenV0 - tokenContracts := dexeth.Tokens[simnetTokenID].NetTokens[dex.Simnet].SwapContracts - gasesV0 = &tokenGasesV0 - tc := *tokenContracts[0] - tc.Gas = *gasesV1 - tokenContracts[1] = &tc - defer delete(tokenContracts, 1) } assetV0.MaxFeeRate = 45 @@ -5453,11 +5428,11 @@ func testMaxSwapRedeemLots(t *testing.T, assetID uint32) { t.Fatalf("expected 63 for max redemptions but got %d", info.MaxRedeemsInTx) } } else { - if info.MaxSwapsInTx != 28 { - t.Fatalf("expected 28 for max swaps but got %d", info.MaxSwapsInTx) + if info.MaxSwapsInTx != 22 { + t.Fatalf("expected 22 for max swaps but got %d", info.MaxSwapsInTx) } - if info.MaxRedeemsInTx != 71 { - t.Fatalf("expected 71 for max redemptions but got %d", info.MaxRedeemsInTx) + if info.MaxRedeemsInTx != 60 { + t.Fatalf("expected 60 for max redemptions but got %d", info.MaxRedeemsInTx) } } } diff --git a/client/asset/eth/nodeclient.go b/client/asset/eth/nodeclient.go index c30aee8d92..ccf7b92cac 100644 --- a/client/asset/eth/nodeclient.go +++ b/client/asset/eth/nodeclient.go @@ -30,8 +30,7 @@ import ( ) const ( - contractVersionNewest = ^uint32(0) - approveGas = 4e5 + approveGas = 4e5 ) var ( @@ -410,9 +409,10 @@ func newTxOpts(ctx context.Context, from common.Address, val, maxGas uint64, max } func gases(contractVer uint32, versionedGases map[uint32]*dexeth.Gases) *dexeth.Gases { - if contractVer != contractVersionNewest { + if contractVer != dexeth.ContractVersionERC20 { return versionedGases[contractVer] } + var bestVer uint32 var bestGases *dexeth.Gases for ver, gases := range versionedGases { diff --git a/client/asset/eth/nodeclient_harness_test.go b/client/asset/eth/nodeclient_harness_test.go index 5eda092fa7..b7c1b33d4d 100644 --- a/client/asset/eth/nodeclient_harness_test.go +++ b/client/asset/eth/nodeclient_harness_test.go @@ -129,10 +129,8 @@ var ( testTokenID uint32 masterToken *dexeth.Token - contractAddr common.Address - - v1 bool - ver uint32 + v1 bool + contractVer uint32 ) func newContract(stamp uint64, secretHash [32]byte, val uint64) *asset.Contract { @@ -149,11 +147,11 @@ func acLocator(c *asset.Contract) []byte { } func makeLocator(secretHash [32]byte, valg, lockTime uint64) []byte { - if ver == 1 { + if contractVer == 1 { return (&dexeth.SwapVector{ From: ethClient.address(), To: participantEthClient.address(), - Value: valg, + Value: dexeth.GweiToWei(valg), SecretHash: secretHash, LockTime: lockTime, }).Locator() @@ -171,7 +169,7 @@ func newRedeem(secret, secretHash [32]byte, valg, lockTime uint64) *asset.Redemp // id: txHash, value: valg, }, - Contract: dexeth.EncodeContractData(ver, makeLocator(secretHash, valg, lockTime)), + Contract: dexeth.EncodeContractData(contractVer, makeLocator(secretHash, valg, lockTime)), }, Secret: secret[:], } @@ -385,15 +383,15 @@ func runSimnet(m *testing.M) (int, error) { return 1, fmt.Errorf("error creating participant wallet dir: %v", err) } - tokenGases = &dexeth.Tokens[testTokenID].NetTokens[dex.Simnet].SwapContracts[ver].Gas + tokenGases = &dexeth.Tokens[testTokenID].NetTokens[dex.Simnet].SwapContracts[contractVer].Gas // ETH swap contract. token := dexeth.Tokens[testTokenID].NetTokens[dex.Simnet] - fmt.Printf("ETH swap contract address is %v\n", dexeth.ContractAddresses[ver][dex.Simnet]) - fmt.Printf("Token swap contract addr is %v\n", token.SwapContracts[ver].Address) + fmt.Printf("ETH swap contract address is %v\n", dexeth.ContractAddresses[contractVer][dex.Simnet]) + fmt.Printf("Token swap contract addr is %v\n", token.SwapContracts[contractVer].Address) fmt.Printf("Test token contract addr is %v\n", token.Address) - contractAddr = dexeth.ContractAddresses[ver][dex.Simnet] + contractAddr := dexeth.ContractAddresses[contractVer][dex.Simnet] initiatorProviders, participantProviders := rpcEndpoints(dex.Simnet) @@ -428,9 +426,9 @@ func runSimnet(m *testing.M) (int, error) { simnetAddr = simnetAcct.Address participantAddr = participantAcct.Address - contractAddr, exists := dexeth.ContractAddresses[ver][dex.Simnet] + contractAddr, exists := dexeth.ContractAddresses[contractVer][dex.Simnet] if !exists || contractAddr == (common.Address{}) { - return 1, fmt.Errorf("no contract address for version %d", ver) + return 1, fmt.Errorf("no contract address for contract version %d", contractVer) } if v1 { @@ -495,7 +493,7 @@ func runSimnet(m *testing.M) (int, error) { func runTestnet(m *testing.M) (int, error) { testTokenID = usdcID masterToken = dexeth.Tokens[testTokenID] - tokenGases = &masterToken.NetTokens[dex.Testnet].SwapContracts[ver].Gas + tokenGases = &masterToken.NetTokens[dex.Testnet].SwapContracts[contractVer].Gas if testnetWalletSeed == "" || testnetParticipantWalletSeed == "" { return 1, errors.New("testnet seeds not set") } @@ -510,8 +508,8 @@ func runTestnet(m *testing.M) (int, error) { return 1, fmt.Errorf("error creating testnet participant wallet dir: %v", err) } secPerBlock = testnetSecPerBlock - contractAddr = dexeth.ContractAddresses[ver][dex.Testnet] - fmt.Printf("ETH swap contract address is %v\n", contractAddr) + contractAddr := dexeth.ContractAddresses[contractVer][dex.Testnet] + fmt.Printf("Swap contract address is %v\n", contractAddr) initiatorRPC, participantRPC := rpcEndpoints(dex.Testnet) @@ -560,13 +558,13 @@ func runTestnet(m *testing.M) (int, error) { simnetAddr = simnetAcct.Address participantAddr = participantAcct.Address - contractAddr, exists := dexeth.ContractAddresses[ver][dex.Testnet] + contractAddr, exists := dexeth.ContractAddresses[contractVer][dex.Testnet] if !exists || contractAddr == (common.Address{}) { - return 1, fmt.Errorf("no contract address for version %d", ver) + return 1, fmt.Errorf("no contract address for version %d", contractVer) } ctor, tokenCtor := newV0Contractor, newV0TokenContractor - if ver == 1 { + if contractVer == 1 { ctor, tokenCtor = newV1Contractor, newV1TokenContractor } @@ -622,6 +620,8 @@ func prepareV1SimnetContractors() (err error) { } func prepareSimnetContractors(c contractorConstructor, tc tokenContractorConstructor) (err error) { + contractAddr := dexeth.ContractAddresses[contractVer][dex.Simnet] + if simnetContractor, err = c(dex.Simnet, contractAddr, simnetAddr, ethClient.contractBackend()); err != nil { return fmt.Errorf("new contractor error: %w", err) } @@ -629,7 +629,9 @@ func prepareSimnetContractors(c contractorConstructor, tc tokenContractorConstru return fmt.Errorf("participant new contractor error: %w", err) } - if simnetTokenContractor, err = tc(dex.Simnet, masterToken, simnetAddr, ethClient.contractBackend()); err != nil { + token := dexeth.Tokens[testTokenID] + + if simnetTokenContractor, err = tc(dex.Simnet, token, simnetAddr, ethClient.contractBackend()); err != nil { return fmt.Errorf("new token contractor error: %w", err) } @@ -638,7 +640,7 @@ func prepareSimnetContractors(c contractorConstructor, tc tokenContractorConstru // (*BoundContract).Call while calling (*ERC20Swap).TokenAddress. time.Sleep(time.Second) - if participantTokenContractor, err = tc(dex.Simnet, masterToken, participantAddr, participantEthClient.contractBackend()); err != nil { + if participantTokenContractor, err = tc(dex.Simnet, token, participantAddr, participantEthClient.contractBackend()); err != nil { return fmt.Errorf("participant new token contractor error: %w", err) } return @@ -674,14 +676,12 @@ func TestMain(m *testing.M) { flag.Parse() if v1 { - ver = 1 + contractVer = 1 } - ethGases = dexeth.VersionedGases[ver] - contractAddr = dexeth.ContractAddresses[BipID][dex.Simnet] + ethGases = dexeth.VersionedGases[contractVer] if isTestnet { - contractAddr = dexeth.ContractAddresses[BipID][dex.Testnet] tmpDir, err := os.MkdirTemp("", "") if err != nil { fmt.Fprintf(os.Stderr, "error creating temporary directory: %v", err) @@ -839,7 +839,7 @@ func TestBasicRetrieval(t *testing.T) { func TestPeering(t *testing.T) { t.Run("testAddPeer", testAddPeer) t.Run("testSyncProgress", testSyncProgress) - t.Run("testGetCodeAt", testGetCodeAt) + // t.Run("testGetCodeAt", testGetCodeAt) } func TestAccount(t *testing.T) { @@ -1167,39 +1167,41 @@ func testSyncProgress(t *testing.T) { spew.Dump(p) } -// func testInitiateGas(t *testing.T, assetID uint32) { -// if assetID != BipID { -// prepareTokenClients(t) -// } +func testInitiateGas(t *testing.T, assetID uint32) { + gases := ethGases + c := simnetContractor + if assetID != BipID { + c = simnetTokenContractor + prepareTokenClients(t) + gases = tokenGases + } -// gases := gases(ver, dexeth.VersionedGases) - -// var previousGas uint64 -// maxSwaps := 50 -// for i := 1; i <= maxSwaps; i++ { -// gas, err := ethClient.estimateInitGas(ctx, i) -// if err != nil { -// t.Fatalf("unexpected error from estimateInitGas(%d): %v", i, err) -// } - -// var expectedGas uint64 -// var actualGas uint64 -// if i == 1 { -// expectedGas = gases.Swap -// actualGas = gas -// } else { -// expectedGas = gases.SwapAdd -// actualGas = gas - previousGas -// } -// if actualGas > expectedGas || actualGas < expectedGas/2 { -// t.Fatalf("Expected incremental gas for %d initiations to be close to %d but got %d", -// i, expectedGas, actualGas) -// } - -// fmt.Printf("Gas used for batch initiating %v swaps: %v. %v more than previous \n", i, gas, gas-previousGas) -// previousGas = gas -// } -// } + var previousGas uint64 + maxSwaps := 50 + for i := 1; i <= maxSwaps; i++ { + gas, err := c.estimateInitGas(ctx, i) + if err != nil { + t.Fatalf("unexpected error from estimateInitGas(%d): %v", i, err) + } + + var expectedGas uint64 + var actualGas uint64 + if i == 1 { + expectedGas = gases.Swap + actualGas = gas + } else { + expectedGas = gases.SwapAdd + actualGas = gas - previousGas + } + if actualGas > expectedGas || actualGas < expectedGas/2 { + t.Fatalf("Expected incremental gas for %d initiations to be close to %d but got %d", + i, expectedGas, actualGas) + } + + fmt.Printf("Gas used for batch initiating %v swaps: %v. %v more than previous \n", i, gas, gas-previousGas) + previousGas = gas + } +} // feesAtBlk calculates the gas fee at blkNum. This adds the base fee at blkNum // to a minimum gas tip cap. @@ -2303,23 +2305,23 @@ func testApproveGas(t *testing.T) { fmt.Printf("replacement tx hash: %s\n", tx.Hash()) }*/ -func testGetCodeAt(t *testing.T) { - cl, is := ethClient.(*nodeClient) - if !is { - t.Skip("getCode tests only run for nodeClient") - } - byteCode, err := cl.getCodeAt(ctx, contractAddr) - if err != nil { - t.Fatalf("Failed to get bytecode: %v", err) - } - c, err := hex.DecodeString(swapv0.ETHSwapRuntimeBin) - if err != nil { - t.Fatalf("Error decoding") - } - if !bytes.Equal(byteCode, c) { - t.Fatal("Contract on chain does not match one in code") - } -} +// func testGetCodeAt(t *testing.T) { +// cl, is := ethClient.(*nodeClient) +// if !is { +// t.Skip("getCode tests only run for nodeClient") +// } +// byteCode, err := cl.getCodeAt(ctx, contractAddr) +// if err != nil { +// t.Fatalf("Failed to get bytecode: %v", err) +// } +// c, err := hex.DecodeString(swapv0.ETHSwapRuntimeBin) +// if err != nil { +// t.Fatalf("Error decoding") +// } +// if !bytes.Equal(byteCode, c) { +// t.Fatal("Contract on chain does not match one in code") +// } +// } func testSignMessage(t *testing.T) { msg := []byte("test message") @@ -2347,7 +2349,7 @@ func TestTokenGasEstimates(t *testing.T) { runSimnetMiner(ctx, "eth", tLogger) prepareTokenClients(t) tLogger.SetLevel(dex.LevelInfo) - if err := getGasEstimates(ctx, ethClient, participantEthClient, simnetTokenContractor, participantTokenContractor, 5, ver, tokenGases, tLogger); err != nil { + if err := getGasEstimates(ctx, ethClient, participantEthClient, simnetTokenContractor, participantTokenContractor, 5, contractVer, tokenGases, dexeth.GweiToWei, tLogger); err != nil { t.Fatalf("getGasEstimates error: %v", err) } } diff --git a/dex/networks/erc20/contracts/ERC20SwapV1.sol b/dex/networks/erc20/contracts/ERC20SwapV1.sol index e5a7eaef45..e24541b2fc 100644 --- a/dex/networks/erc20/contracts/ERC20SwapV1.sol +++ b/dex/networks/erc20/contracts/ERC20SwapV1.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: BlueOak-1.0.0 // pragma should be as specific as possible to allow easier validation. -pragma solidity = 0.8.15; +pragma solidity = 0.8.18; // ERC20Swap creates a contract to be deployed on an ethereum network. In // order to save on gas fees, a separate ERC20Swap contract is deployed @@ -58,16 +58,16 @@ contract ERC20Swap { // the swap record. struct Vector { bytes32 secretHash; + uint256 value; address initiator; uint64 refundTimestamp; address participant; - uint64 value; } // contractKey generates a key hash which commits to the contract data. The // generated hash is used as a key in the swaps map. function contractKey(Vector calldata v) public pure returns (bytes32) { - return sha256(bytes.concat(v.secretHash, bytes20(v.initiator), bytes20(v.participant), bytes8(v.value), bytes8(v.refundTimestamp))); + return sha256(bytes.concat(v.secretHash, bytes20(v.initiator), bytes20(v.participant), bytes32(v.value), bytes8(v.refundTimestamp))); } // Redemption is the information necessary to redeem a Vector. Since we @@ -144,7 +144,7 @@ contract ERC20Swap { swaps[k] = record; - initVal += v.value * 1 gwei; + initVal += v.value; } bool success; @@ -196,7 +196,7 @@ contract ERC20Swap { require(secretValidates(r.secret, r.v.secretHash), "invalid secret"); swaps[k] = r.secret; - amountToRedeem += r.v.value * 1 gwei; + amountToRedeem += r.v.value; } bool success; diff --git a/dex/networks/erc20/contracts/v1/BinRuntimeV1.go b/dex/networks/erc20/contracts/v1/BinRuntimeV1.go index 790689b5be..7ce59acbdb 100644 --- a/dex/networks/erc20/contracts/v1/BinRuntimeV1.go +++ b/dex/networks/erc20/contracts/v1/BinRuntimeV1.go @@ -3,4 +3,4 @@ package v1 -const ERC20SwapRuntimeBin = "6080604052600436106100865760003560e01c80637802689d116100595780637802689d146101265780638c8e8fee14610146578063d2544c0614610192578063eb84e7f2146101b2578063ed7cbed7146101ed57600080fd5b8063428b16e11461008b57806361a16e33146100ad57806364a97bff146100e357806377d7e031146100f6575b600080fd5b34801561009757600080fd5b506100ab6100a6366004610dea565b61020d565b005b3480156100b957600080fd5b506100cd6100c8366004610e5f565b610533565b6040516100da9190610e8d565b60405180910390f35b6100ab6100f1366004610ed0565b6105ef565b34801561010257600080fd5b50610116610111366004610f33565b610918565b60405190151581526020016100da565b34801561013257600080fd5b50610116610141366004610e5f565b610992565b34801561015257600080fd5b5061017a7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100da565b34801561019e57600080fd5b506100ab6101ad366004610e5f565b6109c5565b3480156101be57600080fd5b506101df6101cd366004610f55565b60006020819052908152604090205481565b6040519081526020016100da565b3480156101f957600080fd5b506101df610208366004610e5f565b610cc5565b3233146102355760405162461bcd60e51b815260040161022c90610f6e565b60405180910390fd5b6000805b82811015610407573684848381811061025457610254610f98565b60c0029190910191503390506102706080830160608401610fae565b6001600160a01b0316146102b35760405162461bcd60e51b815260206004820152600a6024820152691b9bdd08185d5d1a195960b21b604482015260640161022c565b600080806102c084610dbe565b9250925092506000811180156102d557504381105b6103115760405162461bcd60e51b815260206004820152600d60248201526c0756e66696c6c6564207377617609c1b604482015260640161022c565b61031c828535610918565b1561035c5760405162461bcd60e51b815260206004820152601060248201526f185b1c9958591e481c995919595b595960821b604482015260640161022c565b61036b60a08501358535610918565b6103a85760405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a59081cd958dc995d60921b604482015260640161022c565b600083815260208190526040902060a0850180359091556103cc9060808601610fde565b6103da90633b9aca0061101e565b6103ee9067ffffffffffffffff168761104e565b95505050505080806103ff90611066565b915050610239565b5060408051336024820152604480820184905282518083039091018152606490910182526020810180516001600160e01b031663a9059cbb60e01b17905290516000916060916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916104819161107f565b6000604051808303816000865af19150503d80600081146104be576040519150601f19603f3d011682016040523d82523d6000602084013e6104c3565b606091505b5090925090508180156104ee5750805115806104ee5750808060200190518101906104ee91906110ba565b61052c5760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b604482015260640161022c565b5050505050565b60408051606081018252600080825260208201819052918101829052908061055a84610dbe565b92509250506105846040805160608101909152806000815260006020820181905260409091015290565b816000036105ab578060005b908160038111156105a3576105a3610e77565b9052506105e7565b600183016105bb57806003610590565b6105c6838635610918565b156105db5760028152602081018390526105e7565b60018152604081018290525b949350505050565b32331461060e5760405162461bcd60e51b815260040161022c90610f6e565b6000805b828110156107e8573684848381811061062d5761062d610f98565b905060a002019050600081608001602081019061064a9190610fde565b67ffffffffffffffff16116106895760405162461bcd60e51b81526020600482015260056024820152640c081d985b60da1b604482015260640161022c565b600061069b6060830160408401610fde565b67ffffffffffffffff16116106e65760405162461bcd60e51b815260206004820152601160248201527003020726566756e6454696d657374616d7607c1b604482015260640161022c565b60006106f182610cc5565b60008181526020819052604090205490915080156107425760405162461bcd60e51b815260206004820152600e60248201526d73776170206e6f7420656d70747960901b604482015260640161022c565b504361074f818435610918565b1561078d5760405162461bcd60e51b815260206004820152600e60248201526d3430b9b41031b7b63634b9b4b7b760911b604482015260640161022c565b60008281526020819052604090208190556107ae60a0840160808501610fde565b6107bc90633b9aca0061101e565b6107d09067ffffffffffffffff168661104e565b945050505080806107e090611066565b915050610612565b5060408051336024820152306044820152606480820184905282518083039091018152608490910182526020810180516001600160e01b03166323b872dd60e01b17905290516000916060916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916108689161107f565b6000604051808303816000865af19150503d80600081146108a5576040519150601f19603f3d011682016040523d82523d6000602084013e6108aa565b606091505b5090925090508180156108d55750805115806108d55750808060200190518101906108d591906110ba565b61052c5760405162461bcd60e51b81526020600482015260146024820152731d1c985b9cd9995c88199c9bdb4819985a5b195960621b604482015260640161022c565b60008160028460405160200161093091815260200190565b60408051601f198184030181529082905261094a9161107f565b602060405180830381855afa158015610967573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061098a91906110dc565b149392505050565b60008060006109a084610dbe565b9250925050806000141580156105e757506109bc828535610918565b15949350505050565b3233146109e45760405162461bcd60e51b815260040161022c90610f6e565b6109f46060820160408301610fde565b67ffffffffffffffff16421015610a445760405162461bcd60e51b81526020600482015260146024820152731b1bd8dadd1a5b59481b9bdd08195e1c1a5c995960621b604482015260640161022c565b6000806000610a5284610dbe565b925092509250600081118015610a685750438111155b610aa65760405162461bcd60e51b815260206004820152600f60248201526e73776170206e6f742061637469766560881b604482015260640161022c565b610ab1828535610918565b15610af65760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c995919595b5959605a1b604482015260640161022c565b60018201610b3e5760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c99599d5b991959605a1b604482015260640161022c565b6000838152602081905260408120600019905560606001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167fa9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b33610baf60a08a0160808b01610fde565b6040516001600160a01b03909216602483015267ffffffffffffffff16604482015260640160408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051610c12919061107f565b6000604051808303816000865af19150503d8060008114610c4f576040519150601f19603f3d011682016040523d82523d6000602084013e610c54565b606091505b509092509050818015610c7f575080511580610c7f575080806020019051810190610c7f91906110ba565b610cbd5760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b604482015260640161022c565b505050505050565b600060028235610cdb6040850160208601610fae565b60601b846060016020810190610cf19190610fae565b60601b610d0460a0870160808801610fde565b60c01b610d176060880160408901610fde565b6040805160208101969096526bffffffffffffffffffffffff19948516908601529190921660548401526001600160c01b0319918216606884015260c01b16607082015260780160408051601f1981840301815290829052610d789161107f565b602060405180830381855afa158015610d95573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610db891906110dc565b92915050565b600080600080610dcd85610cc5565b600081815260208190526040902054909690955085945092505050565b60008060208385031215610dfd57600080fd5b823567ffffffffffffffff80821115610e1557600080fd5b818501915085601f830112610e2957600080fd5b813581811115610e3857600080fd5b86602060c083028501011115610e4d57600080fd5b60209290920196919550909350505050565b600060a08284031215610e7157600080fd5b50919050565b634e487b7160e01b600052602160045260246000fd5b8151606082019060048110610eb257634e487b7160e01b600052602160045260246000fd5b80835250602083015160208301526040830151604083015292915050565b60008060208385031215610ee357600080fd5b823567ffffffffffffffff80821115610efb57600080fd5b818501915085601f830112610f0f57600080fd5b813581811115610f1e57600080fd5b86602060a083028501011115610e4d57600080fd5b60008060408385031215610f4657600080fd5b50508035926020909101359150565b600060208284031215610f6757600080fd5b5035919050565b60208082526010908201526f39b2b73232b910109e9037b934b3b4b760811b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215610fc057600080fd5b81356001600160a01b0381168114610fd757600080fd5b9392505050565b600060208284031215610ff057600080fd5b813567ffffffffffffffff81168114610fd757600080fd5b634e487b7160e01b600052601160045260246000fd5b600067ffffffffffffffff8083168185168183048111821515161561104557611045611008565b02949350505050565b6000821982111561106157611061611008565b500190565b60006001820161107857611078611008565b5060010190565b6000825160005b818110156110a05760208186018101518583015201611086565b818111156110af576000828501525b509190910192915050565b6000602082840312156110cc57600080fd5b81518015158114610fd757600080fd5b6000602082840312156110ee57600080fd5b505191905056fea2646970667358221220319d89b87a0d5782925310133ed5d12d2ff562b0786611308396804fcad176fc64736f6c634300080f0033" +const ERC20SwapRuntimeBin = "6080604052600436106100865760003560e01c80638cd8dd97116100595780638cd8dd9714610141578063a76f9f2d14610161578063d5cfd0491461018f578063db3b419c146101af578063eb84e7f2146101dc57600080fd5b806323f0388b1461008b5780633da59631146100ad57806377d7e031146100c05780638c8e8fee146100f5575b600080fd5b34801561009757600080fd5b506100ab6100a6366004610d30565b610209565b005b6100ab6100bb366004610da5565b61050c565b3480156100cc57600080fd5b506100e06100db366004610e08565b6107f9565b60405190151581526020015b60405180910390f35b34801561010157600080fd5b506101297f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100ec565b34801561014d57600080fd5b506100ab61015c366004610e2a565b610875565b34801561016d57600080fd5b5061018161017c366004610e2a565b610b2d565b6040519081526020016100ec565b34801561019b57600080fd5b506100e06101aa366004610e2a565b610c15565b3480156101bb57600080fd5b506101cf6101ca366004610e2a565b610c49565b6040516100ec9190610e58565b3480156101e857600080fd5b506101816101f7366004610e9b565b60006020819052908152604090205481565b3233146102315760405162461bcd60e51b815260040161022890610eb4565b60405180910390fd5b6000805b828110156103e0573684848381811061025057610250610ede565b60c00291909101915033905061026c60a0830160808401610ef4565b6001600160a01b0316146102af5760405162461bcd60e51b815260206004820152600a6024820152691b9bdd08185d5d1a195960b21b6044820152606401610228565b600080806102bc84610d04565b9250925092506000811180156102d157504381105b61030d5760405162461bcd60e51b815260206004820152600d60248201526c0756e66696c6c6564207377617609c1b6044820152606401610228565b6103188285356107f9565b156103585760405162461bcd60e51b815260206004820152601060248201526f185b1c9958591e481c995919595b595960821b6044820152606401610228565b61036760a085013585356107f9565b6103a45760405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a59081cd958dc995d60921b6044820152606401610228565b60008381526020818152604090912060a086013590556103c79085013587610f3a565b95505050505080806103d890610f4d565b915050610235565b5060408051336024820152604480820184905282518083039091018152606490910182526020810180516001600160e01b031663a9059cbb60e01b17905290516000916060916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169161045a91610f66565b6000604051808303816000865af19150503d8060008114610497576040519150601f19603f3d011682016040523d82523d6000602084013e61049c565b606091505b5090925090508180156104c75750805115806104c75750808060200190518101906104c79190610f95565b6105055760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b6044820152606401610228565b5050505050565b32331461052b5760405162461bcd60e51b815260040161022890610eb4565b6000805b828110156106c9573684848381811061054a5761054a610ede565b905060a002019050600081602001351161058e5760405162461bcd60e51b81526020600482015260056024820152640c081d985b60da1b6044820152606401610228565b60006105a06080830160608401610fb7565b67ffffffffffffffff16116105eb5760405162461bcd60e51b815260206004820152601160248201527003020726566756e6454696d657374616d7607c1b6044820152606401610228565b60006105f682610b2d565b60008181526020819052604090205490915080156106475760405162461bcd60e51b815260206004820152600e60248201526d73776170206e6f7420656d70747960901b6044820152606401610228565b50436106548184356107f9565b156106925760405162461bcd60e51b815260206004820152600e60248201526d3430b9b41031b7b63634b9b4b7b760911b6044820152606401610228565b6000828152602081815260409091208290556106b19084013586610f3a565b945050505080806106c190610f4d565b91505061052f565b5060408051336024820152306044820152606480820184905282518083039091018152608490910182526020810180516001600160e01b03166323b872dd60e01b17905290516000916060916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169161074991610f66565b6000604051808303816000865af19150503d8060008114610786576040519150601f19603f3d011682016040523d82523d6000602084013e61078b565b606091505b5090925090508180156107b65750805115806107b65750808060200190518101906107b69190610f95565b6105055760405162461bcd60e51b81526020600482015260146024820152731d1c985b9cd9995c88199c9bdb4819985a5b195960621b6044820152606401610228565b60008160028460405160200161081191815260200190565b60408051601f198184030181529082905261082b91610f66565b602060405180830381855afa158015610848573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061086b9190610fe1565b1490505b92915050565b3233146108945760405162461bcd60e51b815260040161022890610eb4565b6108a46080820160608301610fb7565b67ffffffffffffffff164210156108f45760405162461bcd60e51b81526020600482015260146024820152731b1bd8dadd1a5b59481b9bdd08195e1c1a5c995960621b6044820152606401610228565b600080600061090284610d04565b9250925092506000811180156109185750438111155b6109565760405162461bcd60e51b815260206004820152600f60248201526e73776170206e6f742061637469766560881b6044820152606401610228565b6109618285356107f9565b156109a65760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c995919595b5959605a1b6044820152606401610228565b600182016109ee5760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c99599d5b991959605a1b6044820152606401610228565b6000838152602081815260408083206000199055805133602482015287830135604480830191909152825180830390910181526064909101825291820180516001600160e01b031663a9059cbb60e01b179052516060917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691610a7a9190610f66565b6000604051808303816000865af19150503d8060008114610ab7576040519150601f19603f3d011682016040523d82523d6000602084013e610abc565b606091505b509092509050818015610ae7575080511580610ae7575080806020019051810190610ae79190610f95565b610b255760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b6044820152606401610228565b505050505050565b600060028235610b436060850160408601610ef4565b60601b610b5660a0860160808701610ef4565b60601b856020013560001b866060016020810190610b749190610fb7565b6040805160208101969096526bffffffffffffffffffffffff199485169086015292909116605484015260688301526001600160c01b031960c09190911b16608882015260900160408051601f1981840301815290829052610bd591610f66565b602060405180830381855afa158015610bf2573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061086f9190610fe1565b6000806000610c2384610d04565b925092505080600014158015610c415750610c3f8285356107f9565b155b949350505050565b604080516060810182526000808252602082018190529181018290529080610c7084610d04565b9250925050610c9a6040805160608101909152806000815260006020820181905260409091015290565b81600003610cc1578060005b90816003811115610cb957610cb9610e42565b905250610c41565b60018301610cd157806003610ca6565b610cdc8386356107f9565b15610cf1576002815260208101839052610c41565b6001815260408101919091529392505050565b600080600080610d1385610b2d565b600081815260208190526040902054909690955085945092505050565b60008060208385031215610d4357600080fd5b823567ffffffffffffffff80821115610d5b57600080fd5b818501915085601f830112610d6f57600080fd5b813581811115610d7e57600080fd5b86602060c083028501011115610d9357600080fd5b60209290920196919550909350505050565b60008060208385031215610db857600080fd5b823567ffffffffffffffff80821115610dd057600080fd5b818501915085601f830112610de457600080fd5b813581811115610df357600080fd5b86602060a083028501011115610d9357600080fd5b60008060408385031215610e1b57600080fd5b50508035926020909101359150565b600060a08284031215610e3c57600080fd5b50919050565b634e487b7160e01b600052602160045260246000fd5b8151606082019060048110610e7d57634e487b7160e01b600052602160045260246000fd5b80835250602083015160208301526040830151604083015292915050565b600060208284031215610ead57600080fd5b5035919050565b60208082526010908201526f39b2b73232b910109e9037b934b3b4b760811b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215610f0657600080fd5b81356001600160a01b0381168114610f1d57600080fd5b9392505050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561086f5761086f610f24565b600060018201610f5f57610f5f610f24565b5060010190565b6000825160005b81811015610f875760208186018101518583015201610f6d565b506000920191825250919050565b600060208284031215610fa757600080fd5b81518015158114610f1d57600080fd5b600060208284031215610fc957600080fd5b813567ffffffffffffffff81168114610f1d57600080fd5b600060208284031215610ff357600080fd5b505191905056fea2646970667358221220c0241e9efff6cacb5548883e39463986c365c3946a5a393e3484418cfb88e66a64736f6c63430008120033" diff --git a/dex/networks/erc20/contracts/v1/contract.go b/dex/networks/erc20/contracts/v1/contract.go index 7afaf0f4f0..75531d53a0 100644 --- a/dex/networks/erc20/contracts/v1/contract.go +++ b/dex/networks/erc20/contracts/v1/contract.go @@ -31,8 +31,8 @@ var ( // ERC20SwapMetaData contains all meta data concerning the ERC20Swap contract. var ERC20SwapMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"value\",\"type\":\"uint64\"}],\"internalType\":\"structERC20Swap.Vector\",\"name\":\"v\",\"type\":\"tuple\"}],\"name\":\"contractKey\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"value\",\"type\":\"uint64\"}],\"internalType\":\"structERC20Swap.Vector[]\",\"name\":\"contracts\",\"type\":\"tuple[]\"}],\"name\":\"initiate\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"value\",\"type\":\"uint64\"}],\"internalType\":\"structERC20Swap.Vector\",\"name\":\"v\",\"type\":\"tuple\"}],\"name\":\"isRedeemable\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"value\",\"type\":\"uint64\"}],\"internalType\":\"structERC20Swap.Vector\",\"name\":\"v\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"secret\",\"type\":\"bytes32\"}],\"internalType\":\"structERC20Swap.Redemption[]\",\"name\":\"redemptions\",\"type\":\"tuple[]\"}],\"name\":\"redeem\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"value\",\"type\":\"uint64\"}],\"internalType\":\"structERC20Swap.Vector\",\"name\":\"v\",\"type\":\"tuple\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"secret\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"}],\"name\":\"secretValidates\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"value\",\"type\":\"uint64\"}],\"internalType\":\"structERC20Swap.Vector\",\"name\":\"v\",\"type\":\"tuple\"}],\"name\":\"status\",\"outputs\":[{\"components\":[{\"internalType\":\"enumERC20Swap.Step\",\"name\":\"step\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"secret\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"internalType\":\"structERC20Swap.Status\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"swaps\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token_address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x60a060405234801561001057600080fd5b506040516111cb3803806111cb83398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b60805161112b6100a060003960008181610158015281816104570152818161083e0152610b5d015261112b6000f3fe6080604052600436106100865760003560e01c80637802689d116100595780637802689d146101265780638c8e8fee14610146578063d2544c0614610192578063eb84e7f2146101b2578063ed7cbed7146101ed57600080fd5b8063428b16e11461008b57806361a16e33146100ad57806364a97bff146100e357806377d7e031146100f6575b600080fd5b34801561009757600080fd5b506100ab6100a6366004610dea565b61020d565b005b3480156100b957600080fd5b506100cd6100c8366004610e5f565b610533565b6040516100da9190610e8d565b60405180910390f35b6100ab6100f1366004610ed0565b6105ef565b34801561010257600080fd5b50610116610111366004610f33565b610918565b60405190151581526020016100da565b34801561013257600080fd5b50610116610141366004610e5f565b610992565b34801561015257600080fd5b5061017a7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100da565b34801561019e57600080fd5b506100ab6101ad366004610e5f565b6109c5565b3480156101be57600080fd5b506101df6101cd366004610f55565b60006020819052908152604090205481565b6040519081526020016100da565b3480156101f957600080fd5b506101df610208366004610e5f565b610cc5565b3233146102355760405162461bcd60e51b815260040161022c90610f6e565b60405180910390fd5b6000805b82811015610407573684848381811061025457610254610f98565b60c0029190910191503390506102706080830160608401610fae565b6001600160a01b0316146102b35760405162461bcd60e51b815260206004820152600a6024820152691b9bdd08185d5d1a195960b21b604482015260640161022c565b600080806102c084610dbe565b9250925092506000811180156102d557504381105b6103115760405162461bcd60e51b815260206004820152600d60248201526c0756e66696c6c6564207377617609c1b604482015260640161022c565b61031c828535610918565b1561035c5760405162461bcd60e51b815260206004820152601060248201526f185b1c9958591e481c995919595b595960821b604482015260640161022c565b61036b60a08501358535610918565b6103a85760405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a59081cd958dc995d60921b604482015260640161022c565b600083815260208190526040902060a0850180359091556103cc9060808601610fde565b6103da90633b9aca0061101e565b6103ee9067ffffffffffffffff168761104e565b95505050505080806103ff90611066565b915050610239565b5060408051336024820152604480820184905282518083039091018152606490910182526020810180516001600160e01b031663a9059cbb60e01b17905290516000916060916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916104819161107f565b6000604051808303816000865af19150503d80600081146104be576040519150601f19603f3d011682016040523d82523d6000602084013e6104c3565b606091505b5090925090508180156104ee5750805115806104ee5750808060200190518101906104ee91906110ba565b61052c5760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b604482015260640161022c565b5050505050565b60408051606081018252600080825260208201819052918101829052908061055a84610dbe565b92509250506105846040805160608101909152806000815260006020820181905260409091015290565b816000036105ab578060005b908160038111156105a3576105a3610e77565b9052506105e7565b600183016105bb57806003610590565b6105c6838635610918565b156105db5760028152602081018390526105e7565b60018152604081018290525b949350505050565b32331461060e5760405162461bcd60e51b815260040161022c90610f6e565b6000805b828110156107e8573684848381811061062d5761062d610f98565b905060a002019050600081608001602081019061064a9190610fde565b67ffffffffffffffff16116106895760405162461bcd60e51b81526020600482015260056024820152640c081d985b60da1b604482015260640161022c565b600061069b6060830160408401610fde565b67ffffffffffffffff16116106e65760405162461bcd60e51b815260206004820152601160248201527003020726566756e6454696d657374616d7607c1b604482015260640161022c565b60006106f182610cc5565b60008181526020819052604090205490915080156107425760405162461bcd60e51b815260206004820152600e60248201526d73776170206e6f7420656d70747960901b604482015260640161022c565b504361074f818435610918565b1561078d5760405162461bcd60e51b815260206004820152600e60248201526d3430b9b41031b7b63634b9b4b7b760911b604482015260640161022c565b60008281526020819052604090208190556107ae60a0840160808501610fde565b6107bc90633b9aca0061101e565b6107d09067ffffffffffffffff168661104e565b945050505080806107e090611066565b915050610612565b5060408051336024820152306044820152606480820184905282518083039091018152608490910182526020810180516001600160e01b03166323b872dd60e01b17905290516000916060916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916108689161107f565b6000604051808303816000865af19150503d80600081146108a5576040519150601f19603f3d011682016040523d82523d6000602084013e6108aa565b606091505b5090925090508180156108d55750805115806108d55750808060200190518101906108d591906110ba565b61052c5760405162461bcd60e51b81526020600482015260146024820152731d1c985b9cd9995c88199c9bdb4819985a5b195960621b604482015260640161022c565b60008160028460405160200161093091815260200190565b60408051601f198184030181529082905261094a9161107f565b602060405180830381855afa158015610967573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061098a91906110dc565b149392505050565b60008060006109a084610dbe565b9250925050806000141580156105e757506109bc828535610918565b15949350505050565b3233146109e45760405162461bcd60e51b815260040161022c90610f6e565b6109f46060820160408301610fde565b67ffffffffffffffff16421015610a445760405162461bcd60e51b81526020600482015260146024820152731b1bd8dadd1a5b59481b9bdd08195e1c1a5c995960621b604482015260640161022c565b6000806000610a5284610dbe565b925092509250600081118015610a685750438111155b610aa65760405162461bcd60e51b815260206004820152600f60248201526e73776170206e6f742061637469766560881b604482015260640161022c565b610ab1828535610918565b15610af65760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c995919595b5959605a1b604482015260640161022c565b60018201610b3e5760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c99599d5b991959605a1b604482015260640161022c565b6000838152602081905260408120600019905560606001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167fa9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b33610baf60a08a0160808b01610fde565b6040516001600160a01b03909216602483015267ffffffffffffffff16604482015260640160408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051610c12919061107f565b6000604051808303816000865af19150503d8060008114610c4f576040519150601f19603f3d011682016040523d82523d6000602084013e610c54565b606091505b509092509050818015610c7f575080511580610c7f575080806020019051810190610c7f91906110ba565b610cbd5760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b604482015260640161022c565b505050505050565b600060028235610cdb6040850160208601610fae565b60601b846060016020810190610cf19190610fae565b60601b610d0460a0870160808801610fde565b60c01b610d176060880160408901610fde565b6040805160208101969096526bffffffffffffffffffffffff19948516908601529190921660548401526001600160c01b0319918216606884015260c01b16607082015260780160408051601f1981840301815290829052610d789161107f565b602060405180830381855afa158015610d95573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610db891906110dc565b92915050565b600080600080610dcd85610cc5565b600081815260208190526040902054909690955085945092505050565b60008060208385031215610dfd57600080fd5b823567ffffffffffffffff80821115610e1557600080fd5b818501915085601f830112610e2957600080fd5b813581811115610e3857600080fd5b86602060c083028501011115610e4d57600080fd5b60209290920196919550909350505050565b600060a08284031215610e7157600080fd5b50919050565b634e487b7160e01b600052602160045260246000fd5b8151606082019060048110610eb257634e487b7160e01b600052602160045260246000fd5b80835250602083015160208301526040830151604083015292915050565b60008060208385031215610ee357600080fd5b823567ffffffffffffffff80821115610efb57600080fd5b818501915085601f830112610f0f57600080fd5b813581811115610f1e57600080fd5b86602060a083028501011115610e4d57600080fd5b60008060408385031215610f4657600080fd5b50508035926020909101359150565b600060208284031215610f6757600080fd5b5035919050565b60208082526010908201526f39b2b73232b910109e9037b934b3b4b760811b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215610fc057600080fd5b81356001600160a01b0381168114610fd757600080fd5b9392505050565b600060208284031215610ff057600080fd5b813567ffffffffffffffff81168114610fd757600080fd5b634e487b7160e01b600052601160045260246000fd5b600067ffffffffffffffff8083168185168183048111821515161561104557611045611008565b02949350505050565b6000821982111561106157611061611008565b500190565b60006001820161107857611078611008565b5060010190565b6000825160005b818110156110a05760208186018101518583015201611086565b818111156110af576000828501525b509190910192915050565b6000602082840312156110cc57600080fd5b81518015158114610fd757600080fd5b6000602082840312156110ee57600080fd5b505191905056fea2646970667358221220319d89b87a0d5782925310133ed5d12d2ff562b0786611308396804fcad176fc64736f6c634300080f0033", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"}],\"internalType\":\"structERC20Swap.Vector\",\"name\":\"v\",\"type\":\"tuple\"}],\"name\":\"contractKey\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"}],\"internalType\":\"structERC20Swap.Vector[]\",\"name\":\"contracts\",\"type\":\"tuple[]\"}],\"name\":\"initiate\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"}],\"internalType\":\"structERC20Swap.Vector\",\"name\":\"v\",\"type\":\"tuple\"}],\"name\":\"isRedeemable\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"}],\"internalType\":\"structERC20Swap.Vector\",\"name\":\"v\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"secret\",\"type\":\"bytes32\"}],\"internalType\":\"structERC20Swap.Redemption[]\",\"name\":\"redemptions\",\"type\":\"tuple[]\"}],\"name\":\"redeem\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"}],\"internalType\":\"structERC20Swap.Vector\",\"name\":\"v\",\"type\":\"tuple\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"secret\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"}],\"name\":\"secretValidates\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"}],\"internalType\":\"structERC20Swap.Vector\",\"name\":\"v\",\"type\":\"tuple\"}],\"name\":\"status\",\"outputs\":[{\"components\":[{\"internalType\":\"enumERC20Swap.Step\",\"name\":\"step\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"secret\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"internalType\":\"structERC20Swap.Status\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"swaps\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token_address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x60a060405234801561001057600080fd5b506040516110d03803806110d083398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b6080516110306100a060003960008181610107015281816104300152818161071f0152610a4701526110306000f3fe6080604052600436106100865760003560e01c80638cd8dd97116100595780638cd8dd9714610141578063a76f9f2d14610161578063d5cfd0491461018f578063db3b419c146101af578063eb84e7f2146101dc57600080fd5b806323f0388b1461008b5780633da59631146100ad57806377d7e031146100c05780638c8e8fee146100f5575b600080fd5b34801561009757600080fd5b506100ab6100a6366004610d30565b610209565b005b6100ab6100bb366004610da5565b61050c565b3480156100cc57600080fd5b506100e06100db366004610e08565b6107f9565b60405190151581526020015b60405180910390f35b34801561010157600080fd5b506101297f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100ec565b34801561014d57600080fd5b506100ab61015c366004610e2a565b610875565b34801561016d57600080fd5b5061018161017c366004610e2a565b610b2d565b6040519081526020016100ec565b34801561019b57600080fd5b506100e06101aa366004610e2a565b610c15565b3480156101bb57600080fd5b506101cf6101ca366004610e2a565b610c49565b6040516100ec9190610e58565b3480156101e857600080fd5b506101816101f7366004610e9b565b60006020819052908152604090205481565b3233146102315760405162461bcd60e51b815260040161022890610eb4565b60405180910390fd5b6000805b828110156103e0573684848381811061025057610250610ede565b60c00291909101915033905061026c60a0830160808401610ef4565b6001600160a01b0316146102af5760405162461bcd60e51b815260206004820152600a6024820152691b9bdd08185d5d1a195960b21b6044820152606401610228565b600080806102bc84610d04565b9250925092506000811180156102d157504381105b61030d5760405162461bcd60e51b815260206004820152600d60248201526c0756e66696c6c6564207377617609c1b6044820152606401610228565b6103188285356107f9565b156103585760405162461bcd60e51b815260206004820152601060248201526f185b1c9958591e481c995919595b595960821b6044820152606401610228565b61036760a085013585356107f9565b6103a45760405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a59081cd958dc995d60921b6044820152606401610228565b60008381526020818152604090912060a086013590556103c79085013587610f3a565b95505050505080806103d890610f4d565b915050610235565b5060408051336024820152604480820184905282518083039091018152606490910182526020810180516001600160e01b031663a9059cbb60e01b17905290516000916060916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169161045a91610f66565b6000604051808303816000865af19150503d8060008114610497576040519150601f19603f3d011682016040523d82523d6000602084013e61049c565b606091505b5090925090508180156104c75750805115806104c75750808060200190518101906104c79190610f95565b6105055760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b6044820152606401610228565b5050505050565b32331461052b5760405162461bcd60e51b815260040161022890610eb4565b6000805b828110156106c9573684848381811061054a5761054a610ede565b905060a002019050600081602001351161058e5760405162461bcd60e51b81526020600482015260056024820152640c081d985b60da1b6044820152606401610228565b60006105a06080830160608401610fb7565b67ffffffffffffffff16116105eb5760405162461bcd60e51b815260206004820152601160248201527003020726566756e6454696d657374616d7607c1b6044820152606401610228565b60006105f682610b2d565b60008181526020819052604090205490915080156106475760405162461bcd60e51b815260206004820152600e60248201526d73776170206e6f7420656d70747960901b6044820152606401610228565b50436106548184356107f9565b156106925760405162461bcd60e51b815260206004820152600e60248201526d3430b9b41031b7b63634b9b4b7b760911b6044820152606401610228565b6000828152602081815260409091208290556106b19084013586610f3a565b945050505080806106c190610f4d565b91505061052f565b5060408051336024820152306044820152606480820184905282518083039091018152608490910182526020810180516001600160e01b03166323b872dd60e01b17905290516000916060916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169161074991610f66565b6000604051808303816000865af19150503d8060008114610786576040519150601f19603f3d011682016040523d82523d6000602084013e61078b565b606091505b5090925090508180156107b65750805115806107b65750808060200190518101906107b69190610f95565b6105055760405162461bcd60e51b81526020600482015260146024820152731d1c985b9cd9995c88199c9bdb4819985a5b195960621b6044820152606401610228565b60008160028460405160200161081191815260200190565b60408051601f198184030181529082905261082b91610f66565b602060405180830381855afa158015610848573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061086b9190610fe1565b1490505b92915050565b3233146108945760405162461bcd60e51b815260040161022890610eb4565b6108a46080820160608301610fb7565b67ffffffffffffffff164210156108f45760405162461bcd60e51b81526020600482015260146024820152731b1bd8dadd1a5b59481b9bdd08195e1c1a5c995960621b6044820152606401610228565b600080600061090284610d04565b9250925092506000811180156109185750438111155b6109565760405162461bcd60e51b815260206004820152600f60248201526e73776170206e6f742061637469766560881b6044820152606401610228565b6109618285356107f9565b156109a65760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c995919595b5959605a1b6044820152606401610228565b600182016109ee5760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c99599d5b991959605a1b6044820152606401610228565b6000838152602081815260408083206000199055805133602482015287830135604480830191909152825180830390910181526064909101825291820180516001600160e01b031663a9059cbb60e01b179052516060917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691610a7a9190610f66565b6000604051808303816000865af19150503d8060008114610ab7576040519150601f19603f3d011682016040523d82523d6000602084013e610abc565b606091505b509092509050818015610ae7575080511580610ae7575080806020019051810190610ae79190610f95565b610b255760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b6044820152606401610228565b505050505050565b600060028235610b436060850160408601610ef4565b60601b610b5660a0860160808701610ef4565b60601b856020013560001b866060016020810190610b749190610fb7565b6040805160208101969096526bffffffffffffffffffffffff199485169086015292909116605484015260688301526001600160c01b031960c09190911b16608882015260900160408051601f1981840301815290829052610bd591610f66565b602060405180830381855afa158015610bf2573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061086f9190610fe1565b6000806000610c2384610d04565b925092505080600014158015610c415750610c3f8285356107f9565b155b949350505050565b604080516060810182526000808252602082018190529181018290529080610c7084610d04565b9250925050610c9a6040805160608101909152806000815260006020820181905260409091015290565b81600003610cc1578060005b90816003811115610cb957610cb9610e42565b905250610c41565b60018301610cd157806003610ca6565b610cdc8386356107f9565b15610cf1576002815260208101839052610c41565b6001815260408101919091529392505050565b600080600080610d1385610b2d565b600081815260208190526040902054909690955085945092505050565b60008060208385031215610d4357600080fd5b823567ffffffffffffffff80821115610d5b57600080fd5b818501915085601f830112610d6f57600080fd5b813581811115610d7e57600080fd5b86602060c083028501011115610d9357600080fd5b60209290920196919550909350505050565b60008060208385031215610db857600080fd5b823567ffffffffffffffff80821115610dd057600080fd5b818501915085601f830112610de457600080fd5b813581811115610df357600080fd5b86602060a083028501011115610d9357600080fd5b60008060408385031215610e1b57600080fd5b50508035926020909101359150565b600060a08284031215610e3c57600080fd5b50919050565b634e487b7160e01b600052602160045260246000fd5b8151606082019060048110610e7d57634e487b7160e01b600052602160045260246000fd5b80835250602083015160208301526040830151604083015292915050565b600060208284031215610ead57600080fd5b5035919050565b60208082526010908201526f39b2b73232b910109e9037b934b3b4b760811b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215610f0657600080fd5b81356001600160a01b0381168114610f1d57600080fd5b9392505050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561086f5761086f610f24565b600060018201610f5f57610f5f610f24565b5060010190565b6000825160005b81811015610f875760208186018101518583015201610f6d565b506000920191825250919050565b600060208284031215610fa757600080fd5b81518015158114610f1d57600080fd5b600060208284031215610fc957600080fd5b813567ffffffffffffffff81168114610f1d57600080fd5b600060208284031215610ff357600080fd5b505191905056fea2646970667358221220c0241e9efff6cacb5548883e39463986c365c3946a5a393e3484418cfb88e66a64736f6c63430008120033", } // ERC20SwapABI is the input ABI used to generate the binding from. @@ -202,9 +202,9 @@ func (_ERC20Swap *ERC20SwapTransactorRaw) Transact(opts *bind.TransactOpts, meth return _ERC20Swap.Contract.contract.Transact(opts, method, params...) } -// ContractKey is a free data retrieval call binding the contract method 0xed7cbed7. +// ContractKey is a free data retrieval call binding the contract method 0xa76f9f2d. // -// Solidity: function contractKey((bytes32,address,uint64,address,uint64) v) pure returns(bytes32) +// Solidity: function contractKey((bytes32,uint256,address,uint64,address) v) pure returns(bytes32) func (_ERC20Swap *ERC20SwapCaller) ContractKey(opts *bind.CallOpts, v ethv1.ETHSwapVector) ([32]byte, error) { var out []interface{} err := _ERC20Swap.contract.Call(opts, &out, "contractKey", v) @@ -219,23 +219,23 @@ func (_ERC20Swap *ERC20SwapCaller) ContractKey(opts *bind.CallOpts, v ethv1.ETHS } -// ContractKey is a free data retrieval call binding the contract method 0xed7cbed7. +// ContractKey is a free data retrieval call binding the contract method 0xa76f9f2d. // -// Solidity: function contractKey((bytes32,address,uint64,address,uint64) v) pure returns(bytes32) +// Solidity: function contractKey((bytes32,uint256,address,uint64,address) v) pure returns(bytes32) func (_ERC20Swap *ERC20SwapSession) ContractKey(v ethv1.ETHSwapVector) ([32]byte, error) { return _ERC20Swap.Contract.ContractKey(&_ERC20Swap.CallOpts, v) } -// ContractKey is a free data retrieval call binding the contract method 0xed7cbed7. +// ContractKey is a free data retrieval call binding the contract method 0xa76f9f2d. // -// Solidity: function contractKey((bytes32,address,uint64,address,uint64) v) pure returns(bytes32) +// Solidity: function contractKey((bytes32,uint256,address,uint64,address) v) pure returns(bytes32) func (_ERC20Swap *ERC20SwapCallerSession) ContractKey(v ethv1.ETHSwapVector) ([32]byte, error) { return _ERC20Swap.Contract.ContractKey(&_ERC20Swap.CallOpts, v) } -// IsRedeemable is a free data retrieval call binding the contract method 0x7802689d. +// IsRedeemable is a free data retrieval call binding the contract method 0xd5cfd049. // -// Solidity: function isRedeemable((bytes32,address,uint64,address,uint64) v) view returns(bool) +// Solidity: function isRedeemable((bytes32,uint256,address,uint64,address) v) view returns(bool) func (_ERC20Swap *ERC20SwapCaller) IsRedeemable(opts *bind.CallOpts, v ethv1.ETHSwapVector) (bool, error) { var out []interface{} err := _ERC20Swap.contract.Call(opts, &out, "isRedeemable", v) @@ -250,16 +250,16 @@ func (_ERC20Swap *ERC20SwapCaller) IsRedeemable(opts *bind.CallOpts, v ethv1.ETH } -// IsRedeemable is a free data retrieval call binding the contract method 0x7802689d. +// IsRedeemable is a free data retrieval call binding the contract method 0xd5cfd049. // -// Solidity: function isRedeemable((bytes32,address,uint64,address,uint64) v) view returns(bool) +// Solidity: function isRedeemable((bytes32,uint256,address,uint64,address) v) view returns(bool) func (_ERC20Swap *ERC20SwapSession) IsRedeemable(v ethv1.ETHSwapVector) (bool, error) { return _ERC20Swap.Contract.IsRedeemable(&_ERC20Swap.CallOpts, v) } -// IsRedeemable is a free data retrieval call binding the contract method 0x7802689d. +// IsRedeemable is a free data retrieval call binding the contract method 0xd5cfd049. // -// Solidity: function isRedeemable((bytes32,address,uint64,address,uint64) v) view returns(bool) +// Solidity: function isRedeemable((bytes32,uint256,address,uint64,address) v) view returns(bool) func (_ERC20Swap *ERC20SwapCallerSession) IsRedeemable(v ethv1.ETHSwapVector) (bool, error) { return _ERC20Swap.Contract.IsRedeemable(&_ERC20Swap.CallOpts, v) } @@ -295,9 +295,9 @@ func (_ERC20Swap *ERC20SwapCallerSession) SecretValidates(secret [32]byte, secre return _ERC20Swap.Contract.SecretValidates(&_ERC20Swap.CallOpts, secret, secretHash) } -// Status is a free data retrieval call binding the contract method 0x61a16e33. +// Status is a free data retrieval call binding the contract method 0xdb3b419c. // -// Solidity: function status((bytes32,address,uint64,address,uint64) v) view returns((uint8,bytes32,uint256)) +// Solidity: function status((bytes32,uint256,address,uint64,address) v) view returns((uint8,bytes32,uint256)) func (_ERC20Swap *ERC20SwapCaller) Status(opts *bind.CallOpts, v ethv1.ETHSwapVector) (ethv1.ETHSwapStatus, error) { var out []interface{} err := _ERC20Swap.contract.Call(opts, &out, "status", v) @@ -312,16 +312,16 @@ func (_ERC20Swap *ERC20SwapCaller) Status(opts *bind.CallOpts, v ethv1.ETHSwapVe } -// Status is a free data retrieval call binding the contract method 0x61a16e33. +// Status is a free data retrieval call binding the contract method 0xdb3b419c. // -// Solidity: function status((bytes32,address,uint64,address,uint64) v) view returns((uint8,bytes32,uint256)) +// Solidity: function status((bytes32,uint256,address,uint64,address) v) view returns((uint8,bytes32,uint256)) func (_ERC20Swap *ERC20SwapSession) Status(v ethv1.ETHSwapVector) (ethv1.ETHSwapStatus, error) { return _ERC20Swap.Contract.Status(&_ERC20Swap.CallOpts, v) } -// Status is a free data retrieval call binding the contract method 0x61a16e33. +// Status is a free data retrieval call binding the contract method 0xdb3b419c. // -// Solidity: function status((bytes32,address,uint64,address,uint64) v) view returns((uint8,bytes32,uint256)) +// Solidity: function status((bytes32,uint256,address,uint64,address) v) view returns((uint8,bytes32,uint256)) func (_ERC20Swap *ERC20SwapCallerSession) Status(v ethv1.ETHSwapVector) (ethv1.ETHSwapStatus, error) { return _ERC20Swap.Contract.Status(&_ERC20Swap.CallOpts, v) } @@ -388,65 +388,65 @@ func (_ERC20Swap *ERC20SwapCallerSession) TokenAddress() (common.Address, error) return _ERC20Swap.Contract.TokenAddress(&_ERC20Swap.CallOpts) } -// Initiate is a paid mutator transaction binding the contract method 0x64a97bff. +// Initiate is a paid mutator transaction binding the contract method 0x3da59631. // -// Solidity: function initiate((bytes32,address,uint64,address,uint64)[] contracts) payable returns() +// Solidity: function initiate((bytes32,uint256,address,uint64,address)[] contracts) payable returns() func (_ERC20Swap *ERC20SwapTransactor) Initiate(opts *bind.TransactOpts, contracts []ethv1.ETHSwapVector) (*types.Transaction, error) { return _ERC20Swap.contract.Transact(opts, "initiate", contracts) } -// Initiate is a paid mutator transaction binding the contract method 0x64a97bff. +// Initiate is a paid mutator transaction binding the contract method 0x3da59631. // -// Solidity: function initiate((bytes32,address,uint64,address,uint64)[] contracts) payable returns() +// Solidity: function initiate((bytes32,uint256,address,uint64,address)[] contracts) payable returns() func (_ERC20Swap *ERC20SwapSession) Initiate(contracts []ethv1.ETHSwapVector) (*types.Transaction, error) { return _ERC20Swap.Contract.Initiate(&_ERC20Swap.TransactOpts, contracts) } -// Initiate is a paid mutator transaction binding the contract method 0x64a97bff. +// Initiate is a paid mutator transaction binding the contract method 0x3da59631. // -// Solidity: function initiate((bytes32,address,uint64,address,uint64)[] contracts) payable returns() +// Solidity: function initiate((bytes32,uint256,address,uint64,address)[] contracts) payable returns() func (_ERC20Swap *ERC20SwapTransactorSession) Initiate(contracts []ethv1.ETHSwapVector) (*types.Transaction, error) { return _ERC20Swap.Contract.Initiate(&_ERC20Swap.TransactOpts, contracts) } -// Redeem is a paid mutator transaction binding the contract method 0x428b16e1. +// Redeem is a paid mutator transaction binding the contract method 0x23f0388b. // -// Solidity: function redeem(((bytes32,address,uint64,address,uint64),bytes32)[] redemptions) returns() +// Solidity: function redeem(((bytes32,uint256,address,uint64,address),bytes32)[] redemptions) returns() func (_ERC20Swap *ERC20SwapTransactor) Redeem(opts *bind.TransactOpts, redemptions []ethv1.ETHSwapRedemption) (*types.Transaction, error) { return _ERC20Swap.contract.Transact(opts, "redeem", redemptions) } -// Redeem is a paid mutator transaction binding the contract method 0x428b16e1. +// Redeem is a paid mutator transaction binding the contract method 0x23f0388b. // -// Solidity: function redeem(((bytes32,address,uint64,address,uint64),bytes32)[] redemptions) returns() +// Solidity: function redeem(((bytes32,uint256,address,uint64,address),bytes32)[] redemptions) returns() func (_ERC20Swap *ERC20SwapSession) Redeem(redemptions []ethv1.ETHSwapRedemption) (*types.Transaction, error) { return _ERC20Swap.Contract.Redeem(&_ERC20Swap.TransactOpts, redemptions) } -// Redeem is a paid mutator transaction binding the contract method 0x428b16e1. +// Redeem is a paid mutator transaction binding the contract method 0x23f0388b. // -// Solidity: function redeem(((bytes32,address,uint64,address,uint64),bytes32)[] redemptions) returns() +// Solidity: function redeem(((bytes32,uint256,address,uint64,address),bytes32)[] redemptions) returns() func (_ERC20Swap *ERC20SwapTransactorSession) Redeem(redemptions []ethv1.ETHSwapRedemption) (*types.Transaction, error) { return _ERC20Swap.Contract.Redeem(&_ERC20Swap.TransactOpts, redemptions) } -// Refund is a paid mutator transaction binding the contract method 0xd2544c06. +// Refund is a paid mutator transaction binding the contract method 0x8cd8dd97. // -// Solidity: function refund((bytes32,address,uint64,address,uint64) v) returns() +// Solidity: function refund((bytes32,uint256,address,uint64,address) v) returns() func (_ERC20Swap *ERC20SwapTransactor) Refund(opts *bind.TransactOpts, v ethv1.ETHSwapVector) (*types.Transaction, error) { return _ERC20Swap.contract.Transact(opts, "refund", v) } -// Refund is a paid mutator transaction binding the contract method 0xd2544c06. +// Refund is a paid mutator transaction binding the contract method 0x8cd8dd97. // -// Solidity: function refund((bytes32,address,uint64,address,uint64) v) returns() +// Solidity: function refund((bytes32,uint256,address,uint64,address) v) returns() func (_ERC20Swap *ERC20SwapSession) Refund(v ethv1.ETHSwapVector) (*types.Transaction, error) { return _ERC20Swap.Contract.Refund(&_ERC20Swap.TransactOpts, v) } -// Refund is a paid mutator transaction binding the contract method 0xd2544c06. +// Refund is a paid mutator transaction binding the contract method 0x8cd8dd97. // -// Solidity: function refund((bytes32,address,uint64,address,uint64) v) returns() +// Solidity: function refund((bytes32,uint256,address,uint64,address) v) returns() func (_ERC20Swap *ERC20SwapTransactorSession) Refund(v ethv1.ETHSwapVector) (*types.Transaction, error) { return _ERC20Swap.Contract.Refund(&_ERC20Swap.TransactOpts, v) } diff --git a/dex/networks/eth/contracts/ETHSwapV1.sol b/dex/networks/eth/contracts/ETHSwapV1.sol index d1e115b67f..d83d0dff0a 100644 --- a/dex/networks/eth/contracts/ETHSwapV1.sol +++ b/dex/networks/eth/contracts/ETHSwapV1.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: BlueOak-1.0.0 // pragma should be as specific as possible to allow easier validation. -pragma solidity = 0.8.15; +pragma solidity = 0.8.18; // ETHSwap creates a contract to be deployed on an ethereum network. After // deployed, it keeps a record of the state of a contract and enables @@ -50,16 +50,16 @@ contract ETHSwap { // the swap record. struct Vector { bytes32 secretHash; + uint256 value; address initiator; uint64 refundTimestamp; address participant; - uint64 value; } // contractKey generates a key hash which commits to the contract data. The // generated hash is used as a key in the swaps map. function contractKey(Vector calldata v) public pure returns (bytes32) { - return sha256(bytes.concat(v.secretHash, bytes20(v.initiator), bytes20(v.participant), bytes8(v.value), bytes8(v.refundTimestamp))); + return sha256(bytes.concat(v.secretHash, bytes20(v.initiator), bytes20(v.participant), bytes32(v.value), bytes8(v.refundTimestamp))); } // Redemption is the information necessary to redeem a Vector. Since we @@ -137,7 +137,7 @@ contract ETHSwap { swaps[k] = record; - initVal += v.value * 1 gwei; + initVal += v.value; } require(initVal == msg.value, "bad val"); @@ -187,7 +187,11 @@ contract ETHSwap { require(secretValidates(r.secret, r.v.secretHash), "invalid secret"); swaps[k] = r.secret; - amountToRedeem += r.v.value * 1 gwei; + + + // DRAFT TODO: NOOOOOO! This doesn't account for decimals. This is + // WRONG for e.g. USDC. + amountToRedeem += r.v.value; } (bool ok, ) = payable(msg.sender).call{value: amountToRedeem}(""); @@ -221,7 +225,7 @@ contract ETHSwap { swaps[k] = RefundRecord; - (bool ok, ) = payable(v.initiator).call{value: v.value * 1 gwei}(""); + (bool ok, ) = payable(v.initiator).call{value: v.value}(""); require(ok == true, "transfer failed"); } } diff --git a/dex/networks/eth/contracts/v1/BinRuntimeV1.go b/dex/networks/eth/contracts/v1/BinRuntimeV1.go index a7a9d0f326..eda4d68d48 100644 --- a/dex/networks/eth/contracts/v1/BinRuntimeV1.go +++ b/dex/networks/eth/contracts/v1/BinRuntimeV1.go @@ -3,4 +3,4 @@ package v1 -const ETHSwapRuntimeBin = "60806040526004361061007b5760003560e01c80637802689d1161004e5780637802689d1461011b578063d2544c061461013b578063eb84e7f21461015b578063ed7cbed71461019657600080fd5b8063428b16e11461008057806361a16e33146100a257806364a97bff146100d857806377d7e031146100eb575b600080fd5b34801561008c57600080fd5b506100a061009b366004610b6f565b6101b6565b005b3480156100ae57600080fd5b506100c26100bd366004610be4565b610447565b6040516100cf9190610c12565b60405180910390f35b6100a06100e6366004610c55565b610503565b3480156100f757600080fd5b5061010b610106366004610cb8565b61073b565b60405190151581526020016100cf565b34801561012757600080fd5b5061010b610136366004610be4565b6107b5565b34801561014757600080fd5b506100a0610156366004610be4565b6107e8565b34801561016757600080fd5b50610188610176366004610cda565b60006020819052908152604090205481565b6040519081526020016100cf565b3480156101a257600080fd5b506101886101b1366004610be4565b610a4a565b3233146101de5760405162461bcd60e51b81526004016101d590610cf3565b60405180910390fd5b6000805b828110156103b057368484838181106101fd576101fd610d1d565b60c0029190910191503390506102196080830160608401610d33565b6001600160a01b03161461025c5760405162461bcd60e51b815260206004820152600a6024820152691b9bdd08185d5d1a195960b21b60448201526064016101d5565b6000808061026984610b43565b92509250925060008111801561027e57504381105b6102ba5760405162461bcd60e51b815260206004820152600d60248201526c0756e66696c6c6564207377617609c1b60448201526064016101d5565b6102c582853561073b565b156103055760405162461bcd60e51b815260206004820152601060248201526f185b1c9958591e481c995919595b595960821b60448201526064016101d5565b61031460a0850135853561073b565b6103515760405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a59081cd958dc995d60921b60448201526064016101d5565b600083815260208190526040902060a0850180359091556103759060808601610d63565b61038390633b9aca00610da3565b6103979067ffffffffffffffff1687610dd3565b95505050505080806103a890610deb565b9150506101e2565b50604051600090339083908381818185875af1925050503d80600081146103f3576040519150601f19603f3d011682016040523d82523d6000602084013e6103f8565b606091505b50909150506001811515146104415760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b60448201526064016101d5565b50505050565b60408051606081018252600080825260208201819052918101829052908061046e84610b43565b92509250506104986040805160608101909152806000815260006020820181905260409091015290565b816000036104bf578060005b908160038111156104b7576104b7610bfc565b9052506104fb565b600183016104cf578060036104a4565b6104da83863561073b565b156104ef5760028152602081018390526104fb565b60018152604081018290525b949350505050565b3233146105225760405162461bcd60e51b81526004016101d590610cf3565b6000805b828110156106fc573684848381811061054157610541610d1d565b905060a002019050600081608001602081019061055e9190610d63565b67ffffffffffffffff161161059d5760405162461bcd60e51b81526020600482015260056024820152640c081d985b60da1b60448201526064016101d5565b60006105af6060830160408401610d63565b67ffffffffffffffff16116105fa5760405162461bcd60e51b815260206004820152601160248201527003020726566756e6454696d657374616d7607c1b60448201526064016101d5565b600061060582610a4a565b60008181526020819052604090205490915080156106565760405162461bcd60e51b815260206004820152600e60248201526d73776170206e6f7420656d70747960901b60448201526064016101d5565b504361066381843561073b565b156106a15760405162461bcd60e51b815260206004820152600e60248201526d3430b9b41031b7b63634b9b4b7b760911b60448201526064016101d5565b60008281526020819052604090208190556106c260a0840160808501610d63565b6106d090633b9aca00610da3565b6106e49067ffffffffffffffff1686610dd3565b945050505080806106f490610deb565b915050610526565b503481146107365760405162461bcd60e51b8152602060048201526007602482015266189859081d985b60ca1b60448201526064016101d5565b505050565b60008160028460405160200161075391815260200190565b60408051601f198184030181529082905261076d91610e04565b602060405180830381855afa15801561078a573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906107ad9190610e3f565b149392505050565b60008060006107c384610b43565b9250925050806000141580156104fb57506107df82853561073b565b15949350505050565b3233146108075760405162461bcd60e51b81526004016101d590610cf3565b6108176060820160408301610d63565b67ffffffffffffffff164210156108675760405162461bcd60e51b81526020600482015260146024820152731b1bd8dadd1a5b59481b9bdd08195e1c1a5c995960621b60448201526064016101d5565b600080600061087584610b43565b92509250925060008111801561088b5750438111155b6108c95760405162461bcd60e51b815260206004820152600f60248201526e73776170206e6f742061637469766560881b60448201526064016101d5565b6108d482853561073b565b156109195760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c995919595b5959605a1b60448201526064016101d5565b600182016109615760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c99599d5b991959605a1b60448201526064016101d5565b600083815260208181526040808320600019905561098491908701908701610d33565b6001600160a01b031661099d60a0870160808801610d63565b6109ab90633b9aca00610da3565b67ffffffffffffffff1660405160006040518083038185875af1925050503d80600081146109f5576040519150601f19603f3d011682016040523d82523d6000602084013e6109fa565b606091505b5090915050600181151514610a435760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b60448201526064016101d5565b5050505050565b600060028235610a606040850160208601610d33565b60601b846060016020810190610a769190610d33565b60601b610a8960a0870160808801610d63565b60c01b610a9c6060880160408901610d63565b6040805160208101969096526bffffffffffffffffffffffff19948516908601529190921660548401526001600160c01b0319918216606884015260c01b16607082015260780160408051601f1981840301815290829052610afd91610e04565b602060405180830381855afa158015610b1a573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610b3d9190610e3f565b92915050565b600080600080610b5285610a4a565b600081815260208190526040902054909690955085945092505050565b60008060208385031215610b8257600080fd5b823567ffffffffffffffff80821115610b9a57600080fd5b818501915085601f830112610bae57600080fd5b813581811115610bbd57600080fd5b86602060c083028501011115610bd257600080fd5b60209290920196919550909350505050565b600060a08284031215610bf657600080fd5b50919050565b634e487b7160e01b600052602160045260246000fd5b8151606082019060048110610c3757634e487b7160e01b600052602160045260246000fd5b80835250602083015160208301526040830151604083015292915050565b60008060208385031215610c6857600080fd5b823567ffffffffffffffff80821115610c8057600080fd5b818501915085601f830112610c9457600080fd5b813581811115610ca357600080fd5b86602060a083028501011115610bd257600080fd5b60008060408385031215610ccb57600080fd5b50508035926020909101359150565b600060208284031215610cec57600080fd5b5035919050565b60208082526010908201526f39b2b73232b910109e9037b934b3b4b760811b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215610d4557600080fd5b81356001600160a01b0381168114610d5c57600080fd5b9392505050565b600060208284031215610d7557600080fd5b813567ffffffffffffffff81168114610d5c57600080fd5b634e487b7160e01b600052601160045260246000fd5b600067ffffffffffffffff80831681851681830481118215151615610dca57610dca610d8d565b02949350505050565b60008219821115610de657610de6610d8d565b500190565b600060018201610dfd57610dfd610d8d565b5060010190565b6000825160005b81811015610e255760208186018101518583015201610e0b565b81811115610e34576000828501525b509190910192915050565b600060208284031215610e5157600080fd5b505191905056fea2646970667358221220d735868682c69bb69ed936f11e2f136e7da44cb347e0b1d67acd1e088ea13dd664736f6c634300080f0033" +const ETHSwapRuntimeBin = "60806040526004361061007b5760003560e01c8063a76f9f2d1161004e578063a76f9f2d1461010a578063d5cfd04914610138578063db3b419c14610158578063eb84e7f21461018557600080fd5b806323f0388b146100805780633da59631146100a257806377d7e031146100b55780638cd8dd97146100ea575b600080fd5b34801561008c57600080fd5b506100a061009b366004610adb565b6101b2565b005b6100a06100b0366004610b50565b610420565b3480156100c157600080fd5b506100d56100d0366004610bb3565b61061c565b60405190151581526020015b60405180910390f35b3480156100f657600080fd5b506100a0610105366004610bd5565b610698565b34801561011657600080fd5b5061012a610125366004610bd5565b6108d8565b6040519081526020016100e1565b34801561014457600080fd5b506100d5610153366004610bd5565b6109c0565b34801561016457600080fd5b50610178610173366004610bd5565b6109f4565b6040516100e19190610c03565b34801561019157600080fd5b5061012a6101a0366004610c46565b60006020819052908152604090205481565b3233146101da5760405162461bcd60e51b81526004016101d190610c5f565b60405180910390fd5b6000805b8281101561038957368484838181106101f9576101f9610c89565b60c00291909101915033905061021560a0830160808401610c9f565b6001600160a01b0316146102585760405162461bcd60e51b815260206004820152600a6024820152691b9bdd08185d5d1a195960b21b60448201526064016101d1565b6000808061026584610aaf565b92509250925060008111801561027a57504381105b6102b65760405162461bcd60e51b815260206004820152600d60248201526c0756e66696c6c6564207377617609c1b60448201526064016101d1565b6102c182853561061c565b156103015760405162461bcd60e51b815260206004820152601060248201526f185b1c9958591e481c995919595b595960821b60448201526064016101d1565b61031060a0850135853561061c565b61034d5760405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a59081cd958dc995d60921b60448201526064016101d1565b60008381526020818152604090912060a086013590556103709085013587610ce5565b955050505050808061038190610cf8565b9150506101de565b50604051600090339083908381818185875af1925050503d80600081146103cc576040519150601f19603f3d011682016040523d82523d6000602084013e6103d1565b606091505b509091505060018115151461041a5760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b60448201526064016101d1565b50505050565b32331461043f5760405162461bcd60e51b81526004016101d190610c5f565b6000805b828110156105dd573684848381811061045e5761045e610c89565b905060a00201905060008160200135116104a25760405162461bcd60e51b81526020600482015260056024820152640c081d985b60da1b60448201526064016101d1565b60006104b46080830160608401610d11565b67ffffffffffffffff16116104ff5760405162461bcd60e51b815260206004820152601160248201527003020726566756e6454696d657374616d7607c1b60448201526064016101d1565b600061050a826108d8565b600081815260208190526040902054909150801561055b5760405162461bcd60e51b815260206004820152600e60248201526d73776170206e6f7420656d70747960901b60448201526064016101d1565b504361056881843561061c565b156105a65760405162461bcd60e51b815260206004820152600e60248201526d3430b9b41031b7b63634b9b4b7b760911b60448201526064016101d1565b6000828152602081815260409091208290556105c59084013586610ce5565b945050505080806105d590610cf8565b915050610443565b503481146106175760405162461bcd60e51b8152602060048201526007602482015266189859081d985b60ca1b60448201526064016101d1565b505050565b60008160028460405160200161063491815260200190565b60408051601f198184030181529082905261064e91610d3b565b602060405180830381855afa15801561066b573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061068e9190610d6a565b1490505b92915050565b3233146106b75760405162461bcd60e51b81526004016101d190610c5f565b6106c76080820160608301610d11565b67ffffffffffffffff164210156107175760405162461bcd60e51b81526020600482015260146024820152731b1bd8dadd1a5b59481b9bdd08195e1c1a5c995960621b60448201526064016101d1565b600080600061072584610aaf565b92509250925060008111801561073b5750438111155b6107795760405162461bcd60e51b815260206004820152600f60248201526e73776170206e6f742061637469766560881b60448201526064016101d1565b61078482853561061c565b156107c95760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c995919595b5959605a1b60448201526064016101d1565b600182016108115760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c99599d5b991959605a1b60448201526064016101d1565b60008381526020819052604080822060001990556108359060608701908701610c9f565b6001600160a01b0316856020013560405160006040518083038185875af1925050503d8060008114610883576040519150601f19603f3d011682016040523d82523d6000602084013e610888565b606091505b50909150506001811515146108d15760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b60448201526064016101d1565b5050505050565b6000600282356108ee6060850160408601610c9f565b60601b61090160a0860160808701610c9f565b60601b856020013560001b86606001602081019061091f9190610d11565b6040805160208101969096526bffffffffffffffffffffffff199485169086015292909116605484015260688301526001600160c01b031960c09190911b16608882015260900160408051601f198184030181529082905261098091610d3b565b602060405180830381855afa15801561099d573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906106929190610d6a565b60008060006109ce84610aaf565b9250925050806000141580156109ec57506109ea82853561061c565b155b949350505050565b604080516060810182526000808252602082018190529181018290529080610a1b84610aaf565b9250925050610a456040805160608101909152806000815260006020820181905260409091015290565b81600003610a6c578060005b90816003811115610a6457610a64610bed565b9052506109ec565b60018301610a7c57806003610a51565b610a8783863561061c565b15610a9c5760028152602081018390526109ec565b6001815260408101919091529392505050565b600080600080610abe856108d8565b600081815260208190526040902054909690955085945092505050565b60008060208385031215610aee57600080fd5b823567ffffffffffffffff80821115610b0657600080fd5b818501915085601f830112610b1a57600080fd5b813581811115610b2957600080fd5b86602060c083028501011115610b3e57600080fd5b60209290920196919550909350505050565b60008060208385031215610b6357600080fd5b823567ffffffffffffffff80821115610b7b57600080fd5b818501915085601f830112610b8f57600080fd5b813581811115610b9e57600080fd5b86602060a083028501011115610b3e57600080fd5b60008060408385031215610bc657600080fd5b50508035926020909101359150565b600060a08284031215610be757600080fd5b50919050565b634e487b7160e01b600052602160045260246000fd5b8151606082019060048110610c2857634e487b7160e01b600052602160045260246000fd5b80835250602083015160208301526040830151604083015292915050565b600060208284031215610c5857600080fd5b5035919050565b60208082526010908201526f39b2b73232b910109e9037b934b3b4b760811b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215610cb157600080fd5b81356001600160a01b0381168114610cc857600080fd5b9392505050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561069257610692610ccf565b600060018201610d0a57610d0a610ccf565b5060010190565b600060208284031215610d2357600080fd5b813567ffffffffffffffff81168114610cc857600080fd5b6000825160005b81811015610d5c5760208186018101518583015201610d42565b506000920191825250919050565b600060208284031215610d7c57600080fd5b505191905056fea2646970667358221220d06fb8ed23d4808c2b9f4f691e0abd03030305c1af9428077386f96e11f2643364736f6c63430008120033" diff --git a/dex/networks/eth/contracts/v1/contract.go b/dex/networks/eth/contracts/v1/contract.go index 07de2ac59e..86e9dc9982 100644 --- a/dex/networks/eth/contracts/v1/contract.go +++ b/dex/networks/eth/contracts/v1/contract.go @@ -44,16 +44,16 @@ type ETHSwapStatus struct { // ETHSwapVector is an auto generated low-level Go binding around an user-defined struct. type ETHSwapVector struct { SecretHash [32]byte + Value *big.Int Initiator common.Address RefundTimestamp uint64 Participant common.Address - Value uint64 } // ETHSwapMetaData contains all meta data concerning the ETHSwap contract. var ETHSwapMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"value\",\"type\":\"uint64\"}],\"internalType\":\"structETHSwap.Vector\",\"name\":\"v\",\"type\":\"tuple\"}],\"name\":\"contractKey\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"value\",\"type\":\"uint64\"}],\"internalType\":\"structETHSwap.Vector[]\",\"name\":\"contracts\",\"type\":\"tuple[]\"}],\"name\":\"initiate\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"value\",\"type\":\"uint64\"}],\"internalType\":\"structETHSwap.Vector\",\"name\":\"v\",\"type\":\"tuple\"}],\"name\":\"isRedeemable\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"value\",\"type\":\"uint64\"}],\"internalType\":\"structETHSwap.Vector\",\"name\":\"v\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"secret\",\"type\":\"bytes32\"}],\"internalType\":\"structETHSwap.Redemption[]\",\"name\":\"redemptions\",\"type\":\"tuple[]\"}],\"name\":\"redeem\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"value\",\"type\":\"uint64\"}],\"internalType\":\"structETHSwap.Vector\",\"name\":\"v\",\"type\":\"tuple\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"secret\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"}],\"name\":\"secretValidates\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"value\",\"type\":\"uint64\"}],\"internalType\":\"structETHSwap.Vector\",\"name\":\"v\",\"type\":\"tuple\"}],\"name\":\"status\",\"outputs\":[{\"components\":[{\"internalType\":\"enumETHSwap.Step\",\"name\":\"step\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"secret\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"internalType\":\"structETHSwap.Status\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"swaps\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b50610e8e806100206000396000f3fe60806040526004361061007b5760003560e01c80637802689d1161004e5780637802689d1461011b578063d2544c061461013b578063eb84e7f21461015b578063ed7cbed71461019657600080fd5b8063428b16e11461008057806361a16e33146100a257806364a97bff146100d857806377d7e031146100eb575b600080fd5b34801561008c57600080fd5b506100a061009b366004610b6f565b6101b6565b005b3480156100ae57600080fd5b506100c26100bd366004610be4565b610447565b6040516100cf9190610c12565b60405180910390f35b6100a06100e6366004610c55565b610503565b3480156100f757600080fd5b5061010b610106366004610cb8565b61073b565b60405190151581526020016100cf565b34801561012757600080fd5b5061010b610136366004610be4565b6107b5565b34801561014757600080fd5b506100a0610156366004610be4565b6107e8565b34801561016757600080fd5b50610188610176366004610cda565b60006020819052908152604090205481565b6040519081526020016100cf565b3480156101a257600080fd5b506101886101b1366004610be4565b610a4a565b3233146101de5760405162461bcd60e51b81526004016101d590610cf3565b60405180910390fd5b6000805b828110156103b057368484838181106101fd576101fd610d1d565b60c0029190910191503390506102196080830160608401610d33565b6001600160a01b03161461025c5760405162461bcd60e51b815260206004820152600a6024820152691b9bdd08185d5d1a195960b21b60448201526064016101d5565b6000808061026984610b43565b92509250925060008111801561027e57504381105b6102ba5760405162461bcd60e51b815260206004820152600d60248201526c0756e66696c6c6564207377617609c1b60448201526064016101d5565b6102c582853561073b565b156103055760405162461bcd60e51b815260206004820152601060248201526f185b1c9958591e481c995919595b595960821b60448201526064016101d5565b61031460a0850135853561073b565b6103515760405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a59081cd958dc995d60921b60448201526064016101d5565b600083815260208190526040902060a0850180359091556103759060808601610d63565b61038390633b9aca00610da3565b6103979067ffffffffffffffff1687610dd3565b95505050505080806103a890610deb565b9150506101e2565b50604051600090339083908381818185875af1925050503d80600081146103f3576040519150601f19603f3d011682016040523d82523d6000602084013e6103f8565b606091505b50909150506001811515146104415760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b60448201526064016101d5565b50505050565b60408051606081018252600080825260208201819052918101829052908061046e84610b43565b92509250506104986040805160608101909152806000815260006020820181905260409091015290565b816000036104bf578060005b908160038111156104b7576104b7610bfc565b9052506104fb565b600183016104cf578060036104a4565b6104da83863561073b565b156104ef5760028152602081018390526104fb565b60018152604081018290525b949350505050565b3233146105225760405162461bcd60e51b81526004016101d590610cf3565b6000805b828110156106fc573684848381811061054157610541610d1d565b905060a002019050600081608001602081019061055e9190610d63565b67ffffffffffffffff161161059d5760405162461bcd60e51b81526020600482015260056024820152640c081d985b60da1b60448201526064016101d5565b60006105af6060830160408401610d63565b67ffffffffffffffff16116105fa5760405162461bcd60e51b815260206004820152601160248201527003020726566756e6454696d657374616d7607c1b60448201526064016101d5565b600061060582610a4a565b60008181526020819052604090205490915080156106565760405162461bcd60e51b815260206004820152600e60248201526d73776170206e6f7420656d70747960901b60448201526064016101d5565b504361066381843561073b565b156106a15760405162461bcd60e51b815260206004820152600e60248201526d3430b9b41031b7b63634b9b4b7b760911b60448201526064016101d5565b60008281526020819052604090208190556106c260a0840160808501610d63565b6106d090633b9aca00610da3565b6106e49067ffffffffffffffff1686610dd3565b945050505080806106f490610deb565b915050610526565b503481146107365760405162461bcd60e51b8152602060048201526007602482015266189859081d985b60ca1b60448201526064016101d5565b505050565b60008160028460405160200161075391815260200190565b60408051601f198184030181529082905261076d91610e04565b602060405180830381855afa15801561078a573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906107ad9190610e3f565b149392505050565b60008060006107c384610b43565b9250925050806000141580156104fb57506107df82853561073b565b15949350505050565b3233146108075760405162461bcd60e51b81526004016101d590610cf3565b6108176060820160408301610d63565b67ffffffffffffffff164210156108675760405162461bcd60e51b81526020600482015260146024820152731b1bd8dadd1a5b59481b9bdd08195e1c1a5c995960621b60448201526064016101d5565b600080600061087584610b43565b92509250925060008111801561088b5750438111155b6108c95760405162461bcd60e51b815260206004820152600f60248201526e73776170206e6f742061637469766560881b60448201526064016101d5565b6108d482853561073b565b156109195760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c995919595b5959605a1b60448201526064016101d5565b600182016109615760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c99599d5b991959605a1b60448201526064016101d5565b600083815260208181526040808320600019905561098491908701908701610d33565b6001600160a01b031661099d60a0870160808801610d63565b6109ab90633b9aca00610da3565b67ffffffffffffffff1660405160006040518083038185875af1925050503d80600081146109f5576040519150601f19603f3d011682016040523d82523d6000602084013e6109fa565b606091505b5090915050600181151514610a435760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b60448201526064016101d5565b5050505050565b600060028235610a606040850160208601610d33565b60601b846060016020810190610a769190610d33565b60601b610a8960a0870160808801610d63565b60c01b610a9c6060880160408901610d63565b6040805160208101969096526bffffffffffffffffffffffff19948516908601529190921660548401526001600160c01b0319918216606884015260c01b16607082015260780160408051601f1981840301815290829052610afd91610e04565b602060405180830381855afa158015610b1a573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610b3d9190610e3f565b92915050565b600080600080610b5285610a4a565b600081815260208190526040902054909690955085945092505050565b60008060208385031215610b8257600080fd5b823567ffffffffffffffff80821115610b9a57600080fd5b818501915085601f830112610bae57600080fd5b813581811115610bbd57600080fd5b86602060c083028501011115610bd257600080fd5b60209290920196919550909350505050565b600060a08284031215610bf657600080fd5b50919050565b634e487b7160e01b600052602160045260246000fd5b8151606082019060048110610c3757634e487b7160e01b600052602160045260246000fd5b80835250602083015160208301526040830151604083015292915050565b60008060208385031215610c6857600080fd5b823567ffffffffffffffff80821115610c8057600080fd5b818501915085601f830112610c9457600080fd5b813581811115610ca357600080fd5b86602060a083028501011115610bd257600080fd5b60008060408385031215610ccb57600080fd5b50508035926020909101359150565b600060208284031215610cec57600080fd5b5035919050565b60208082526010908201526f39b2b73232b910109e9037b934b3b4b760811b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215610d4557600080fd5b81356001600160a01b0381168114610d5c57600080fd5b9392505050565b600060208284031215610d7557600080fd5b813567ffffffffffffffff81168114610d5c57600080fd5b634e487b7160e01b600052601160045260246000fd5b600067ffffffffffffffff80831681851681830481118215151615610dca57610dca610d8d565b02949350505050565b60008219821115610de657610de6610d8d565b500190565b600060018201610dfd57610dfd610d8d565b5060010190565b6000825160005b81811015610e255760208186018101518583015201610e0b565b81811115610e34576000828501525b509190910192915050565b600060208284031215610e5157600080fd5b505191905056fea2646970667358221220d735868682c69bb69ed936f11e2f136e7da44cb347e0b1d67acd1e088ea13dd664736f6c634300080f0033", + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"}],\"internalType\":\"structETHSwap.Vector\",\"name\":\"v\",\"type\":\"tuple\"}],\"name\":\"contractKey\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"}],\"internalType\":\"structETHSwap.Vector[]\",\"name\":\"contracts\",\"type\":\"tuple[]\"}],\"name\":\"initiate\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"}],\"internalType\":\"structETHSwap.Vector\",\"name\":\"v\",\"type\":\"tuple\"}],\"name\":\"isRedeemable\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"}],\"internalType\":\"structETHSwap.Vector\",\"name\":\"v\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"secret\",\"type\":\"bytes32\"}],\"internalType\":\"structETHSwap.Redemption[]\",\"name\":\"redemptions\",\"type\":\"tuple[]\"}],\"name\":\"redeem\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"}],\"internalType\":\"structETHSwap.Vector\",\"name\":\"v\",\"type\":\"tuple\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"secret\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"}],\"name\":\"secretValidates\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"secretHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"refundTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"participant\",\"type\":\"address\"}],\"internalType\":\"structETHSwap.Vector\",\"name\":\"v\",\"type\":\"tuple\"}],\"name\":\"status\",\"outputs\":[{\"components\":[{\"internalType\":\"enumETHSwap.Step\",\"name\":\"step\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"secret\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"internalType\":\"structETHSwap.Status\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"swaps\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b50610db9806100206000396000f3fe60806040526004361061007b5760003560e01c8063a76f9f2d1161004e578063a76f9f2d1461010a578063d5cfd04914610138578063db3b419c14610158578063eb84e7f21461018557600080fd5b806323f0388b146100805780633da59631146100a257806377d7e031146100b55780638cd8dd97146100ea575b600080fd5b34801561008c57600080fd5b506100a061009b366004610adb565b6101b2565b005b6100a06100b0366004610b50565b610420565b3480156100c157600080fd5b506100d56100d0366004610bb3565b61061c565b60405190151581526020015b60405180910390f35b3480156100f657600080fd5b506100a0610105366004610bd5565b610698565b34801561011657600080fd5b5061012a610125366004610bd5565b6108d8565b6040519081526020016100e1565b34801561014457600080fd5b506100d5610153366004610bd5565b6109c0565b34801561016457600080fd5b50610178610173366004610bd5565b6109f4565b6040516100e19190610c03565b34801561019157600080fd5b5061012a6101a0366004610c46565b60006020819052908152604090205481565b3233146101da5760405162461bcd60e51b81526004016101d190610c5f565b60405180910390fd5b6000805b8281101561038957368484838181106101f9576101f9610c89565b60c00291909101915033905061021560a0830160808401610c9f565b6001600160a01b0316146102585760405162461bcd60e51b815260206004820152600a6024820152691b9bdd08185d5d1a195960b21b60448201526064016101d1565b6000808061026584610aaf565b92509250925060008111801561027a57504381105b6102b65760405162461bcd60e51b815260206004820152600d60248201526c0756e66696c6c6564207377617609c1b60448201526064016101d1565b6102c182853561061c565b156103015760405162461bcd60e51b815260206004820152601060248201526f185b1c9958591e481c995919595b595960821b60448201526064016101d1565b61031060a0850135853561061c565b61034d5760405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a59081cd958dc995d60921b60448201526064016101d1565b60008381526020818152604090912060a086013590556103709085013587610ce5565b955050505050808061038190610cf8565b9150506101de565b50604051600090339083908381818185875af1925050503d80600081146103cc576040519150601f19603f3d011682016040523d82523d6000602084013e6103d1565b606091505b509091505060018115151461041a5760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b60448201526064016101d1565b50505050565b32331461043f5760405162461bcd60e51b81526004016101d190610c5f565b6000805b828110156105dd573684848381811061045e5761045e610c89565b905060a00201905060008160200135116104a25760405162461bcd60e51b81526020600482015260056024820152640c081d985b60da1b60448201526064016101d1565b60006104b46080830160608401610d11565b67ffffffffffffffff16116104ff5760405162461bcd60e51b815260206004820152601160248201527003020726566756e6454696d657374616d7607c1b60448201526064016101d1565b600061050a826108d8565b600081815260208190526040902054909150801561055b5760405162461bcd60e51b815260206004820152600e60248201526d73776170206e6f7420656d70747960901b60448201526064016101d1565b504361056881843561061c565b156105a65760405162461bcd60e51b815260206004820152600e60248201526d3430b9b41031b7b63634b9b4b7b760911b60448201526064016101d1565b6000828152602081815260409091208290556105c59084013586610ce5565b945050505080806105d590610cf8565b915050610443565b503481146106175760405162461bcd60e51b8152602060048201526007602482015266189859081d985b60ca1b60448201526064016101d1565b505050565b60008160028460405160200161063491815260200190565b60408051601f198184030181529082905261064e91610d3b565b602060405180830381855afa15801561066b573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061068e9190610d6a565b1490505b92915050565b3233146106b75760405162461bcd60e51b81526004016101d190610c5f565b6106c76080820160608301610d11565b67ffffffffffffffff164210156107175760405162461bcd60e51b81526020600482015260146024820152731b1bd8dadd1a5b59481b9bdd08195e1c1a5c995960621b60448201526064016101d1565b600080600061072584610aaf565b92509250925060008111801561073b5750438111155b6107795760405162461bcd60e51b815260206004820152600f60248201526e73776170206e6f742061637469766560881b60448201526064016101d1565b61078482853561061c565b156107c95760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c995919595b5959605a1b60448201526064016101d1565b600182016108115760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c99599d5b991959605a1b60448201526064016101d1565b60008381526020819052604080822060001990556108359060608701908701610c9f565b6001600160a01b0316856020013560405160006040518083038185875af1925050503d8060008114610883576040519150601f19603f3d011682016040523d82523d6000602084013e610888565b606091505b50909150506001811515146108d15760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b60448201526064016101d1565b5050505050565b6000600282356108ee6060850160408601610c9f565b60601b61090160a0860160808701610c9f565b60601b856020013560001b86606001602081019061091f9190610d11565b6040805160208101969096526bffffffffffffffffffffffff199485169086015292909116605484015260688301526001600160c01b031960c09190911b16608882015260900160408051601f198184030181529082905261098091610d3b565b602060405180830381855afa15801561099d573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906106929190610d6a565b60008060006109ce84610aaf565b9250925050806000141580156109ec57506109ea82853561061c565b155b949350505050565b604080516060810182526000808252602082018190529181018290529080610a1b84610aaf565b9250925050610a456040805160608101909152806000815260006020820181905260409091015290565b81600003610a6c578060005b90816003811115610a6457610a64610bed565b9052506109ec565b60018301610a7c57806003610a51565b610a8783863561061c565b15610a9c5760028152602081018390526109ec565b6001815260408101919091529392505050565b600080600080610abe856108d8565b600081815260208190526040902054909690955085945092505050565b60008060208385031215610aee57600080fd5b823567ffffffffffffffff80821115610b0657600080fd5b818501915085601f830112610b1a57600080fd5b813581811115610b2957600080fd5b86602060c083028501011115610b3e57600080fd5b60209290920196919550909350505050565b60008060208385031215610b6357600080fd5b823567ffffffffffffffff80821115610b7b57600080fd5b818501915085601f830112610b8f57600080fd5b813581811115610b9e57600080fd5b86602060a083028501011115610b3e57600080fd5b60008060408385031215610bc657600080fd5b50508035926020909101359150565b600060a08284031215610be757600080fd5b50919050565b634e487b7160e01b600052602160045260246000fd5b8151606082019060048110610c2857634e487b7160e01b600052602160045260246000fd5b80835250602083015160208301526040830151604083015292915050565b600060208284031215610c5857600080fd5b5035919050565b60208082526010908201526f39b2b73232b910109e9037b934b3b4b760811b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215610cb157600080fd5b81356001600160a01b0381168114610cc857600080fd5b9392505050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561069257610692610ccf565b600060018201610d0a57610d0a610ccf565b5060010190565b600060208284031215610d2357600080fd5b813567ffffffffffffffff81168114610cc857600080fd5b6000825160005b81811015610d5c5760208186018101518583015201610d42565b506000920191825250919050565b600060208284031215610d7c57600080fd5b505191905056fea2646970667358221220d06fb8ed23d4808c2b9f4f691e0abd03030305c1af9428077386f96e11f2643364736f6c63430008120033", } // ETHSwapABI is the input ABI used to generate the binding from. @@ -223,9 +223,9 @@ func (_ETHSwap *ETHSwapTransactorRaw) Transact(opts *bind.TransactOpts, method s return _ETHSwap.Contract.contract.Transact(opts, method, params...) } -// ContractKey is a free data retrieval call binding the contract method 0xed7cbed7. +// ContractKey is a free data retrieval call binding the contract method 0xa76f9f2d. // -// Solidity: function contractKey((bytes32,address,uint64,address,uint64) v) pure returns(bytes32) +// Solidity: function contractKey((bytes32,uint256,address,uint64,address) v) pure returns(bytes32) func (_ETHSwap *ETHSwapCaller) ContractKey(opts *bind.CallOpts, v ETHSwapVector) ([32]byte, error) { var out []interface{} err := _ETHSwap.contract.Call(opts, &out, "contractKey", v) @@ -240,23 +240,23 @@ func (_ETHSwap *ETHSwapCaller) ContractKey(opts *bind.CallOpts, v ETHSwapVector) } -// ContractKey is a free data retrieval call binding the contract method 0xed7cbed7. +// ContractKey is a free data retrieval call binding the contract method 0xa76f9f2d. // -// Solidity: function contractKey((bytes32,address,uint64,address,uint64) v) pure returns(bytes32) +// Solidity: function contractKey((bytes32,uint256,address,uint64,address) v) pure returns(bytes32) func (_ETHSwap *ETHSwapSession) ContractKey(v ETHSwapVector) ([32]byte, error) { return _ETHSwap.Contract.ContractKey(&_ETHSwap.CallOpts, v) } -// ContractKey is a free data retrieval call binding the contract method 0xed7cbed7. +// ContractKey is a free data retrieval call binding the contract method 0xa76f9f2d. // -// Solidity: function contractKey((bytes32,address,uint64,address,uint64) v) pure returns(bytes32) +// Solidity: function contractKey((bytes32,uint256,address,uint64,address) v) pure returns(bytes32) func (_ETHSwap *ETHSwapCallerSession) ContractKey(v ETHSwapVector) ([32]byte, error) { return _ETHSwap.Contract.ContractKey(&_ETHSwap.CallOpts, v) } -// IsRedeemable is a free data retrieval call binding the contract method 0x7802689d. +// IsRedeemable is a free data retrieval call binding the contract method 0xd5cfd049. // -// Solidity: function isRedeemable((bytes32,address,uint64,address,uint64) v) view returns(bool) +// Solidity: function isRedeemable((bytes32,uint256,address,uint64,address) v) view returns(bool) func (_ETHSwap *ETHSwapCaller) IsRedeemable(opts *bind.CallOpts, v ETHSwapVector) (bool, error) { var out []interface{} err := _ETHSwap.contract.Call(opts, &out, "isRedeemable", v) @@ -271,16 +271,16 @@ func (_ETHSwap *ETHSwapCaller) IsRedeemable(opts *bind.CallOpts, v ETHSwapVector } -// IsRedeemable is a free data retrieval call binding the contract method 0x7802689d. +// IsRedeemable is a free data retrieval call binding the contract method 0xd5cfd049. // -// Solidity: function isRedeemable((bytes32,address,uint64,address,uint64) v) view returns(bool) +// Solidity: function isRedeemable((bytes32,uint256,address,uint64,address) v) view returns(bool) func (_ETHSwap *ETHSwapSession) IsRedeemable(v ETHSwapVector) (bool, error) { return _ETHSwap.Contract.IsRedeemable(&_ETHSwap.CallOpts, v) } -// IsRedeemable is a free data retrieval call binding the contract method 0x7802689d. +// IsRedeemable is a free data retrieval call binding the contract method 0xd5cfd049. // -// Solidity: function isRedeemable((bytes32,address,uint64,address,uint64) v) view returns(bool) +// Solidity: function isRedeemable((bytes32,uint256,address,uint64,address) v) view returns(bool) func (_ETHSwap *ETHSwapCallerSession) IsRedeemable(v ETHSwapVector) (bool, error) { return _ETHSwap.Contract.IsRedeemable(&_ETHSwap.CallOpts, v) } @@ -316,9 +316,9 @@ func (_ETHSwap *ETHSwapCallerSession) SecretValidates(secret [32]byte, secretHas return _ETHSwap.Contract.SecretValidates(&_ETHSwap.CallOpts, secret, secretHash) } -// Status is a free data retrieval call binding the contract method 0x61a16e33. +// Status is a free data retrieval call binding the contract method 0xdb3b419c. // -// Solidity: function status((bytes32,address,uint64,address,uint64) v) view returns((uint8,bytes32,uint256)) +// Solidity: function status((bytes32,uint256,address,uint64,address) v) view returns((uint8,bytes32,uint256)) func (_ETHSwap *ETHSwapCaller) Status(opts *bind.CallOpts, v ETHSwapVector) (ETHSwapStatus, error) { var out []interface{} err := _ETHSwap.contract.Call(opts, &out, "status", v) @@ -333,16 +333,16 @@ func (_ETHSwap *ETHSwapCaller) Status(opts *bind.CallOpts, v ETHSwapVector) (ETH } -// Status is a free data retrieval call binding the contract method 0x61a16e33. +// Status is a free data retrieval call binding the contract method 0xdb3b419c. // -// Solidity: function status((bytes32,address,uint64,address,uint64) v) view returns((uint8,bytes32,uint256)) +// Solidity: function status((bytes32,uint256,address,uint64,address) v) view returns((uint8,bytes32,uint256)) func (_ETHSwap *ETHSwapSession) Status(v ETHSwapVector) (ETHSwapStatus, error) { return _ETHSwap.Contract.Status(&_ETHSwap.CallOpts, v) } -// Status is a free data retrieval call binding the contract method 0x61a16e33. +// Status is a free data retrieval call binding the contract method 0xdb3b419c. // -// Solidity: function status((bytes32,address,uint64,address,uint64) v) view returns((uint8,bytes32,uint256)) +// Solidity: function status((bytes32,uint256,address,uint64,address) v) view returns((uint8,bytes32,uint256)) func (_ETHSwap *ETHSwapCallerSession) Status(v ETHSwapVector) (ETHSwapStatus, error) { return _ETHSwap.Contract.Status(&_ETHSwap.CallOpts, v) } @@ -378,65 +378,65 @@ func (_ETHSwap *ETHSwapCallerSession) Swaps(arg0 [32]byte) ([32]byte, error) { return _ETHSwap.Contract.Swaps(&_ETHSwap.CallOpts, arg0) } -// Initiate is a paid mutator transaction binding the contract method 0x64a97bff. +// Initiate is a paid mutator transaction binding the contract method 0x3da59631. // -// Solidity: function initiate((bytes32,address,uint64,address,uint64)[] contracts) payable returns() +// Solidity: function initiate((bytes32,uint256,address,uint64,address)[] contracts) payable returns() func (_ETHSwap *ETHSwapTransactor) Initiate(opts *bind.TransactOpts, contracts []ETHSwapVector) (*types.Transaction, error) { return _ETHSwap.contract.Transact(opts, "initiate", contracts) } -// Initiate is a paid mutator transaction binding the contract method 0x64a97bff. +// Initiate is a paid mutator transaction binding the contract method 0x3da59631. // -// Solidity: function initiate((bytes32,address,uint64,address,uint64)[] contracts) payable returns() +// Solidity: function initiate((bytes32,uint256,address,uint64,address)[] contracts) payable returns() func (_ETHSwap *ETHSwapSession) Initiate(contracts []ETHSwapVector) (*types.Transaction, error) { return _ETHSwap.Contract.Initiate(&_ETHSwap.TransactOpts, contracts) } -// Initiate is a paid mutator transaction binding the contract method 0x64a97bff. +// Initiate is a paid mutator transaction binding the contract method 0x3da59631. // -// Solidity: function initiate((bytes32,address,uint64,address,uint64)[] contracts) payable returns() +// Solidity: function initiate((bytes32,uint256,address,uint64,address)[] contracts) payable returns() func (_ETHSwap *ETHSwapTransactorSession) Initiate(contracts []ETHSwapVector) (*types.Transaction, error) { return _ETHSwap.Contract.Initiate(&_ETHSwap.TransactOpts, contracts) } -// Redeem is a paid mutator transaction binding the contract method 0x428b16e1. +// Redeem is a paid mutator transaction binding the contract method 0x23f0388b. // -// Solidity: function redeem(((bytes32,address,uint64,address,uint64),bytes32)[] redemptions) returns() +// Solidity: function redeem(((bytes32,uint256,address,uint64,address),bytes32)[] redemptions) returns() func (_ETHSwap *ETHSwapTransactor) Redeem(opts *bind.TransactOpts, redemptions []ETHSwapRedemption) (*types.Transaction, error) { return _ETHSwap.contract.Transact(opts, "redeem", redemptions) } -// Redeem is a paid mutator transaction binding the contract method 0x428b16e1. +// Redeem is a paid mutator transaction binding the contract method 0x23f0388b. // -// Solidity: function redeem(((bytes32,address,uint64,address,uint64),bytes32)[] redemptions) returns() +// Solidity: function redeem(((bytes32,uint256,address,uint64,address),bytes32)[] redemptions) returns() func (_ETHSwap *ETHSwapSession) Redeem(redemptions []ETHSwapRedemption) (*types.Transaction, error) { return _ETHSwap.Contract.Redeem(&_ETHSwap.TransactOpts, redemptions) } -// Redeem is a paid mutator transaction binding the contract method 0x428b16e1. +// Redeem is a paid mutator transaction binding the contract method 0x23f0388b. // -// Solidity: function redeem(((bytes32,address,uint64,address,uint64),bytes32)[] redemptions) returns() +// Solidity: function redeem(((bytes32,uint256,address,uint64,address),bytes32)[] redemptions) returns() func (_ETHSwap *ETHSwapTransactorSession) Redeem(redemptions []ETHSwapRedemption) (*types.Transaction, error) { return _ETHSwap.Contract.Redeem(&_ETHSwap.TransactOpts, redemptions) } -// Refund is a paid mutator transaction binding the contract method 0xd2544c06. +// Refund is a paid mutator transaction binding the contract method 0x8cd8dd97. // -// Solidity: function refund((bytes32,address,uint64,address,uint64) v) returns() +// Solidity: function refund((bytes32,uint256,address,uint64,address) v) returns() func (_ETHSwap *ETHSwapTransactor) Refund(opts *bind.TransactOpts, v ETHSwapVector) (*types.Transaction, error) { return _ETHSwap.contract.Transact(opts, "refund", v) } -// Refund is a paid mutator transaction binding the contract method 0xd2544c06. +// Refund is a paid mutator transaction binding the contract method 0x8cd8dd97. // -// Solidity: function refund((bytes32,address,uint64,address,uint64) v) returns() +// Solidity: function refund((bytes32,uint256,address,uint64,address) v) returns() func (_ETHSwap *ETHSwapSession) Refund(v ETHSwapVector) (*types.Transaction, error) { return _ETHSwap.Contract.Refund(&_ETHSwap.TransactOpts, v) } -// Refund is a paid mutator transaction binding the contract method 0xd2544c06. +// Refund is a paid mutator transaction binding the contract method 0x8cd8dd97. // -// Solidity: function refund((bytes32,address,uint64,address,uint64) v) returns() +// Solidity: function refund((bytes32,uint256,address,uint64,address) v) returns() func (_ETHSwap *ETHSwapTransactorSession) Refund(v ETHSwapVector) (*types.Transaction, error) { return _ETHSwap.Contract.Refund(&_ETHSwap.TransactOpts, v) } diff --git a/dex/networks/eth/params.go b/dex/networks/eth/params.go index b671a51860..3178b2f945 100644 --- a/dex/networks/eth/params.go +++ b/dex/networks/eth/params.go @@ -5,6 +5,7 @@ package eth import ( "encoding/binary" + "encoding/hex" "encoding/json" "errors" "fmt" @@ -61,13 +62,13 @@ var ( ContractAddresses = map[uint32]map[dex.Network]common.Address{ 0: { dex.Mainnet: common.HexToAddress("0x8C17e4968B6903E1601be82Ca989c5B5E2c7b400"), - dex.Simnet: common.HexToAddress("0x2f68e723b8989ba1c6a9f03e42f33cb7dc9d606f"), dex.Testnet: common.HexToAddress("0x198463496037754564e9bea5418Bf4117Db0520C"), + dex.Simnet: common.HexToAddress("0x2f68e723b8989ba1c6a9f03e42f33cb7dc9d606f"), }, 1: { dex.Mainnet: common.Address{}, dex.Testnet: common.Address{}, - dex.Simnet: common.Address{}, + dex.Simnet: common.HexToAddress("0x2f68e723b8989ba1c6a9f03e42f33cb7dc9d606f"), }, } @@ -86,22 +87,21 @@ var v0Gases = &Gases{ } var v1Gases = &Gases{ - // First swap used 48769 gas Recommended Gases.Swap = 63399 - // 4 additional swaps averaged 26904 gas each. Recommended Gases.SwapAdd = 34975 - // [48769 75679 102590 129486 156385] - Swap: 63_399, - SwapAdd: 34_975, - // First redeem used 39792 gas. Recommended Gases.Redeem = 51729 - // 4 additional redeems averaged 11037 gas each. recommended Gases.RedeemAdd = 14348 - // [39792 50836 61880 72898 83943] - - // Compare expected Swap + Redeem = 88k with UniSwap v2: 102k, v3: 127k - // A 1-match order is cheaper that UniSwap with v1 gases. - Redeem: 51_729, - RedeemAdd: 14_348, - // Average of 5 refunds: 40155. Recommended Gases.Refund = 52201 - // [40158 40158 40158 40158 40146] - Refund: 52_201, + // First swap used 48340 gas Recommended Gases.Swap = 62842 + Swap: 62_842, + // 4 additional swaps averaged 26499 gas each. Recommended Gases.SwapAdd = 34448 + // [48340 74837 101338 127836 154338] + SwapAdd: 34_448, + // First redeem used 39496 gas. Recommended Gases.Redeem = 51344 + Redeem: 51_344, + // 4 additional redeems averaged 10744 gas each. recommended Gases.RedeemAdd = 13967 + // [39496 50238 60984 71727 82473] + RedeemAdd: 13_967, + // *** Compare expected Swap + Redeem = 88k with UniSwap v2: 102k, v3: 127k + // *** A 1-match order is cheaper than UniSwap. + // Average of 5 refunds: 39918. Recommended Gases.Refund = 51893 + // [39918 39918 39918 39918 39918] + Refund: 51_893, } // LoadGenesisFile loads a Genesis config from a json file. @@ -129,8 +129,20 @@ func EncodeContractData(contractVersion uint32, locator []byte) []byte { return b } -// DecodeLocator unpacks the contract version and secret hash. -func DecodeLocator(data []byte) (contractVersion uint32, locator []byte, err error) { +func DecodeContractDataV0(data []byte) (secretHash [32]byte, err error) { + contractVer, secretHashB, err := DecodeContractData(data) + if err != nil { + return secretHash, err + } + if contractVer != 0 { + return secretHash, errors.New("not contract version 0") + } + copy(secretHash[:], secretHashB) + return +} + +// DecodeContractData unpacks the contract version and the locator. +func DecodeContractData(data []byte) (contractVersion uint32, locator []byte, err error) { if len(data) < 4 { err = errors.New("invalid short encoding") return @@ -260,9 +272,9 @@ func (ss SwapStep) String() string { type SwapVector struct { From common.Address To common.Address - Value uint64 + Value *big.Int SecretHash [32]byte - LockTime uint64 + LockTime uint64 // seconds } // Locator encodes a version 1 locator for the SwapVector. @@ -270,12 +282,23 @@ func (v *SwapVector) Locator() []byte { locator := make([]byte, LocatorV1Length) copy(locator[0:20], v.From[:]) copy(locator[20:40], v.To[:]) - binary.BigEndian.PutUint64(locator[40:48], v.Value) - copy(locator[48:80], v.SecretHash[:]) - binary.BigEndian.PutUint64(locator[80:88], v.LockTime) + v.Value.FillBytes(locator[40:72]) + copy(locator[72:104], v.SecretHash[:]) + binary.BigEndian.PutUint64(locator[104:112], v.LockTime) return locator } +func (v *SwapVector) String() string { + return fmt.Sprintf("{ from = %s, to = %s, value = %d, secret hash = %s, locktime = %s }", + v.From, v.To, v.Value, hex.EncodeToString(v.SecretHash[:]), time.UnixMilli(int64(v.LockTime))) +} + +func CompareVectors(v1, v2 *SwapVector) bool { + // Check vector equivalence. + return v1.Value.Cmp(v2.Value) == 0 && v1.To == v2.To && v1.From == v2.From && + v1.LockTime == v2.LockTime && v1.SecretHash == v2.SecretHash +} + // SwapStatus is the contract data that specifies the current contract state. type SwapStatus struct { BlockHeight uint64 @@ -375,9 +398,9 @@ func ParseV0Locator(locator []byte) (secretHash [32]byte, err error) { return } -// LocatorV1Length = from 20 + to 20 + value 8 + secretHash 32 + -// lockTime 8 = 88 bytes -const LocatorV1Length = 88 +// LocatorV1Length = from 20 + to 20 + value 32 + secretHash 32 + +// lockTime 8 = 112 bytes +const LocatorV1Length = 112 func ParseV1Locator(locator []byte) (v *SwapVector, err error) { // from 20 + to 20 + value 8 + secretHash 32 + lockTime 8 @@ -385,22 +408,47 @@ func ParseV1Locator(locator []byte) (v *SwapVector, err error) { v = &SwapVector{ From: common.BytesToAddress(locator[:20]), To: common.BytesToAddress(locator[20:40]), - Value: binary.BigEndian.Uint64(locator[40:48]), - LockTime: binary.BigEndian.Uint64(locator[80:88]), + Value: new(big.Int).SetBytes(locator[40:72]), + LockTime: binary.BigEndian.Uint64(locator[104:112]), } - copy(v.SecretHash[:], locator[48:80]) + copy(v.SecretHash[:], locator[72:104]) } else { err = fmt.Errorf("wrong v1 locator length. wanted %d, got %d", LocatorV1Length, len(locator)) } return } -func SwapVectorToAbigen(c *SwapVector) swapv1.ETHSwapVector { +func SwapVectorToAbigen(v *SwapVector) swapv1.ETHSwapVector { return swapv1.ETHSwapVector{ - SecretHash: c.SecretHash, - Initiator: c.From, - RefundTimestamp: c.LockTime, - Participant: c.To, - Value: c.Value, + SecretHash: v.SecretHash, + Initiator: v.From, + RefundTimestamp: v.LockTime, + Participant: v.To, + Value: v.Value, } } + +// ProtocolVersion assists in mapping the dex.Asset.Version to a contract +// version. +type ProtocolVersion uint32 + +const ( + ProtocolVersionZero ProtocolVersion = iota + ProtocolVersionV1Contracts +) + +func (v ProtocolVersion) ContractVersion() uint32 { + switch v { + case ProtocolVersionZero: + return 0 + case ProtocolVersionV1Contracts: + return 1 + default: + return ContractVersionUnknown + } +} + +var ( + ContractVersionERC20 = ^uint32(0) + ContractVersionUnknown = ContractVersionERC20 - 1 +) diff --git a/dex/networks/eth/tokens.go b/dex/networks/eth/tokens.go index 4e4d983318..9ec3559003 100644 --- a/dex/networks/eth/tokens.go +++ b/dex/networks/eth/tokens.go @@ -101,56 +101,51 @@ var Tokens = map[uint32]*Token{ 0: { // Swap contract address. The simnet harness writes this // address to file. Live tests must populate this field. - Address: common.Address{}, + Address: common.HexToAddress("0x2f68e723b8989ba1c6a9f03e42f33cb7dc9d606f"), Gas: Gases{ - // Results from client's GetGasEstimates. - // - // First swap used 171756 gas - // 4 additional swaps averaged 112607 gas each - // [171756 284366 396976 509586 622184] - // First redeem used 63214 gas - // 4 additional redeems averaged 31641 gas each - // [63214 94858 126502 158135 189779] - // Average of 5 refunds: 48127 - // [48127 48127 48127 48127 48127] - // - // Approve is the gas used to call the approve - // method of the contract. For Approve transactions, - // the very first approval for an account-spender - // pair takes more than subsequent approvals. The - // results are repeated for a different account's - // first approvals on the same contract, so it's not - // just the global first. - // Average of 5 approvals: 27365 - // [44465 27365 27365 27365 27365] - // - // The first transfer to an address the contract has - // not seen before will insert a new key into the - // contract's token map. The amount of extra gas - // this consumes seems to depend on the size of the - // map and is not noticeable on simnet. - // Average of 5 transfers: 32540 - // [32540 32540 32540 32540 32540] - Swap: 174_000, - SwapAdd: 115_000, - Redeem: 70_000, - RedeemAdd: 33_000, - Refund: 50_000, - Approve: 46_000, - Transfer: 35_000, + // First swap used 171664 gas Recommended Gases.Swap = 223163 + Swap: 223_163, + // 4 additional swaps averaged 112612 gas each. Recommended Gases.SwapAdd = 146395 + // [171664 284279 396870 509509 622112] + SwapAdd: 146_395, + // First redeem used 63158 gas. Recommended Gases.Redeem = 82105 + Redeem: 82_105, + // 4 additional redeems averaged 31626 gas each. recommended Gases.RedeemAdd = 41113 + // [63158 94799 126404 158058 189663] + RedeemAdd: 41_113, + // Average of 5 refunds: 48095. Recommended Gases.Refund = 62523 + // [48098 48098 48086 48098 48098] + Refund: 62_523, + // Average of 2 approvals: 44754. Recommended Gases.Approve = 58180 + // [44754 44754] + Approve: 58_180, + // Average of 1 transfers: 49646. Recommended Gases.Transfer = 64539 + // [49646] + Transfer: 64_539, }, }, 1: { - // DRAFT TODO - Address: common.Address{}, + Address: common.HexToAddress("0x2f68e723b8989ba1c6a9f03e42f33cb7dc9d606f"), Gas: Gases{ - Swap: 174_000, // [171756 284366 396976 509586 622184] - SwapAdd: 115_000, - Redeem: 70_000, // [63214 94858 126502 158135 189779] - RedeemAdd: 33_000, - Refund: 50_000, // [48127 48127 48127 48127 48127] - Approve: 46_000, // [44465 27365 27365 27365 27365] - Transfer: 35_000, // [32540 32540 32540 32540 32540] + // First swap used 85547 gas Recommended Gases.Swap = 111211 + Swap: 111_211, + // 4 additional swaps averaged 26499 gas each. Recommended Gases.SwapAdd = 34448 + // [85547 112048 138534 165048 191546] + SwapAdd: 34_448, + // First redeem used 42219 gas. Recommended Gases.Redeem = 54884 + Redeem: 54_884, + // 4 additional redeems averaged 10744 gas each. recommended Gases.RedeemAdd = 13967 + // [42219 52965 63695 74430 85198] + RedeemAdd: 13_967, + // Average of 5 refunds: 45022. Recommended Gases.Refund = 58528 + // [45025 45025 45013 45025 45025] + Refund: 58_528, + // Average of 2 approvals: 44754. Recommended Gases.Approve = 58180 + // [44754 44754] + Approve: 58_180, + // Average of 1 transfers: 49646. Recommended Gases.Transfer = 64539 + // [49646] + Transfer: 64_539, }, }, }, @@ -296,14 +291,6 @@ func MaybeReadSimnetAddrsDir( return } - fmt.Println("------------") - for ver, nets := range contractAddrs { - fmt.Println("--MaybeReadSimnetAddrsDir.0", ver, len(nets)) - for net, addr := range nets { - fmt.Println("--MaybeReadSimnetAddrsDir.1", net, addr) - } - } - ethSwapContractAddrFileV0 := filepath.Join(harnessDir, "eth_swap_contract_address.txt") tokenSwapContractAddrFileV0 := filepath.Join(harnessDir, "erc20_swap_contract_address.txt") ethSwapContractAddrFileV1 := filepath.Join(harnessDir, "eth_swap_contract_address_v1.txt") diff --git a/dex/networks/eth/txdata.go b/dex/networks/eth/txdata.go index e89db1e066..6aabcc1bd0 100644 --- a/dex/networks/eth/txdata.go +++ b/dex/networks/eth/txdata.go @@ -191,10 +191,10 @@ func ParseInitiateDataV1(calldata []byte) (map[[SecretHashSize]byte]*SwapVector, } initiations, ok := args[0].value.([]struct { SecretHash [32]byte `json:"secretHash"` + Value *big.Int `json:"value"` Initiator common.Address `json:"initiator"` RefundTimestamp uint64 `json:"refundTimestamp"` Participant common.Address `json:"participant"` - Value uint64 `json:"value"` }) if !ok { return nil, fmt.Errorf("expected first arg of type []swapv1.ETHSwapContract but got %T", args[0].value) @@ -241,10 +241,10 @@ func ParseRedeemDataV1(calldata []byte) (map[[SecretHashSize]byte]*RedemptionV1, redemptions, ok := args[0].value.([]struct { V struct { SecretHash [32]uint8 `json:"secretHash"` + Value *big.Int `json:"value"` Initiator common.Address `json:"initiator"` RefundTimestamp uint64 `json:"refundTimestamp"` Participant common.Address `json:"participant"` - Value uint64 `json:"value"` } `json:"v"` Secret [32]uint8 `json:"secret"` }) @@ -294,10 +294,10 @@ func ParseRefundDataV1(calldata []byte) (*SwapVector, error) { } contract, ok := args[0].value.(struct { SecretHash [32]byte `json:"secretHash"` + Value *big.Int `json:"value"` Initiator common.Address `json:"initiator"` RefundTimestamp uint64 `json:"refundTimestamp"` Participant common.Address `json:"participant"` - Value uint64 `json:"value"` }) if !ok { return nil, fmt.Errorf("expected first arg of type [32]byte but got %T", args[0].value) diff --git a/dex/networks/polygon/params.go b/dex/networks/polygon/params.go index 46747fc653..d9e0f8ba5c 100644 --- a/dex/networks/polygon/params.go +++ b/dex/networks/polygon/params.go @@ -111,7 +111,19 @@ var ( Transfer: 64_539, }, }, - 1: {}, + 1: { + // DRAFT TODO + Address: common.Address{}, // Set in MaybeReadSimnetAddrs + Gas: dexeth.Gases{ + Swap: 223_163, + SwapAdd: 146_399, + Redeem: 82_121, + RedeemAdd: 41_113, + Refund: 62_527, + Approve: 58_180, + Transfer: 64_539, + }, + }, }, }, }, diff --git a/dex/testing/eth/harness.sh b/dex/testing/eth/harness.sh index cb46ab186b..5f1cb6b68d 100755 --- a/dex/testing/eth/harness.sh +++ b/dex/testing/eth/harness.sh @@ -45,8 +45,8 @@ ERC20_SWAP_V0="60a060405234801561001057600080fd5b50604051610e92380380610e9283398 TEST_TOKEN="608060405234801561001057600080fd5b506040805180820190915260098152682a32b9ba2a37b5b2b760b91b602082015260039061003e90826101ad565b506040805180820190915260038152621514d560ea1b602082015260049061006690826101ad565b506909513ea9de0243800000600255600060208190526902544faa778090e000007f7d4921c2bc32c0110a31d16f4efb43c7a1228f1df7af765f608241dee5c62ebc8190557f59603491850c7d11499afe95b334ccfd92b48b36a15df31ef59ff5813fe3708281905573d12ab7cf72ccf1f3882ec99ddc53cd415635c3be9091527f5bd8dfce2dbb581d0922a094c40bab2f7d2f0ea9aaf275bf0fcc0f027a2ff91d5561026c565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061013857607f821691505b60208210810361015857634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156101a857600081815260208120601f850160051c810160208610156101855750805b601f850160051c820191505b818110156101a457828155600101610191565b5050505b505050565b81516001600160401b038111156101c6576101c661010e565b6101da816101d48454610124565b8461015e565b602080601f83116001811461020f57600084156101f75750858301515b600019600386901b1c1916600185901b1785556101a4565b600085815260208120601f198616915b8281101561023e5788860151825594840194600190910190840161021f565b508582101561025c5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6107c08061027b6000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c806370a082311161007157806370a08231146101235780638ba4cc3c1461014c57806395d89b4114610161578063a9059cbb14610169578063ce714b511461017c578063dd62ed3e1461018f57600080fd5b806306fdde03146100ae578063095ea7b3146100cc57806318160ddd146100ef57806323b872dd14610101578063313ce56714610114575b600080fd5b6100b66101c8565b6040516100c3919061060a565b60405180910390f35b6100df6100da366004610674565b61025a565b60405190151581526020016100c3565b6002545b6040519081526020016100c3565b6100df61010f36600461069e565b610271565b604051601281526020016100c3565b6100f36101313660046106da565b6001600160a01b031660009081526020819052604090205490565b61015f61015a366004610674565b610320565b005b6100b6610368565b6100df610177366004610674565b610377565b6100df61018a36600461069e565b610384565b6100f361019d3660046106fc565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6060600380546101d79061072f565b80601f01602080910402602001604051908101604052809291908181526020018280546102039061072f565b80156102505780601f1061022557610100808354040283529160200191610250565b820191906000526020600020905b81548152906001019060200180831161023357829003601f168201915b5050505050905090565b600061026733848461039b565b5060015b92915050565b600061027e84848461048a565b6001600160a01b0384166000908152600160209081526040808320338452909152902054828110156103085760405162461bcd60e51b815260206004820152602860248201527f45524332303a207472616e7366657220616d6f756e74206578636565647320616044820152676c6c6f77616e636560c01b60648201526084015b60405180910390fd5b610315853385840361039b565b506001949350505050565b80600260008282546103329190610769565b90915550506001600160a01b0382166000908152602081905260408120805483929061035f908490610769565b90915550505050565b6060600480546101d79061072f565b600061026733848461048a565b600061039184848461039b565b5060019392505050565b6001600160a01b0383166103fd5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016102ff565b6001600160a01b03821661045e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016102ff565b6001600160a01b0392831660009081526001602090815260408083209490951682529290925291902055565b6001600160a01b0383166104ee5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016102ff565b6001600160a01b0382166105505760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016102ff565b6001600160a01b038316600090815260208190526040902054818110156105c85760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016102ff565b6001600160a01b038085166000908152602081905260408082208585039055918516815290812080548492906105ff908490610769565b909155505050505050565b600060208083528351808285015260005b818110156106375785810183015185820160400152820161061b565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b038116811461066f57600080fd5b919050565b6000806040838503121561068757600080fd5b61069083610658565b946020939093013593505050565b6000806000606084860312156106b357600080fd5b6106bc84610658565b92506106ca60208501610658565b9150604084013590509250925092565b6000602082840312156106ec57600080fd5b6106f582610658565b9392505050565b6000806040838503121561070f57600080fd5b61071883610658565b915061072660208401610658565b90509250929050565b600181811c9082168061074357607f821691505b60208210810361076357634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561026b57634e487b7160e01b600052601160045260246000fdfea2646970667358221220e48184f15ae575a1ab3966580821ddaff3654cd0137084d70ceeeb4d906b3c5364736f6c63430008120033" MULTIBALANCE_BIN="608060405234801561001057600080fd5b50610483806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063d3e5ca8714610030575b600080fd5b61004361003e3660046102a5565b610059565b604051610050919061032b565b60405180910390f35b60606000610068836001610385565b67ffffffffffffffff8111156100805761008061039e565b6040519080825280602002602001820160405280156100a9578160200160208202803683370190505b509050846001600160a01b031631816000815181106100ca576100ca6103b4565b60200260200101818152505060005b838110156102805760008585838181106100f5576100f56103b4565b905060200201602081019061010a91906103ca565b905060006060826001600160a01b03167f70a08231b98ef4ca268c9cc3f6b4590e4bfec28280db06bb5d45e689f2a360be8a60405160240161015b91906001600160a01b0391909116815260200190565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161019991906103ec565b600060405180830381855afa9150503d80600081146101d4576040519150601f19603f3d011682016040523d82523d6000602084013e6101d9565b606091505b509092509050816102285760405162461bcd60e51b815260206004820152601560248201527418985b185b98d953d98818d85b1b0819985a5b1959605a1b604482015260640160405180910390fd5b60008180602001905181019061023e919061041b565b9050808661024d876001610385565b8151811061025d5761025d6103b4565b60200260200101818152505050505050808061027890610434565b9150506100d9565b50949350505050565b80356001600160a01b03811681146102a057600080fd5b919050565b6000806000604084860312156102ba57600080fd5b6102c384610289565b9250602084013567ffffffffffffffff808211156102e057600080fd5b818601915086601f8301126102f457600080fd5b81358181111561030357600080fd5b8760208260051b850101111561031857600080fd5b6020830194508093505050509250925092565b6020808252825182820181905260009190848201906040850190845b8181101561036357835183529284019291840191600101610347565b50909695505050505050565b634e487b7160e01b600052601160045260246000fd5b808201808211156103985761039861036f565b92915050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000602082840312156103dc57600080fd5b6103e582610289565b9392505050565b6000825160005b8181101561040d57602081860181015185830152016103f3565b506000920191825250919050565b60006020828403121561042d57600080fd5b5051919050565b6000600182016104465761044661036f565b506001019056fea26469706673582212207074e3e189a2692e2841f7943a9de24bcdbca943ee6bfcbd83a2fa6e43ec497b64736f6c63430008120033" -ETH_SWAP_V1="608060405234801561001057600080fd5b50610e8e806100206000396000f3fe60806040526004361061007b5760003560e01c80637802689d1161004e5780637802689d1461011b578063d2544c061461013b578063eb84e7f21461015b578063ed7cbed71461019657600080fd5b8063428b16e11461008057806361a16e33146100a257806364a97bff146100d857806377d7e031146100eb575b600080fd5b34801561008c57600080fd5b506100a061009b366004610b6f565b6101b6565b005b3480156100ae57600080fd5b506100c26100bd366004610be4565b610447565b6040516100cf9190610c12565b60405180910390f35b6100a06100e6366004610c55565b610503565b3480156100f757600080fd5b5061010b610106366004610cb8565b61073b565b60405190151581526020016100cf565b34801561012757600080fd5b5061010b610136366004610be4565b6107b5565b34801561014757600080fd5b506100a0610156366004610be4565b6107e8565b34801561016757600080fd5b50610188610176366004610cda565b60006020819052908152604090205481565b6040519081526020016100cf565b3480156101a257600080fd5b506101886101b1366004610be4565b610a4a565b3233146101de5760405162461bcd60e51b81526004016101d590610cf3565b60405180910390fd5b6000805b828110156103b057368484838181106101fd576101fd610d1d565b60c0029190910191503390506102196080830160608401610d33565b6001600160a01b03161461025c5760405162461bcd60e51b815260206004820152600a6024820152691b9bdd08185d5d1a195960b21b60448201526064016101d5565b6000808061026984610b43565b92509250925060008111801561027e57504381105b6102ba5760405162461bcd60e51b815260206004820152600d60248201526c0756e66696c6c6564207377617609c1b60448201526064016101d5565b6102c582853561073b565b156103055760405162461bcd60e51b815260206004820152601060248201526f185b1c9958591e481c995919595b595960821b60448201526064016101d5565b61031460a0850135853561073b565b6103515760405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a59081cd958dc995d60921b60448201526064016101d5565b600083815260208190526040902060a0850180359091556103759060808601610d63565b61038390633b9aca00610da3565b6103979067ffffffffffffffff1687610dd3565b95505050505080806103a890610deb565b9150506101e2565b50604051600090339083908381818185875af1925050503d80600081146103f3576040519150601f19603f3d011682016040523d82523d6000602084013e6103f8565b606091505b50909150506001811515146104415760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b60448201526064016101d5565b50505050565b60408051606081018252600080825260208201819052918101829052908061046e84610b43565b92509250506104986040805160608101909152806000815260006020820181905260409091015290565b816000036104bf578060005b908160038111156104b7576104b7610bfc565b9052506104fb565b600183016104cf578060036104a4565b6104da83863561073b565b156104ef5760028152602081018390526104fb565b60018152604081018290525b949350505050565b3233146105225760405162461bcd60e51b81526004016101d590610cf3565b6000805b828110156106fc573684848381811061054157610541610d1d565b905060a002019050600081608001602081019061055e9190610d63565b67ffffffffffffffff161161059d5760405162461bcd60e51b81526020600482015260056024820152640c081d985b60da1b60448201526064016101d5565b60006105af6060830160408401610d63565b67ffffffffffffffff16116105fa5760405162461bcd60e51b815260206004820152601160248201527003020726566756e6454696d657374616d7607c1b60448201526064016101d5565b600061060582610a4a565b60008181526020819052604090205490915080156106565760405162461bcd60e51b815260206004820152600e60248201526d73776170206e6f7420656d70747960901b60448201526064016101d5565b504361066381843561073b565b156106a15760405162461bcd60e51b815260206004820152600e60248201526d3430b9b41031b7b63634b9b4b7b760911b60448201526064016101d5565b60008281526020819052604090208190556106c260a0840160808501610d63565b6106d090633b9aca00610da3565b6106e49067ffffffffffffffff1686610dd3565b945050505080806106f490610deb565b915050610526565b503481146107365760405162461bcd60e51b8152602060048201526007602482015266189859081d985b60ca1b60448201526064016101d5565b505050565b60008160028460405160200161075391815260200190565b60408051601f198184030181529082905261076d91610e04565b602060405180830381855afa15801561078a573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906107ad9190610e3f565b149392505050565b60008060006107c384610b43565b9250925050806000141580156104fb57506107df82853561073b565b15949350505050565b3233146108075760405162461bcd60e51b81526004016101d590610cf3565b6108176060820160408301610d63565b67ffffffffffffffff164210156108675760405162461bcd60e51b81526020600482015260146024820152731b1bd8dadd1a5b59481b9bdd08195e1c1a5c995960621b60448201526064016101d5565b600080600061087584610b43565b92509250925060008111801561088b5750438111155b6108c95760405162461bcd60e51b815260206004820152600f60248201526e73776170206e6f742061637469766560881b60448201526064016101d5565b6108d482853561073b565b156109195760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c995919595b5959605a1b60448201526064016101d5565b600182016109615760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c99599d5b991959605a1b60448201526064016101d5565b600083815260208181526040808320600019905561098491908701908701610d33565b6001600160a01b031661099d60a0870160808801610d63565b6109ab90633b9aca00610da3565b67ffffffffffffffff1660405160006040518083038185875af1925050503d80600081146109f5576040519150601f19603f3d011682016040523d82523d6000602084013e6109fa565b606091505b5090915050600181151514610a435760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b60448201526064016101d5565b5050505050565b600060028235610a606040850160208601610d33565b60601b846060016020810190610a769190610d33565b60601b610a8960a0870160808801610d63565b60c01b610a9c6060880160408901610d63565b6040805160208101969096526bffffffffffffffffffffffff19948516908601529190921660548401526001600160c01b0319918216606884015260c01b16607082015260780160408051601f1981840301815290829052610afd91610e04565b602060405180830381855afa158015610b1a573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610b3d9190610e3f565b92915050565b600080600080610b5285610a4a565b600081815260208190526040902054909690955085945092505050565b60008060208385031215610b8257600080fd5b823567ffffffffffffffff80821115610b9a57600080fd5b818501915085601f830112610bae57600080fd5b813581811115610bbd57600080fd5b86602060c083028501011115610bd257600080fd5b60209290920196919550909350505050565b600060a08284031215610bf657600080fd5b50919050565b634e487b7160e01b600052602160045260246000fd5b8151606082019060048110610c3757634e487b7160e01b600052602160045260246000fd5b80835250602083015160208301526040830151604083015292915050565b60008060208385031215610c6857600080fd5b823567ffffffffffffffff80821115610c8057600080fd5b818501915085601f830112610c9457600080fd5b813581811115610ca357600080fd5b86602060a083028501011115610bd257600080fd5b60008060408385031215610ccb57600080fd5b50508035926020909101359150565b600060208284031215610cec57600080fd5b5035919050565b60208082526010908201526f39b2b73232b910109e9037b934b3b4b760811b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215610d4557600080fd5b81356001600160a01b0381168114610d5c57600080fd5b9392505050565b600060208284031215610d7557600080fd5b813567ffffffffffffffff81168114610d5c57600080fd5b634e487b7160e01b600052601160045260246000fd5b600067ffffffffffffffff80831681851681830481118215151615610dca57610dca610d8d565b02949350505050565b60008219821115610de657610de6610d8d565b500190565b600060018201610dfd57610dfd610d8d565b5060010190565b6000825160005b81811015610e255760208186018101518583015201610e0b565b81811115610e34576000828501525b509190910192915050565b600060208284031215610e5157600080fd5b505191905056fea2646970667358221220d735868682c69bb69ed936f11e2f136e7da44cb347e0b1d67acd1e088ea13dd664736f6c634300080f0033" -ERC20_SWAP_V1="60a060405234801561001057600080fd5b506040516111cb3803806111cb83398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b60805161112b6100a060003960008181610158015281816104570152818161083e0152610b5d015261112b6000f3fe6080604052600436106100865760003560e01c80637802689d116100595780637802689d146101265780638c8e8fee14610146578063d2544c0614610192578063eb84e7f2146101b2578063ed7cbed7146101ed57600080fd5b8063428b16e11461008b57806361a16e33146100ad57806364a97bff146100e357806377d7e031146100f6575b600080fd5b34801561009757600080fd5b506100ab6100a6366004610dea565b61020d565b005b3480156100b957600080fd5b506100cd6100c8366004610e5f565b610533565b6040516100da9190610e8d565b60405180910390f35b6100ab6100f1366004610ed0565b6105ef565b34801561010257600080fd5b50610116610111366004610f33565b610918565b60405190151581526020016100da565b34801561013257600080fd5b50610116610141366004610e5f565b610992565b34801561015257600080fd5b5061017a7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100da565b34801561019e57600080fd5b506100ab6101ad366004610e5f565b6109c5565b3480156101be57600080fd5b506101df6101cd366004610f55565b60006020819052908152604090205481565b6040519081526020016100da565b3480156101f957600080fd5b506101df610208366004610e5f565b610cc5565b3233146102355760405162461bcd60e51b815260040161022c90610f6e565b60405180910390fd5b6000805b82811015610407573684848381811061025457610254610f98565b60c0029190910191503390506102706080830160608401610fae565b6001600160a01b0316146102b35760405162461bcd60e51b815260206004820152600a6024820152691b9bdd08185d5d1a195960b21b604482015260640161022c565b600080806102c084610dbe565b9250925092506000811180156102d557504381105b6103115760405162461bcd60e51b815260206004820152600d60248201526c0756e66696c6c6564207377617609c1b604482015260640161022c565b61031c828535610918565b1561035c5760405162461bcd60e51b815260206004820152601060248201526f185b1c9958591e481c995919595b595960821b604482015260640161022c565b61036b60a08501358535610918565b6103a85760405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a59081cd958dc995d60921b604482015260640161022c565b600083815260208190526040902060a0850180359091556103cc9060808601610fde565b6103da90633b9aca0061101e565b6103ee9067ffffffffffffffff168761104e565b95505050505080806103ff90611066565b915050610239565b5060408051336024820152604480820184905282518083039091018152606490910182526020810180516001600160e01b031663a9059cbb60e01b17905290516000916060916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916104819161107f565b6000604051808303816000865af19150503d80600081146104be576040519150601f19603f3d011682016040523d82523d6000602084013e6104c3565b606091505b5090925090508180156104ee5750805115806104ee5750808060200190518101906104ee91906110ba565b61052c5760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b604482015260640161022c565b5050505050565b60408051606081018252600080825260208201819052918101829052908061055a84610dbe565b92509250506105846040805160608101909152806000815260006020820181905260409091015290565b816000036105ab578060005b908160038111156105a3576105a3610e77565b9052506105e7565b600183016105bb57806003610590565b6105c6838635610918565b156105db5760028152602081018390526105e7565b60018152604081018290525b949350505050565b32331461060e5760405162461bcd60e51b815260040161022c90610f6e565b6000805b828110156107e8573684848381811061062d5761062d610f98565b905060a002019050600081608001602081019061064a9190610fde565b67ffffffffffffffff16116106895760405162461bcd60e51b81526020600482015260056024820152640c081d985b60da1b604482015260640161022c565b600061069b6060830160408401610fde565b67ffffffffffffffff16116106e65760405162461bcd60e51b815260206004820152601160248201527003020726566756e6454696d657374616d7607c1b604482015260640161022c565b60006106f182610cc5565b60008181526020819052604090205490915080156107425760405162461bcd60e51b815260206004820152600e60248201526d73776170206e6f7420656d70747960901b604482015260640161022c565b504361074f818435610918565b1561078d5760405162461bcd60e51b815260206004820152600e60248201526d3430b9b41031b7b63634b9b4b7b760911b604482015260640161022c565b60008281526020819052604090208190556107ae60a0840160808501610fde565b6107bc90633b9aca0061101e565b6107d09067ffffffffffffffff168661104e565b945050505080806107e090611066565b915050610612565b5060408051336024820152306044820152606480820184905282518083039091018152608490910182526020810180516001600160e01b03166323b872dd60e01b17905290516000916060916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916108689161107f565b6000604051808303816000865af19150503d80600081146108a5576040519150601f19603f3d011682016040523d82523d6000602084013e6108aa565b606091505b5090925090508180156108d55750805115806108d55750808060200190518101906108d591906110ba565b61052c5760405162461bcd60e51b81526020600482015260146024820152731d1c985b9cd9995c88199c9bdb4819985a5b195960621b604482015260640161022c565b60008160028460405160200161093091815260200190565b60408051601f198184030181529082905261094a9161107f565b602060405180830381855afa158015610967573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061098a91906110dc565b149392505050565b60008060006109a084610dbe565b9250925050806000141580156105e757506109bc828535610918565b15949350505050565b3233146109e45760405162461bcd60e51b815260040161022c90610f6e565b6109f46060820160408301610fde565b67ffffffffffffffff16421015610a445760405162461bcd60e51b81526020600482015260146024820152731b1bd8dadd1a5b59481b9bdd08195e1c1a5c995960621b604482015260640161022c565b6000806000610a5284610dbe565b925092509250600081118015610a685750438111155b610aa65760405162461bcd60e51b815260206004820152600f60248201526e73776170206e6f742061637469766560881b604482015260640161022c565b610ab1828535610918565b15610af65760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c995919595b5959605a1b604482015260640161022c565b60018201610b3e5760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c99599d5b991959605a1b604482015260640161022c565b6000838152602081905260408120600019905560606001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167fa9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b33610baf60a08a0160808b01610fde565b6040516001600160a01b03909216602483015267ffffffffffffffff16604482015260640160408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051610c12919061107f565b6000604051808303816000865af19150503d8060008114610c4f576040519150601f19603f3d011682016040523d82523d6000602084013e610c54565b606091505b509092509050818015610c7f575080511580610c7f575080806020019051810190610c7f91906110ba565b610cbd5760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b604482015260640161022c565b505050505050565b600060028235610cdb6040850160208601610fae565b60601b846060016020810190610cf19190610fae565b60601b610d0460a0870160808801610fde565b60c01b610d176060880160408901610fde565b6040805160208101969096526bffffffffffffffffffffffff19948516908601529190921660548401526001600160c01b0319918216606884015260c01b16607082015260780160408051601f1981840301815290829052610d789161107f565b602060405180830381855afa158015610d95573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610db891906110dc565b92915050565b600080600080610dcd85610cc5565b600081815260208190526040902054909690955085945092505050565b60008060208385031215610dfd57600080fd5b823567ffffffffffffffff80821115610e1557600080fd5b818501915085601f830112610e2957600080fd5b813581811115610e3857600080fd5b86602060c083028501011115610e4d57600080fd5b60209290920196919550909350505050565b600060a08284031215610e7157600080fd5b50919050565b634e487b7160e01b600052602160045260246000fd5b8151606082019060048110610eb257634e487b7160e01b600052602160045260246000fd5b80835250602083015160208301526040830151604083015292915050565b60008060208385031215610ee357600080fd5b823567ffffffffffffffff80821115610efb57600080fd5b818501915085601f830112610f0f57600080fd5b813581811115610f1e57600080fd5b86602060a083028501011115610e4d57600080fd5b60008060408385031215610f4657600080fd5b50508035926020909101359150565b600060208284031215610f6757600080fd5b5035919050565b60208082526010908201526f39b2b73232b910109e9037b934b3b4b760811b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215610fc057600080fd5b81356001600160a01b0381168114610fd757600080fd5b9392505050565b600060208284031215610ff057600080fd5b813567ffffffffffffffff81168114610fd757600080fd5b634e487b7160e01b600052601160045260246000fd5b600067ffffffffffffffff8083168185168183048111821515161561104557611045611008565b02949350505050565b6000821982111561106157611061611008565b500190565b60006001820161107857611078611008565b5060010190565b6000825160005b818110156110a05760208186018101518583015201611086565b818111156110af576000828501525b509190910192915050565b6000602082840312156110cc57600080fd5b81518015158114610fd757600080fd5b6000602082840312156110ee57600080fd5b505191905056fea2646970667358221220319d89b87a0d5782925310133ed5d12d2ff562b0786611308396804fcad176fc64736f6c634300080f0033" +ETH_SWAP_V1="608060405234801561001057600080fd5b50610db9806100206000396000f3fe60806040526004361061007b5760003560e01c8063a76f9f2d1161004e578063a76f9f2d1461010a578063d5cfd04914610138578063db3b419c14610158578063eb84e7f21461018557600080fd5b806323f0388b146100805780633da59631146100a257806377d7e031146100b55780638cd8dd97146100ea575b600080fd5b34801561008c57600080fd5b506100a061009b366004610adb565b6101b2565b005b6100a06100b0366004610b50565b610420565b3480156100c157600080fd5b506100d56100d0366004610bb3565b61061c565b60405190151581526020015b60405180910390f35b3480156100f657600080fd5b506100a0610105366004610bd5565b610698565b34801561011657600080fd5b5061012a610125366004610bd5565b6108d8565b6040519081526020016100e1565b34801561014457600080fd5b506100d5610153366004610bd5565b6109c0565b34801561016457600080fd5b50610178610173366004610bd5565b6109f4565b6040516100e19190610c03565b34801561019157600080fd5b5061012a6101a0366004610c46565b60006020819052908152604090205481565b3233146101da5760405162461bcd60e51b81526004016101d190610c5f565b60405180910390fd5b6000805b8281101561038957368484838181106101f9576101f9610c89565b60c00291909101915033905061021560a0830160808401610c9f565b6001600160a01b0316146102585760405162461bcd60e51b815260206004820152600a6024820152691b9bdd08185d5d1a195960b21b60448201526064016101d1565b6000808061026584610aaf565b92509250925060008111801561027a57504381105b6102b65760405162461bcd60e51b815260206004820152600d60248201526c0756e66696c6c6564207377617609c1b60448201526064016101d1565b6102c182853561061c565b156103015760405162461bcd60e51b815260206004820152601060248201526f185b1c9958591e481c995919595b595960821b60448201526064016101d1565b61031060a0850135853561061c565b61034d5760405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a59081cd958dc995d60921b60448201526064016101d1565b60008381526020818152604090912060a086013590556103709085013587610ce5565b955050505050808061038190610cf8565b9150506101de565b50604051600090339083908381818185875af1925050503d80600081146103cc576040519150601f19603f3d011682016040523d82523d6000602084013e6103d1565b606091505b509091505060018115151461041a5760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b60448201526064016101d1565b50505050565b32331461043f5760405162461bcd60e51b81526004016101d190610c5f565b6000805b828110156105dd573684848381811061045e5761045e610c89565b905060a00201905060008160200135116104a25760405162461bcd60e51b81526020600482015260056024820152640c081d985b60da1b60448201526064016101d1565b60006104b46080830160608401610d11565b67ffffffffffffffff16116104ff5760405162461bcd60e51b815260206004820152601160248201527003020726566756e6454696d657374616d7607c1b60448201526064016101d1565b600061050a826108d8565b600081815260208190526040902054909150801561055b5760405162461bcd60e51b815260206004820152600e60248201526d73776170206e6f7420656d70747960901b60448201526064016101d1565b504361056881843561061c565b156105a65760405162461bcd60e51b815260206004820152600e60248201526d3430b9b41031b7b63634b9b4b7b760911b60448201526064016101d1565b6000828152602081815260409091208290556105c59084013586610ce5565b945050505080806105d590610cf8565b915050610443565b503481146106175760405162461bcd60e51b8152602060048201526007602482015266189859081d985b60ca1b60448201526064016101d1565b505050565b60008160028460405160200161063491815260200190565b60408051601f198184030181529082905261064e91610d3b565b602060405180830381855afa15801561066b573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061068e9190610d6a565b1490505b92915050565b3233146106b75760405162461bcd60e51b81526004016101d190610c5f565b6106c76080820160608301610d11565b67ffffffffffffffff164210156107175760405162461bcd60e51b81526020600482015260146024820152731b1bd8dadd1a5b59481b9bdd08195e1c1a5c995960621b60448201526064016101d1565b600080600061072584610aaf565b92509250925060008111801561073b5750438111155b6107795760405162461bcd60e51b815260206004820152600f60248201526e73776170206e6f742061637469766560881b60448201526064016101d1565b61078482853561061c565b156107c95760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c995919595b5959605a1b60448201526064016101d1565b600182016108115760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c99599d5b991959605a1b60448201526064016101d1565b60008381526020819052604080822060001990556108359060608701908701610c9f565b6001600160a01b0316856020013560405160006040518083038185875af1925050503d8060008114610883576040519150601f19603f3d011682016040523d82523d6000602084013e610888565b606091505b50909150506001811515146108d15760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b60448201526064016101d1565b5050505050565b6000600282356108ee6060850160408601610c9f565b60601b61090160a0860160808701610c9f565b60601b856020013560001b86606001602081019061091f9190610d11565b6040805160208101969096526bffffffffffffffffffffffff199485169086015292909116605484015260688301526001600160c01b031960c09190911b16608882015260900160408051601f198184030181529082905261098091610d3b565b602060405180830381855afa15801561099d573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906106929190610d6a565b60008060006109ce84610aaf565b9250925050806000141580156109ec57506109ea82853561061c565b155b949350505050565b604080516060810182526000808252602082018190529181018290529080610a1b84610aaf565b9250925050610a456040805160608101909152806000815260006020820181905260409091015290565b81600003610a6c578060005b90816003811115610a6457610a64610bed565b9052506109ec565b60018301610a7c57806003610a51565b610a8783863561061c565b15610a9c5760028152602081018390526109ec565b6001815260408101919091529392505050565b600080600080610abe856108d8565b600081815260208190526040902054909690955085945092505050565b60008060208385031215610aee57600080fd5b823567ffffffffffffffff80821115610b0657600080fd5b818501915085601f830112610b1a57600080fd5b813581811115610b2957600080fd5b86602060c083028501011115610b3e57600080fd5b60209290920196919550909350505050565b60008060208385031215610b6357600080fd5b823567ffffffffffffffff80821115610b7b57600080fd5b818501915085601f830112610b8f57600080fd5b813581811115610b9e57600080fd5b86602060a083028501011115610b3e57600080fd5b60008060408385031215610bc657600080fd5b50508035926020909101359150565b600060a08284031215610be757600080fd5b50919050565b634e487b7160e01b600052602160045260246000fd5b8151606082019060048110610c2857634e487b7160e01b600052602160045260246000fd5b80835250602083015160208301526040830151604083015292915050565b600060208284031215610c5857600080fd5b5035919050565b60208082526010908201526f39b2b73232b910109e9037b934b3b4b760811b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215610cb157600080fd5b81356001600160a01b0381168114610cc857600080fd5b9392505050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561069257610692610ccf565b600060018201610d0a57610d0a610ccf565b5060010190565b600060208284031215610d2357600080fd5b813567ffffffffffffffff81168114610cc857600080fd5b6000825160005b81811015610d5c5760208186018101518583015201610d42565b506000920191825250919050565b600060208284031215610d7c57600080fd5b505191905056fea2646970667358221220d06fb8ed23d4808c2b9f4f691e0abd03030305c1af9428077386f96e11f2643364736f6c63430008120033" +ERC20_SWAP_V1="60a060405234801561001057600080fd5b506040516110d03803806110d083398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b6080516110306100a060003960008181610107015281816104300152818161071f0152610a4701526110306000f3fe6080604052600436106100865760003560e01c80638cd8dd97116100595780638cd8dd9714610141578063a76f9f2d14610161578063d5cfd0491461018f578063db3b419c146101af578063eb84e7f2146101dc57600080fd5b806323f0388b1461008b5780633da59631146100ad57806377d7e031146100c05780638c8e8fee146100f5575b600080fd5b34801561009757600080fd5b506100ab6100a6366004610d30565b610209565b005b6100ab6100bb366004610da5565b61050c565b3480156100cc57600080fd5b506100e06100db366004610e08565b6107f9565b60405190151581526020015b60405180910390f35b34801561010157600080fd5b506101297f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100ec565b34801561014d57600080fd5b506100ab61015c366004610e2a565b610875565b34801561016d57600080fd5b5061018161017c366004610e2a565b610b2d565b6040519081526020016100ec565b34801561019b57600080fd5b506100e06101aa366004610e2a565b610c15565b3480156101bb57600080fd5b506101cf6101ca366004610e2a565b610c49565b6040516100ec9190610e58565b3480156101e857600080fd5b506101816101f7366004610e9b565b60006020819052908152604090205481565b3233146102315760405162461bcd60e51b815260040161022890610eb4565b60405180910390fd5b6000805b828110156103e0573684848381811061025057610250610ede565b60c00291909101915033905061026c60a0830160808401610ef4565b6001600160a01b0316146102af5760405162461bcd60e51b815260206004820152600a6024820152691b9bdd08185d5d1a195960b21b6044820152606401610228565b600080806102bc84610d04565b9250925092506000811180156102d157504381105b61030d5760405162461bcd60e51b815260206004820152600d60248201526c0756e66696c6c6564207377617609c1b6044820152606401610228565b6103188285356107f9565b156103585760405162461bcd60e51b815260206004820152601060248201526f185b1c9958591e481c995919595b595960821b6044820152606401610228565b61036760a085013585356107f9565b6103a45760405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a59081cd958dc995d60921b6044820152606401610228565b60008381526020818152604090912060a086013590556103c79085013587610f3a565b95505050505080806103d890610f4d565b915050610235565b5060408051336024820152604480820184905282518083039091018152606490910182526020810180516001600160e01b031663a9059cbb60e01b17905290516000916060916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169161045a91610f66565b6000604051808303816000865af19150503d8060008114610497576040519150601f19603f3d011682016040523d82523d6000602084013e61049c565b606091505b5090925090508180156104c75750805115806104c75750808060200190518101906104c79190610f95565b6105055760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b6044820152606401610228565b5050505050565b32331461052b5760405162461bcd60e51b815260040161022890610eb4565b6000805b828110156106c9573684848381811061054a5761054a610ede565b905060a002019050600081602001351161058e5760405162461bcd60e51b81526020600482015260056024820152640c081d985b60da1b6044820152606401610228565b60006105a06080830160608401610fb7565b67ffffffffffffffff16116105eb5760405162461bcd60e51b815260206004820152601160248201527003020726566756e6454696d657374616d7607c1b6044820152606401610228565b60006105f682610b2d565b60008181526020819052604090205490915080156106475760405162461bcd60e51b815260206004820152600e60248201526d73776170206e6f7420656d70747960901b6044820152606401610228565b50436106548184356107f9565b156106925760405162461bcd60e51b815260206004820152600e60248201526d3430b9b41031b7b63634b9b4b7b760911b6044820152606401610228565b6000828152602081815260409091208290556106b19084013586610f3a565b945050505080806106c190610f4d565b91505061052f565b5060408051336024820152306044820152606480820184905282518083039091018152608490910182526020810180516001600160e01b03166323b872dd60e01b17905290516000916060916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169161074991610f66565b6000604051808303816000865af19150503d8060008114610786576040519150601f19603f3d011682016040523d82523d6000602084013e61078b565b606091505b5090925090508180156107b65750805115806107b65750808060200190518101906107b69190610f95565b6105055760405162461bcd60e51b81526020600482015260146024820152731d1c985b9cd9995c88199c9bdb4819985a5b195960621b6044820152606401610228565b60008160028460405160200161081191815260200190565b60408051601f198184030181529082905261082b91610f66565b602060405180830381855afa158015610848573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061086b9190610fe1565b1490505b92915050565b3233146108945760405162461bcd60e51b815260040161022890610eb4565b6108a46080820160608301610fb7565b67ffffffffffffffff164210156108f45760405162461bcd60e51b81526020600482015260146024820152731b1bd8dadd1a5b59481b9bdd08195e1c1a5c995960621b6044820152606401610228565b600080600061090284610d04565b9250925092506000811180156109185750438111155b6109565760405162461bcd60e51b815260206004820152600f60248201526e73776170206e6f742061637469766560881b6044820152606401610228565b6109618285356107f9565b156109a65760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c995919595b5959605a1b6044820152606401610228565b600182016109ee5760405162461bcd60e51b81526020600482015260156024820152741cddd85c08185b1c9958591e481c99599d5b991959605a1b6044820152606401610228565b6000838152602081815260408083206000199055805133602482015287830135604480830191909152825180830390910181526064909101825291820180516001600160e01b031663a9059cbb60e01b179052516060917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691610a7a9190610f66565b6000604051808303816000865af19150503d8060008114610ab7576040519150601f19603f3d011682016040523d82523d6000602084013e610abc565b606091505b509092509050818015610ae7575080511580610ae7575080806020019051810190610ae79190610f95565b610b255760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b6044820152606401610228565b505050505050565b600060028235610b436060850160408601610ef4565b60601b610b5660a0860160808701610ef4565b60601b856020013560001b866060016020810190610b749190610fb7565b6040805160208101969096526bffffffffffffffffffffffff199485169086015292909116605484015260688301526001600160c01b031960c09190911b16608882015260900160408051601f1981840301815290829052610bd591610f66565b602060405180830381855afa158015610bf2573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061086f9190610fe1565b6000806000610c2384610d04565b925092505080600014158015610c415750610c3f8285356107f9565b155b949350505050565b604080516060810182526000808252602082018190529181018290529080610c7084610d04565b9250925050610c9a6040805160608101909152806000815260006020820181905260409091015290565b81600003610cc1578060005b90816003811115610cb957610cb9610e42565b905250610c41565b60018301610cd157806003610ca6565b610cdc8386356107f9565b15610cf1576002815260208101839052610c41565b6001815260408101919091529392505050565b600080600080610d1385610b2d565b600081815260208190526040902054909690955085945092505050565b60008060208385031215610d4357600080fd5b823567ffffffffffffffff80821115610d5b57600080fd5b818501915085601f830112610d6f57600080fd5b813581811115610d7e57600080fd5b86602060c083028501011115610d9357600080fd5b60209290920196919550909350505050565b60008060208385031215610db857600080fd5b823567ffffffffffffffff80821115610dd057600080fd5b818501915085601f830112610de457600080fd5b813581811115610df357600080fd5b86602060a083028501011115610d9357600080fd5b60008060408385031215610e1b57600080fd5b50508035926020909101359150565b600060a08284031215610e3c57600080fd5b50919050565b634e487b7160e01b600052602160045260246000fd5b8151606082019060048110610e7d57634e487b7160e01b600052602160045260246000fd5b80835250602083015160208301526040830151604083015292915050565b600060208284031215610ead57600080fd5b5035919050565b60208082526010908201526f39b2b73232b910109e9037b934b3b4b760811b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215610f0657600080fd5b81356001600160a01b0381168114610f1d57600080fd5b9392505050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561086f5761086f610f24565b600060018201610f5f57610f5f610f24565b5060010190565b6000825160005b81811015610f875760208186018101518583015201610f6d565b506000920191825250919050565b600060208284031215610fa757600080fd5b81518015158114610f1d57600080fd5b600060208284031215610fc957600080fd5b813567ffffffffffffffff81168114610f1d57600080fd5b600060208284031215610ff357600080fd5b505191905056fea2646970667358221220c0241e9efff6cacb5548883e39463986c365c3946a5a393e3484418cfb88e66a64736f6c63430008120033" # PASSWORD is the password used to unlock all accounts/wallets/addresses. PASSWORD="abc" diff --git a/server/asset/eth/coiner.go b/server/asset/eth/coiner.go index 5a4f26ca83..e19213c29e 100644 --- a/server/asset/eth/coiner.go +++ b/server/asset/eth/coiner.go @@ -9,6 +9,7 @@ import ( "fmt" "math/big" + "decred.org/dcrdex/dex" dexeth "decred.org/dcrdex/dex/networks/eth" "decred.org/dcrdex/server/asset" "github.com/ethereum/go-ethereum" @@ -20,11 +21,11 @@ var _ asset.Coin = (*redeemCoin)(nil) type baseCoin struct { backend *AssetBackend - vector *dexeth.SwapVector + locator []byte gasFeeCap uint64 gasTipCap uint64 txHash common.Hash - value *big.Int + value uint64 txData []byte serializedTx []byte contractVer uint32 @@ -54,29 +55,72 @@ func (be *AssetBackend) newSwapCoin(coinID []byte, contractData []byte) (*swapCo return nil, err } - vectors, err := dexeth.ParseInitiateDataV1(bc.txData) - if err != nil { - return nil, fmt.Errorf("unable to parse initiate call data: %v", err) - } + var sum uint64 + var vector *dexeth.SwapVector + switch bc.contractVer { + case 0: + var secretHash [32]byte + copy(secretHash[:], bc.locator) - vec, ok := vectors[bc.vector.SecretHash] - if !ok { - return nil, fmt.Errorf("tx %v does not contain initiation with locator %x", bc.txHash, bc.vector.Locator()) - } + inits, err := dexeth.ParseInitiateDataV0(bc.txData) + if err != nil { + return nil, fmt.Errorf("unable to parse v0 initiate call data: %v", err) + } + + init, ok := inits[secretHash] + if !ok { + return nil, fmt.Errorf("tx %v does not contain v0 initiation with secret hash %x", bc.txHash, secretHash[:]) + } + for _, in := range inits { + sum = +be.atomize(in.Value) + } + + vector = &dexeth.SwapVector{ + // From: , + To: init.Participant, + Value: init.Value, + SecretHash: secretHash, + LockTime: uint64(init.LockTime.Unix()), + } - if be.assetID == be.baseChainID { - var sum uint64 - for _, in := range vectors { - sum += in.Value + // if value < bc.vector.Value { + // return nil, fmt.Errorf("tx data value is too low. %d < %d", value, bc.vector.Value) + // } + // if init.Participant != bc.vector.To { + // return nil, fmt.Errorf("wrong participant in tx data. wanted %s, got %s", bc.vector.To, init.Participant) + // } + // if init.LockTime.UnixMilli() != int64(bc.vector.LockTime) { + // return nil, fmt.Errorf("wrong locktime in tx data. wanted %s, got %s", time.UnixMilli(int64(bc.vector.LockTime)), init.LockTime) + // } + case 1: + contractVector, err := dexeth.ParseV1Locator(bc.locator) + if err != nil { + return nil, fmt.Errorf("contract data vector decoding error: %w", err) + } + txVectors, err := dexeth.ParseInitiateDataV1(bc.txData) + if err != nil { + return nil, fmt.Errorf("unable to parse v1 initiate call data: %v", err) + } + txVector, ok := txVectors[contractVector.SecretHash] + if !ok { + return nil, fmt.Errorf("tx %v does not contain v1 initiation with vector %s", bc.txHash, contractVector) } - if sum != dexeth.WeiToGwei(bc.value) { - return nil, fmt.Errorf("tx %s value < sum of inits. %d < %d", bc.txHash, bc.value, sum) + if !dexeth.CompareVectors(contractVector, txVector) { + return nil, fmt.Errorf("contract and transaction vectors do not match. %+v != %+v", contractVector, txVector) } + vector = txVector + for _, v := range txVectors { + sum += be.atomize(v.Value) + } + } + + if be.assetID == BipID && bc.value < sum { + return nil, fmt.Errorf("tx %s value < sum of inits. %d < %d", bc.txHash, bc.value, sum) } return &swapCoin{ baseCoin: bc, - vector: vec, + vector: vector, }, nil } @@ -90,25 +134,26 @@ func (be *AssetBackend) newRedeemCoin(coinID []byte, contractData []byte) (*rede if err == asset.CoinNotFoundError { // If the coin is not found, check to see if the swap has been // redeemed by another transaction. - contractVer, locator, err := dexeth.DecodeLocator(contractData) + contractVer, locator, err := dexeth.DecodeContractData(contractData) if err != nil { return nil, err } - vector, err := dexeth.ParseV1Locator(locator) - if err != nil { - return nil, err + if be.contractVer != contractVer { + return nil, fmt.Errorf("wrong contract version for %s. wanted %d, got %d", dex.BipIDSymbol(be.assetID), be.contractVer, contractVer) } - be.log.Warnf("redeem coin with ID %x for locator %x was not found", coinID, locator) - status, err := be.node.status(be.ctx, be.assetID, vector) + + status, vec, err := be.node.statusAndVector(be.ctx, be.assetID, locator) if err != nil { return nil, err } + be.log.Warnf("redeem coin with ID %x for %s was not found", coinID, vec) if status.Step != dexeth.SSRedeemed { return nil, asset.CoinNotFoundError } + bc = &baseCoin{ backend: be, - vector: vector, + locator: locator, contractVer: contractVer, } return &redeemCoin{ @@ -119,22 +164,48 @@ func (be *AssetBackend) newRedeemCoin(coinID []byte, contractData []byte) (*rede return nil, err } - if bc.value.Cmp(new(big.Int)) != 0 { + if bc.value != 0 { return nil, fmt.Errorf("expected tx value of zero for redeem but got: %d", bc.value) } - redemptions, err := dexeth.ParseRedeemDataV1(bc.txData) - if err != nil { - return nil, fmt.Errorf("unable to parse redemption call data: %v", err) - } - redemption, ok := redemptions[bc.vector.SecretHash] - if !ok { - return nil, fmt.Errorf("tx %v does not contain redemption with locator %x", bc.txHash, bc.vector) + var secret [32]byte + switch bc.contractVer { + case 0: + var secretHash [32]byte + copy(secretHash[:], bc.locator) + redemptions, err := dexeth.ParseRedeemDataV0(bc.txData) + if err != nil { + return nil, fmt.Errorf("unable to parse v0 redemption call data: %v", err) + } + redemption, ok := redemptions[secretHash] + if !ok { + return nil, fmt.Errorf("tx %v does not contain redemption for v0 secret hash %x", bc.txHash, secretHash[:]) + } + secret = redemption.Secret + case 1: + vector, err := dexeth.ParseV1Locator(bc.locator) + if err != nil { + return nil, fmt.Errorf("error parsing vector from v1 locator '%x': %w", bc.locator, err) + } + redemptions, err := dexeth.ParseRedeemDataV1(bc.txData) + if err != nil { + return nil, fmt.Errorf("unable to parse v1 redemption call data: %v", err) + } + redemption, ok := redemptions[vector.SecretHash] + if !ok { + return nil, fmt.Errorf("tx %v does not contain redemption for v1 vector %s", bc.txHash, vector) + } + if !dexeth.CompareVectors(redemption.Contract, vector) { + return nil, fmt.Errorf("encoded vector %q doesn't match expected vector %q", redemption.Contract, vector) + } + secret = redemption.Secret + default: + return nil, fmt.Errorf("version %d redeem coin not supported", bc.contractVer) } return &redeemCoin{ baseCoin: bc, - secret: redemption.Secret, + secret: secret, }, nil } @@ -151,26 +222,20 @@ func (be *AssetBackend) baseCoin(coinID []byte, contractData []byte) (*baseCoin, } return nil, fmt.Errorf("unable to fetch transaction: %v", err) } - contractAddr := tx.To() - if *contractAddr != be.contractAddr { - return nil, fmt.Errorf("contract address is not supported: %v", contractAddr) - } serializedTx, err := tx.MarshalBinary() if err != nil { return nil, err } - contractVer, locator, err := dexeth.DecodeLocator(contractData) + contractVer, locator, err := dexeth.DecodeContractData(contractData) if err != nil { return nil, err } - if contractVer != ethContractVersion { - return nil, fmt.Errorf("contract version %d not supported, only %d", contractVer, ethContractVersion) - } - vector, err := dexeth.ParseV1Locator(locator) - if err != nil { - return nil, err + + contractAddr := tx.To() + if *contractAddr != be.contractAddr { + return nil, fmt.Errorf("contract address is not supported: %v", contractAddr) } // Gas price is not stored in the swap, and is used to determine if the @@ -186,7 +251,7 @@ func (be *AssetBackend) baseCoin(coinID []byte, contractData []byte) (*baseCoin, zero := new(big.Int) gasFeeCap := tx.GasFeeCap() if gasFeeCap == nil || gasFeeCap.Cmp(zero) <= 0 { - return nil, fmt.Errorf("Failed to parse gas fee cap from tx %s", txHash) + return nil, fmt.Errorf("failed to parse gas fee cap from tx %s", txHash) } gasFeeCapGwei, err := dexeth.WeiToGweiUint64(gasFeeCap) if err != nil { @@ -195,7 +260,7 @@ func (be *AssetBackend) baseCoin(coinID []byte, contractData []byte) (*baseCoin, gasTipCap := tx.GasTipCap() if gasTipCap == nil || gasTipCap.Cmp(zero) <= 0 { - return nil, fmt.Errorf("Failed to parse gas tip cap from tx %s", txHash) + return nil, fmt.Errorf("failed to parse gas tip cap from tx %s", txHash) } gasTipCapGwei, err := dexeth.WeiToGweiUint64(gasTipCap) if err != nil { @@ -204,11 +269,11 @@ func (be *AssetBackend) baseCoin(coinID []byte, contractData []byte) (*baseCoin, return &baseCoin{ backend: be, - vector: vector, + locator: locator, gasFeeCap: gasFeeCapGwei, gasTipCap: gasTipCapGwei, txHash: txHash, - value: tx.Value(), + value: be.atomize(tx.Value()), txData: tx.Data(), serializedTx: serializedTx, contractVer: contractVer, @@ -225,7 +290,7 @@ func (be *AssetBackend) baseCoin(coinID []byte, contractData []byte) (*baseCoin, // and the same account and nonce, effectively voiding the transaction we // expected to be mined. func (c *swapCoin) Confirmations(ctx context.Context) (int64, error) { - status, err := c.backend.node.status(ctx, c.backend.assetID, c.vector) + status, checkVec, err := c.backend.node.statusAndVector(ctx, c.backend.assetID, c.locator) if err != nil { return -1, err } @@ -238,39 +303,90 @@ func (c *swapCoin) Confirmations(ctx context.Context) (int64, error) { // Assume the tx still has a chance of being mined. return 0, nil } + // Any other swap state is ok. We are sure that initialization + // happened. + + // The swap initiation transaction has some number of + // confirmations, and we are sure the secret hash belongs to + // this swap. Assert that the value, receiver, and locktime are + // as expected. + switch c.contractVer { + case 0: + if checkVec.Value.Cmp(c.vector.Value) != 0 { + return -1, fmt.Errorf("tx data swap val (%d) does not match contract value (%d)", + c.vector.Value, checkVec.Value) + } + if checkVec.To != c.vector.To { + return -1, fmt.Errorf("tx data participant %q does not match contract value %q", + c.vector.To, checkVec.To) + } + if checkVec.LockTime != c.vector.LockTime { + return -1, fmt.Errorf("expected swap locktime (%d) does not match expected (%d)", + c.vector.LockTime, checkVec.LockTime) + } + case 1: + if err := setV1StatusBlockHeight(ctx, c.backend.node, status, c.baseCoin); err != nil { + return 0, err + } + } + bn, err := c.backend.node.blockNumber(ctx) if err != nil { return 0, fmt.Errorf("unable to fetch block number: %v", err) } - if status.Step == dexeth.SSInitiated { - return int64(bn - status.BlockHeight + 1), nil + return int64(bn - status.BlockHeight + 1), nil +} + +func setV1StatusBlockHeight(ctx context.Context, node ethFetcher, status *dexeth.SwapStatus, bc *baseCoin) error { + switch status.Step { + case dexeth.SSNone, dexeth.SSInitiated: + case dexeth.SSRedeemed, dexeth.SSRefunded: + // No block height for redeemed or refunded version 1 contracts, + // only SSInitiated. + r, err := node.transactionReceipt(ctx, bc.txHash) + if err != nil { + return err + } + status.BlockHeight = r.BlockNumber.Uint64() } - // Redeemed or refunded. Have to check the tx. - return c.backend.txConfirmations(ctx, c.txHash) + return nil } func (c *redeemCoin) Confirmations(ctx context.Context) (int64, error) { - status, err := c.backend.node.status(ctx, c.backend.assetID, c.vector) + status, err := c.backend.node.status(ctx, c.backend.assetID, c.locator) if err != nil { return -1, err } - // If swap is in None state, then the redemption can't possibly - // succeed as the swap must already be in the Initialized state - // to redeem. If the swap is in the Refunded state, then the - // redemption either failed or never happened. - if status.Step == dexeth.SSNone || status.Step == dexeth.SSRefunded { - return -1, fmt.Errorf("redemption in failed state with swap at %s state", status.Step) + // There should be no need to check the counter party, or value + // as a swap with a specific secret hash that has been redeemed + // wouldn't have been redeemed without ensuring the initiator + // is the expected address and value was also as expected. Also + // not validating the locktime, as the swap is redeemed and + // locktime no longer relevant. + if status.Step == dexeth.SSRedeemed { + if c.contractVer == 1 { + if err := setV1StatusBlockHeight(ctx, c.backend.node, status, c.baseCoin); err != nil { + return -1, err + } + } + bn, err := c.backend.node.blockNumber(ctx) + if err != nil { + return 0, fmt.Errorf("unable to fetch block number: %v", err) + } + return int64(bn - status.BlockHeight + 1), nil } - // If swap is in the Initiated state, the redemption may be // unmined. if status.Step == dexeth.SSInitiated { // Assume the tx still has a chance of being mined. return 0, nil } - - return c.backend.txConfirmations(ctx, c.txHash) + // If swap is in None state, then the redemption can't possibly + // succeed as the swap must already be in the Initialized state + // to redeem. If the swap is in the Refunded state, then the + // redemption either failed or never happened. + return -1, fmt.Errorf("redemption in failed state with swap at %s state", status.Step) } func (c *redeemCoin) Value() uint64 { return 0 } @@ -298,5 +414,5 @@ func (c *baseCoin) FeeRate() uint64 { // Value returns the value of one swap in order to validate during processing. func (c *swapCoin) Value() uint64 { - return c.vector.Value + return c.value } diff --git a/server/asset/eth/coiner_test.go b/server/asset/eth/coiner_test.go index 5d09103174..74cfad407c 100644 --- a/server/asset/eth/coiner_test.go +++ b/server/asset/eth/coiner_test.go @@ -6,7 +6,9 @@ package eth import ( "context" + "encoding/hex" "errors" + "fmt" "math/big" "testing" @@ -15,6 +17,8 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + // swapv0 "decred.org/dcrdex/dex/networks/eth/contracts/v0" + // swapv1 "decred.org/dcrdex/dex/networks/eth/contracts/v1" ) func randomAddress() *common.Address { @@ -25,11 +29,9 @@ func randomAddress() *common.Address { func TestNewRedeemCoin(t *testing.T) { contractAddr := randomAddress() + secret, secretHash, locator := secretB, secretHashB, locatorB var txHash [32]byte copy(txHash[:], encode.RandomBytes(32)) - contract := dexeth.EncodeContractData(1, vector2.Locator()) - vector3 := *vector2 - contract3 := dexeth.EncodeContractData(1, vector3.Locator()) const gasPrice = 30 const gasTipCap = 2 const value = 5e9 @@ -37,54 +39,66 @@ func TestNewRedeemCoin(t *testing.T) { const wantGasTipCap = 2 tests := []struct { name string - contract []byte + ver uint32 + locator []byte tx *types.Transaction swpErr, txErr error swap *dexeth.SwapState wantErr bool - }{{ - name: "ok redeem", - tx: tTx(gasPrice, gasTipCap, 0, contractAddr, redeemCalldata), - contract: contract, - }, { - name: "non zero value with redeem", - tx: tTx(gasPrice, gasTipCap, value, contractAddr, redeemCalldata), - contract: contract, - wantErr: true, - }, { - name: "unable to decode redeem data, must be redeem for redeem coin type", - tx: tTx(gasPrice, gasTipCap, 0, contractAddr, initCalldata), - contract: contract, - wantErr: true, - }, { - name: "tx coin id for redeem - contract not in tx", - tx: tTx(gasPrice, gasTipCap, value, contractAddr, redeemCalldata), - contract: contract3, - wantErr: true, - }, { - name: "tx not found, redeemed", - txErr: ethereum.NotFound, - swap: tSwap(97, initLocktime, 1000, tRedeem2.Secret, dexeth.SSRedeemed, &initParticipantAddr), - contract: contract, - }, { - name: "tx not found, not redeemed", - txErr: ethereum.NotFound, - swap: tSwap(97, initLocktime, 1000, tRedeem2.Secret, dexeth.SSInitiated, &initParticipantAddr), - contract: contract, - wantErr: true, - }, { - name: "tx not found, swap err", - txErr: ethereum.NotFound, - swpErr: errors.New("swap not found"), - contract: contract, - wantErr: true, - }} + }{ + { + name: "ok redeem v0", + tx: tTx(gasPrice, gasTipCap, 0, contractAddr, redeemCalldataV0), + swap: tSwap(97, initLocktime, 1000, secret, dexeth.SSRedeemed, &participantAddr), + locator: secretHash[:], + }, { + name: "ok redeem v1", + ver: 1, + tx: tTx(gasPrice, gasTipCap, 0, contractAddr, redeemCalldataV1), + swap: tSwap(97, initLocktime, 1000, secret, dexeth.SSRedeemed, &participantAddr), + locator: locator, + }, { + name: "non zero value with redeem", + tx: tTx(gasPrice, gasTipCap, value, contractAddr, redeemCalldataV0), + locator: secretHash[:], + wantErr: true, + }, { + name: "unable to decode redeem data, must be redeem for redeem coin type", + tx: tTx(gasPrice, gasTipCap, 0, contractAddr, initCalldataV0), + locator: secretHash[:], + wantErr: true, + }, { + name: "tx coin id for redeem - contract not in tx", + tx: tTx(gasPrice, gasTipCap, value, contractAddr, redeemCalldataV0), + locator: encode.RandomBytes(32), + wantErr: true, + }, { + name: "tx not found, redeemed", + txErr: ethereum.NotFound, + swap: tSwap(97, initLocktime, 1000, secret, dexeth.SSRedeemed, &participantAddr), + locator: secretHash[:], + }, { + name: "tx not found, not redeemed", + txErr: ethereum.NotFound, + swap: tSwap(97, initLocktime, 1000, secret, dexeth.SSInitiated, &participantAddr), + locator: secretHash[:], + wantErr: true, + }, { + name: "tx not found, swap err", + txErr: ethereum.NotFound, + swpErr: errors.New("swap not found"), + locator: secretHash[:], + wantErr: true, + }, + } for _, test := range tests { node := &testNode{ tx: test.tx, txErr: test.txErr, - swp: test.swap, swpErr: test.swpErr, + swp: map[string]*dexeth.SwapState{ + string(secretHash[:]): test.swap, + }, } eth := &AssetBackend{ baseBackend: &baseBackend{ @@ -95,8 +109,9 @@ func TestNewRedeemCoin(t *testing.T) { initTxSize: uint32(dexeth.InitGas(1, 0)), assetID: BipID, log: tLogger, + atomize: dexeth.WeiToGwei, } - rc, err := eth.newRedeemCoin(txHash[:], test.contract) + rc, err := eth.newRedeemCoin(txHash[:], dexeth.EncodeContractData(test.ver, test.locator)) if test.wantErr { if err == nil { t.Fatalf("expected error for test %q", test.name) @@ -107,9 +122,8 @@ func TestNewRedeemCoin(t *testing.T) { t.Fatalf("unexpected error for test %q: %v", test.name, err) } - if test.txErr == nil && (rc.vector.SecretHash != tRedeem2.V.SecretHash || - rc.secret != tRedeem2.Secret || - rc.value.Uint64() != 0 || + if test.txErr == nil && (rc.secret != secret || + rc.value != 0 || rc.gasFeeCap != wantGas || rc.gasTipCap != wantGasTipCap) { t.Fatalf("returns do not match expected for test %q / %v", test.name, rc) @@ -123,9 +137,11 @@ func TestNewSwapCoin(t *testing.T) { copy(txHash[:], encode.RandomBytes(32)) txCoinIDBytes := txHash[:] badCoinIDBytes := encode.RandomBytes(39) - const gasPrice = 30 - value := tSwap1.Value + tSwap2.Value - const gasTipCap = 2 + const ( + gasPrice = 30 + gasTipCap = 2 + ) + txVal := initValue * 2 wantGas, err := dexeth.WeiToGweiUint64(big.NewInt(3e10)) if err != nil { t.Fatal(err) @@ -134,82 +150,94 @@ func TestNewSwapCoin(t *testing.T) { if err != nil { t.Fatal(err) } - goodContract := dexeth.EncodeContractData(1, vector2.Locator()) - vector3 := *vector2 - vector3.SecretHash = [32]byte{3} - badContract := dexeth.EncodeContractData(1, vector3.Locator()) + tests := []struct { - name string - coinID []byte - contract []byte - tx *types.Transaction - swpErr, txErr error - wantErr bool - }{{ - name: "ok init", - tx: tTx(gasPrice, gasTipCap, value, contractAddr, initCalldata), - coinID: txCoinIDBytes, - contract: goodContract, - }, { - name: "contract incorrect length", - tx: tTx(gasPrice, gasTipCap, value, contractAddr, initCalldata), - coinID: txCoinIDBytes, - contract: goodContract[:len(goodContract)-1], - wantErr: true, - }, { - name: "tx has no data", - tx: tTx(gasPrice, gasTipCap, value, contractAddr, nil), - coinID: txCoinIDBytes, - contract: goodContract, - wantErr: true, - }, { - name: "unable to decode init data, must be init for init coin type", - tx: tTx(gasPrice, gasTipCap, value, contractAddr, redeemCalldata), - coinID: txCoinIDBytes, - contract: goodContract, - wantErr: true, - }, { - name: "unable to decode CoinID", - tx: tTx(gasPrice, gasTipCap, value, contractAddr, initCalldata), - contract: goodContract, - wantErr: true, - }, { - name: "invalid coinID", - tx: tTx(gasPrice, gasTipCap, value, contractAddr, initCalldata), - coinID: badCoinIDBytes, - contract: goodContract, - wantErr: true, - }, { - name: "transaction error", - tx: tTx(gasPrice, gasTipCap, value, contractAddr, initCalldata), - coinID: txCoinIDBytes, - contract: goodContract, - txErr: errors.New(""), - wantErr: true, - }, { - name: "transaction not found error", - tx: tTx(gasPrice, gasTipCap, value, contractAddr, initCalldata), - coinID: txCoinIDBytes, - contract: goodContract, - txErr: ethereum.NotFound, - wantErr: true, - }, { - name: "wrong contract", - tx: tTx(gasPrice, gasTipCap, value, randomAddr, initCalldata), - coinID: txCoinIDBytes, - contract: badContract, - wantErr: true, - // }, { TODO: This test was doing nothing, I think. - // name: "tx coin id for swap - contract not in tx", - // tx: tTx(gasPrice, gasTipCap, value, contractAddr, initCalldata), - // coinID: txCoinIDBytes, - // contract: encode.RandomBytes(32), - // wantErr: true, - }} + name string + ver uint32 + coinID []byte + locator []byte + tx *types.Transaction + swap *dexeth.SwapState + txErr error + wantErr bool + }{ + { + name: "ok init v0", + tx: tTx(gasPrice, gasTipCap, txVal, contractAddr, initCalldataV0), + coinID: txCoinIDBytes, + locator: secretHashA[:], + swap: tSwap(97, initLocktime, initValue, secretA, dexeth.SSRedeemed, &participantAddr), + }, { + name: "ok init v1", + ver: 1, + tx: tTx(gasPrice, gasTipCap, txVal, contractAddr, initCalldataV1), + coinID: txCoinIDBytes, + locator: locatorA, + swap: tSwap(97, initLocktime, initValue, secretA, dexeth.SSRedeemed, &participantAddr), + }, { + name: "contract incorrect length", + tx: tTx(gasPrice, gasTipCap, txVal, contractAddr, initCalldataV0), + coinID: txCoinIDBytes, + locator: secretHashA[:31], + wantErr: true, + }, { + name: "tx has no data", + tx: tTx(gasPrice, gasTipCap, txVal, contractAddr, nil), + coinID: txCoinIDBytes, + locator: secretHashA[:], + wantErr: true, + }, { + name: "unable to decode init data, must be init for init coin type", + tx: tTx(gasPrice, gasTipCap, txVal, contractAddr, redeemCalldataV0), + coinID: txCoinIDBytes, + locator: secretHashA[:], + wantErr: true, + }, { + name: "unable to decode CoinID", + tx: tTx(gasPrice, gasTipCap, txVal, contractAddr, initCalldataV0), + locator: secretHashA[:], + wantErr: true, + }, { + name: "invalid coinID", + tx: tTx(gasPrice, gasTipCap, txVal, contractAddr, initCalldataV0), + coinID: badCoinIDBytes, + locator: secretHashA[:], + wantErr: true, + }, { + name: "transaction error", + tx: tTx(gasPrice, gasTipCap, txVal, contractAddr, initCalldataV0), + coinID: txCoinIDBytes, + locator: secretHashA[:], + txErr: errors.New(""), + wantErr: true, + }, { + name: "transaction not found error", + tx: tTx(gasPrice, gasTipCap, txVal, contractAddr, initCalldataV0), + coinID: txCoinIDBytes, + locator: secretHashA[:], + txErr: ethereum.NotFound, + wantErr: true, + }, { + name: "wrong contract", + tx: tTx(gasPrice, gasTipCap, txVal, randomAddr, initCalldataV0), + coinID: txCoinIDBytes, + locator: secretHashA[:], + wantErr: true, + }, { + name: "tx coin id for swap - contract not in tx", + tx: tTx(gasPrice, gasTipCap, txVal, contractAddr, initCalldataV0), + coinID: txCoinIDBytes, + locator: encode.RandomBytes(32), + wantErr: true, + }, + } for _, test := range tests { node := &testNode{ tx: test.tx, txErr: test.txErr, + swp: map[string]*dexeth.SwapState{ + string(secretHashA[:]): test.swap, + }, } eth := &AssetBackend{ baseBackend: &baseBackend{ @@ -220,7 +248,7 @@ func TestNewSwapCoin(t *testing.T) { initTxSize: uint32(dexeth.InitGas(1, 0)), atomize: dexeth.WeiToGwei, } - sc, err := eth.newSwapCoin(test.coinID, test.contract) + sc, err := eth.newSwapCoin(test.coinID, dexeth.EncodeContractData(test.ver, test.locator)) if test.wantErr { if err == nil { t.Fatalf("expected error for test %q", test.name) @@ -231,12 +259,21 @@ func TestNewSwapCoin(t *testing.T) { t.Fatalf("unexpected error for test %q: %v", test.name, err) } - if sc.vector.To != tSwap2.Participant || - sc.vector.SecretHash != tRedeem2.V.SecretHash || - dexeth.WeiToGwei(sc.value) != value || + if sc.vector.To != participantAddr || + sc.vector.SecretHash != secretHashA || + sc.value != txVal || + sc.vector.Value.Cmp(dexeth.GweiToWei(initValue)) != 0 || sc.gasFeeCap != wantGas || sc.gasTipCap != wantGasTipCap || - sc.vector.LockTime != tSwap2.RefundTimestamp { + sc.vector.LockTime != initLocktime { + + fmt.Println("to:", sc.vector.To, participantAddr) + fmt.Println("secret hash:", hex.EncodeToString(sc.vector.SecretHash[:]), hex.EncodeToString(secretHashA[:])) + fmt.Println("value:", sc.value, txVal) + fmt.Println("swap value:", sc.vector.Value, dexeth.GweiToWei(initValue)) + fmt.Println("gas fee cap:", sc.gasFeeCap, wantGas) + fmt.Println("gas tip cap:", sc.gasTipCap, wantGasTipCap) + fmt.Println("lock time:", sc.vector.LockTime, initLocktime) t.Fatalf("returns do not match expected for test %q / %v", test.name, sc) } @@ -251,68 +288,113 @@ type Confirmer interface { func TestConfirmations(t *testing.T) { contractAddr, nullAddr := new(common.Address), new(common.Address) copy(contractAddr[:], encode.RandomBytes(20)) - txHash := bytesToArray(encode.RandomBytes(32)) - secret := tRedeem2.Secret + secret, secretHash := secretB, secretHashB + var txHash [32]byte + copy(txHash[:], encode.RandomBytes(32)) const gasPrice = 30 const gasTipCap = 2 - swapVal := tSwap2.Value - txVal := tSwap1.Value + tSwap2.Value - const blockNumber = 100 + txVal := initValue * 2 + oneGweiMore := initValue + 1 tests := []struct { name string + ver uint32 swap *dexeth.SwapState + receipt *types.Receipt // v1 only bn uint64 value uint64 wantConfs int64 swapErr, bnErr error wantErr, redeem bool - }{{ - name: "ok has confs value not verified", - bn: 100, - swap: tSwap(97, initLocktime, swapVal, secret, dexeth.SSInitiated, &initParticipantAddr), - value: txVal, - wantConfs: 4, - }, { - name: "ok no confs", - swap: tSwap(0, 0, 0, secret, dexeth.SSNone, nullAddr), - value: txVal, - }, { - name: "ok redeem swap status redeemed", - bn: 97, - swap: tSwap(97, initLocktime, swapVal, secret, dexeth.SSRedeemed, &initParticipantAddr), - value: 0, - wantConfs: 4, - redeem: true, - }, { - name: "ok redeem swap status initiated", - swap: tSwap(blockNumber, initLocktime, swapVal, secret, dexeth.SSInitiated, &initParticipantAddr), - value: 0, - redeem: true, - wantConfs: 0, // SSInitiated is always zero confs for redeems. - }, { - name: "redeem bad swap state None", - swap: tSwap(0, 0, 0, secret, dexeth.SSNone, nullAddr), - value: 0, - wantErr: true, - redeem: true, - }, { - name: "error getting swap", - swapErr: errors.New(""), - value: txVal, - wantErr: true, - }, { - name: "block number error", - swap: tSwap(97, initLocktime, swapVal, secret, dexeth.SSInitiated, &initParticipantAddr), - value: txVal, - bnErr: errors.New(""), - wantErr: true, - }} + }{ + { + name: "ok has confs value not verified v0", + bn: 100, + swap: tSwap(97, initLocktime, initValue, secret, dexeth.SSInitiated, &participantAddr), + value: txVal, + wantConfs: 4, + }, { + name: "ok has confs value not verified v1", + ver: 1, + bn: 100, + swap: tSwap(97, initLocktime, initValue, secret, dexeth.SSInitiated, &participantAddr), + value: txVal, + wantConfs: 4, + }, { + name: "ok no confs", + swap: tSwap(0, 0, 0, secret, dexeth.SSNone, nullAddr), + value: txVal, + }, { + name: "ok 1 conf v1", + ver: 1, + bn: 97, + receipt: &types.Receipt{ + BlockNumber: big.NewInt(97), + }, + swap: tSwap(0, 0, 0, secret, dexeth.SSRedeemed, nullAddr), + value: txVal, + wantConfs: 1, + }, { + name: "ok redeem swap status redeemed", + bn: 97, + swap: tSwap(97, initLocktime, initValue, secret, dexeth.SSRedeemed, &participantAddr), + value: 0, + wantConfs: 1, + redeem: true, + }, { + name: "ok redeem swap status initiated", + swap: tSwap(97, initLocktime, initValue, secret, dexeth.SSInitiated, &participantAddr), + value: 0, + redeem: true, + }, { + name: "redeem bad swap state None", + swap: tSwap(0, 0, 0, secret, dexeth.SSNone, nullAddr), + value: 0, + wantErr: true, + redeem: true, + }, { + name: "error getting swap", + swapErr: errors.New("test error"), + value: txVal, + wantErr: true, + }, { + name: "value differs from initial transaction", + swap: tSwap(99, initLocktime, oneGweiMore, secret, dexeth.SSInitiated, &participantAddr), + value: txVal, + wantErr: true, + }, { + name: "participant differs from initial transaction", + swap: tSwap(99, initLocktime, initValue, secret, dexeth.SSInitiated, nullAddr), + value: txVal, + wantErr: true, + // }, { + // name: "locktime not an int64", + // swap: tSwap(99, new(big.Int).SetUint64(^uint64(0)), value, secret, dexeth.SSInitiated, &participantAddr), + // value: value, + // ct: sctInit, + // wantErr: true, + }, { + name: "locktime differs from initial transaction", + swap: tSwap(99, 0, initValue, secret, dexeth.SSInitiated, &participantAddr), + value: txVal, + wantErr: true, + }, { + name: "block number error", + swap: tSwap(97, initLocktime, initValue, secret, dexeth.SSInitiated, &participantAddr), + value: txVal, + bnErr: errors.New("test error"), + wantErr: true, + }, + } for _, test := range tests { node := &testNode{ - swp: test.swap, swpErr: test.swapErr, - blkNum: blockNumber, + blkNum: test.bn, blkNumErr: test.bnErr, + swp: map[string]*dexeth.SwapState{ + string(secretHash[:]): test.swap, + string(locatorA): test.swap, + }, + receipt: test.receipt, } eth := &AssetBackend{ baseBackend: &baseBackend{ @@ -324,11 +406,15 @@ func TestConfirmations(t *testing.T) { atomize: dexeth.WeiToGwei, } - swapData := dexeth.EncodeContractData(1, vector2.Locator()) - - if test.swap != nil { - node.rcpt = &types.Receipt{BlockNumber: big.NewInt(int64(test.swap.BlockHeight))} + locator := secretHash[:] + redeemCalldata := redeemCalldataV0 + initCalldata := initCalldataV0 + if test.ver == 1 { + redeemCalldata = redeemCalldataV1 + initCalldata = initCalldataV1 + locator = locatorA } + swapData := dexeth.EncodeContractData(test.ver, locator) var confirmer Confirmer var err error @@ -345,7 +431,7 @@ func TestConfirmations(t *testing.T) { _ = confirmer.String() // unrelated panic test - confs, err := confirmer.Confirmations(nil) + confs, err := confirmer.Confirmations(context.TODO()) if test.wantErr { if err == nil { t.Fatalf("expected error for test %q", test.name) @@ -353,7 +439,7 @@ func TestConfirmations(t *testing.T) { continue } if err != nil { - t.Fatalf("unexpected error for test %q: %v", test.name, err) + t.Fatalf("unexpected error for test %q (redeem = %t): %v", test.name, test.redeem, err) } if confs != test.wantConfs { t.Fatalf("want %d but got %d confs for test: %v", test.wantConfs, confs, test.name) @@ -362,29 +448,67 @@ func TestConfirmations(t *testing.T) { } // func TestGeneratePackedInits(t *testing.T) { -// hexToHash := func(s string) (h [32]byte) { -// b, _ := hex.DecodeString(s) -// copy(h[:], b) -// return +// initsV0 := []swapv0.ETHSwapInitiation{ +// { +// RefundTimestamp: big.NewInt(int64(swapVectorA.LockTime)), +// SecretHash: swapVectorA.SecretHash, +// Value: swapVectorA.Value, +// Participant: swapVectorA.To, +// }, +// { +// RefundTimestamp: big.NewInt(int64(swapVectorB.LockTime)), +// SecretHash: swapVectorB.SecretHash, +// Value: swapVectorB.Value, +// Participant: swapVectorB.To, +// }, +// } +// dataV0, err := dexeth.ABIs[0].Pack("initiate", initsV0) +// if err != nil { +// t.Fatalf("Pack error: %v", err) +// } +// fmt.Println("V0 Init Data", hex.EncodeToString(dataV0)) + +// init0 := dexeth.SwapVectorToAbigen(swapVectorA) +// init1 := dexeth.SwapVectorToAbigen(swapVectorB) +// inits := []swapv1.ETHSwapVector{init0, init1} + +// dataV1, err := dexeth.ABIs[1].Pack("initiate", inits) +// if err != nil { +// t.Fatalf("Pack error: %v", err) // } -// inits := []swapv0.ETHSwapInitiation{ +// fmt.Println("V1 Init Data:", hex.EncodeToString(dataV1)) + +// redeemsV0 := []swapv0.ETHSwapRedemption{ +// { +// SecretHash: secretHashA, +// Secret: secretA, +// }, +// { +// SecretHash: secretHashB, +// Secret: secretB, +// }, +// } +// dataV0, err = dexeth.ABIs[0].Pack("redeem", redeemsV0) +// if err != nil { +// t.Fatalf("Pack error: %v", err) +// } +// fmt.Println("V0 Redeem Data", hex.EncodeToString(dataV0)) + +// redeemsV1 := []swapv1.ETHSwapRedemption{ // { -// RefundTimestamp: big.NewInt(1632112916), -// SecretHash: hexToHash("8b3e4acc53b664f9cf6fcac0adcd328e95d62ba1f4379650ae3e1460a0f9d1a1"), -// Value: dexeth.GweiToWei(25e8), -// Participant: common.HexToAddress("0x345853e21b1d475582e71cc269124ed5e2dd3422"), +// V: init0, +// Secret: secretA, // }, // { -// RefundTimestamp: big.NewInt(1632112916), -// SecretHash: hexToHash("ebdc4c31b88d0c8f4d644591a8e00e92b607f920ad8050deb7c7469767d9c561"), -// Value: dexeth.GweiToWei(25e8), -// Participant: common.HexToAddress("0x345853e21b1d475582e71cc269124ed5e2dd3422"), +// V: init1, +// Secret: secretB, // }, // } -// data, err := dexeth.ABIs[0].Pack("initiate", inits) +// dataV1, err = dexeth.ABIs[1].Pack("redeem", redeemsV1) // if err != nil { // t.Fatalf("Pack error: %v", err) // } +// fmt.Println("V1 Redeem Data", hex.EncodeToString(dataV1)) -// fmt.Printf("tx data: %x \n", data) +// t.Fatal("ok") // } diff --git a/server/asset/eth/eth.go b/server/asset/eth/eth.go index 12891bb851..14140ab6bc 100644 --- a/server/asset/eth/eth.go +++ b/server/asset/eth/eth.go @@ -8,6 +8,7 @@ import ( "bytes" "context" "crypto/sha256" + "encoding/json" "errors" "fmt" "math/big" @@ -23,91 +24,118 @@ import ( "decred.org/dcrdex/server/asset" "github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" ) +const ( + BipID = 60 +) + +var ( + _ asset.Driver = (*Driver)(nil) + _ asset.TokenBacker = (*ETHBackend)(nil) + + defaultProtocolVersion = dexeth.ProtocolVersionV1Contracts + protocolVersionsFilePath = "evm-protocol-overrides.json" + protocolVersionsOverrides = make(map[uint32]dexeth.ProtocolVersion) + + backendInfo = &asset.BackendInfo{ + SupportsDynamicTxFee: true, + } + + testTokenID, _ = dex.BipSymbolID("dextt.eth") + usdcID, _ = dex.BipSymbolID("usdc.eth") +) + +func init() { + // Load any legacy/reverted protocol versions. + if b, err := os.ReadFile(protocolVersionsFilePath); err == nil && len(b) > 0 { + var symbolVers map[string]uint32 + if err := json.Unmarshal(b, &symbolVers); err != nil { + panic(fmt.Sprintf("provided protocol override file at %q did not parse: %v", protocolVersionsFilePath, err)) + } + for symbol, v := range symbolVers { + assetID, found := dex.BipSymbolID(symbol) + if !found { + panic(fmt.Sprintf("asset %s specified in protocol override file is not known", symbol)) + } + protocolVersionsOverrides[assetID] = ProtocolVersion(v) + } + } + + asset.Register(BipID, &Driver{ + DriverBase: DriverBase{ + ProtocolVersion: ProtocolVersion(BipID), + UI: dexeth.UnitInfo, + Nam: "Ethereum", + }, + }) + + registerToken(testTokenID, ProtocolVersion(testTokenID)) + registerToken(usdcID, ProtocolVersion(usdcID)) +} + +// ProtocolVersion returns the default protocol version unless a reversion is +// specified in the file at protocolVersionsFilePath. +func ProtocolVersion(assetID uint32) dexeth.ProtocolVersion { + v, found := protocolVersionsOverrides[assetID] + if found { + return v + } + return defaultProtocolVersion +} + type VersionedToken struct { *dexeth.Token - Ver uint32 + ContractVersion uint32 } var registeredTokens = make(map[uint32]*VersionedToken) -func registerToken(assetID uint32, ver uint32) { +func registerToken(assetID uint32, protocolVer dexeth.ProtocolVersion) { token, exists := dexeth.Tokens[assetID] if !exists { panic(fmt.Sprintf("no token constructor for asset ID %d", assetID)) } - asset.RegisterToken(assetID, &TokenDriver{ + drv := &TokenDriver{ DriverBase: DriverBase{ - Ver: ver, - UI: token.UnitInfo, - Nam: token.Name, + ProtocolVersion: protocolVer, + UI: token.UnitInfo, + Nam: token.Name, }, Token: token.Token, - }) + } + asset.RegisterToken(assetID, drv) registeredTokens[assetID] = &VersionedToken{ - Token: token, - Ver: ver, + Token: token, + ContractVersion: protocolVer.ContractVersion(), } } -func init() { - asset.Register(BipID, &Driver{ - DriverBase: DriverBase{ - Ver: version, - UI: dexeth.UnitInfo, - Nam: "Ethereum", - }, - }) - - registerToken(testTokenID, ethContractVersion) - registerToken(usdcID, ethContractVersion) -} - -const ( - BipID = 60 - ethContractVersion = 1 - version = 1 -) - -var ( - _ asset.Driver = (*Driver)(nil) - _ asset.TokenBacker = (*ETHBackend)(nil) - - backendInfo = &asset.BackendInfo{ - SupportsDynamicTxFee: true, - } - - testTokenID, _ = dex.BipSymbolID("dextt.eth") - usdcID, _ = dex.BipSymbolID("usdc.eth") -) - func networkToken(vToken *VersionedToken, net dex.Network) (netToken *dexeth.NetToken, contract *dexeth.SwapContract, err error) { netToken, found := vToken.NetTokens[net] if !found { return nil, nil, fmt.Errorf("no addresses for %s on %s", vToken.Name, net) } - contract, found = netToken.SwapContracts[vToken.Ver] + contract, found = netToken.SwapContracts[vToken.ContractVersion] if !found || contract.Address == (common.Address{}) { - return nil, nil, fmt.Errorf("no version %d address for %s on %s", vToken.Ver, vToken.Name, net) + return nil, nil, fmt.Errorf("no version %d address for %s on %s", vToken.ContractVersion, vToken.Name, net) } return } type DriverBase struct { - UI dex.UnitInfo - Ver uint32 - Nam string + UI dex.UnitInfo + ProtocolVersion dexeth.ProtocolVersion + Nam string } // Version returns the Backend implementation's version number. func (d *DriverBase) Version() uint32 { - return d.Ver + return uint32(d.ProtocolVersion) } // DecodeCoinID creates a human-readable representation of a coin ID for @@ -164,11 +192,13 @@ type ethFetcher interface { connect(ctx context.Context) error suggestGasTipCap(ctx context.Context) (*big.Int, error) transaction(ctx context.Context, hash common.Hash) (tx *types.Transaction, isMempool bool, err error) + transactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) // token- and asset-specific methods loadToken(ctx context.Context, assetID uint32, vToken *VersionedToken) error - status(ctx context.Context, assetID uint32, vector *dexeth.SwapVector) (*dexeth.SwapStatus, error) + status(ctx context.Context, assetID uint32, locator []byte) (*dexeth.SwapStatus, error) + vector(ctx context.Context, assetID uint32, locator []byte) (*dexeth.SwapVector, error) + statusAndVector(ctx context.Context, assetID uint32, locator []byte) (*dexeth.SwapStatus, *dexeth.SwapVector, error) accountBalance(ctx context.Context, assetID uint32, addr common.Address) (*big.Int, error) - receipt(context.Context, common.Hash) (*types.Receipt, error) } type baseBackend struct { @@ -215,6 +245,7 @@ type AssetBackend struct { redeemSize uint64 contractAddr common.Address + contractVer uint32 } // ETHBackend implements some Ethereum-specific methods. @@ -238,14 +269,15 @@ var _ asset.AccountBalancer = (*ETHBackend)(nil) // unconnectedETH returns a Backend without a node. The node should be set // before use. -func unconnectedETH(bipID uint32, contractAddr common.Address, vTokens map[uint32]*VersionedToken, logger dex.Logger, net dex.Network) (*ETHBackend, error) { +func unconnectedETH(bipID uint32, vTokens map[uint32]*VersionedToken, logger dex.Logger, net dex.Network) (*ETHBackend, error) { // TODO: At some point multiple contracts will need to be used, at // least for transitory periods when updating the contract, and // possibly a random contract setup, and so this section will need to // change to support multiple contracts. - contractAddr, exists := dexeth.ContractAddresses[ethContractVersion][net] + contractVer := ProtocolVersion(bipID).ContractVersion() + contractAddr, exists := dexeth.ContractAddresses[contractVer][net] if !exists || contractAddr == (common.Address{}) { - return nil, fmt.Errorf("no eth contract for version %d, net %s", ethContractVersion, net) + return nil, fmt.Errorf("no eth contract for version %d, net %s", contractVer, net) } return ÐBackend{&AssetBackend{ baseBackend: &baseBackend{ @@ -259,10 +291,11 @@ func unconnectedETH(bipID uint32, contractAddr common.Address, vTokens map[uint3 log: logger, contractAddr: contractAddr, blockChans: make(map[chan *asset.BlockUpdate]struct{}), - initTxSize: uint32(dexeth.InitGas(1, ethContractVersion)), - redeemSize: dexeth.RedeemGas(1, ethContractVersion), + initTxSize: uint32(dexeth.InitGas(1, contractVer)), + redeemSize: dexeth.RedeemGas(1, contractVer), assetID: bipID, atomize: dexeth.WeiToGwei, + contractVer: contractVer, }}, nil } @@ -343,17 +376,18 @@ func NewEVMBackend( baseChainID, net, log := cfg.AssetID, cfg.Net, cfg.Logger assetName := strings.ToUpper(dex.BipIDSymbol(baseChainID)) + contractVer := ProtocolVersion(baseChainID).ContractVersion() - netAddrs, found := contractAddrs[ethContractVersion] + netAddrs, found := contractAddrs[contractVer] if !found { - return nil, fmt.Errorf("no contract address for %s version %d", assetName, ethContractVersion) + return nil, fmt.Errorf("no contract address for %s version %d", assetName, contractVer) } contractAddr, found := netAddrs[net] if !found { - return nil, fmt.Errorf("no contract address for %s version %d on %s", assetName, ethContractVersion, net) + return nil, fmt.Errorf("no contract address for %s version %d on %s", assetName, contractVer, net) } - eth, err := unconnectedETH(baseChainID, contractAddr, vTokens, log, net) + eth, err := unconnectedETH(baseChainID, vTokens, log, net) if err != nil { return nil, err } @@ -574,33 +608,27 @@ func (be *AssetBackend) sendBlockUpdate(u *asset.BlockUpdate) { // ValidateContract ensures that contractData encodes both the expected contract // version and a secret hash. func (eth *ETHBackend) ValidateContract(contractData []byte) error { - ver, _, err := dexeth.DecodeLocator(contractData) + _, _, err := dexeth.DecodeContractData(contractData) if err != nil { // ensures secretHash is proper length return err } - - if ver != ethContractVersion { - return fmt.Errorf("incorrect swap contract version %d, wanted %d", ver, ethContractVersion) - } return nil } // ValidateContract ensures that contractData encodes both the expected swap // contract version and a secret hash. func (eth *TokenBackend) ValidateContract(contractData []byte) error { - ver, _, err := dexeth.DecodeLocator(contractData) + contractVer, _, err := dexeth.DecodeContractData(contractData) if err != nil { // ensures secretHash is proper length return err } - - if ver != eth.VersionedToken.Ver { - return fmt.Errorf("incorrect token swap contract version %d, wanted %d", ver, eth.VersionedToken.Ver) - } - _, _, err = networkToken(eth.VersionedToken, eth.net) if err != nil { return fmt.Errorf("error locating token: %v", err) } + if contractVer != eth.VersionedToken.ContractVersion { + return fmt.Errorf("incorrect token swap contract version %d, wanted %d", contractVer, eth.VersionedToken.ContractVersion) + } return nil } @@ -633,22 +661,30 @@ func (be *AssetBackend) Contract(coinID, contractData []byte) (*asset.Contract, } // ValidateSecret checks that the secret satisfies the secret hash. -func (eth *baseBackend) ValidateSecret(secret, contractData []byte) bool { - contractVer, locator, err := dexeth.DecodeLocator(contractData) +func (eth *AssetBackend) ValidateSecret(secret, contractData []byte) bool { + contractVer, locator, err := dexeth.DecodeContractData(contractData) if err != nil { - eth.baseLogger.Errorf("unable to decode contract data: %w", err) + eth.log.Errorf("Error decoding contract data for validation: %v", err) return false } - if contractVer != ethContractVersion { - return false - } - vec, err := dexeth.ParseV1Locator(locator) - if err != nil { - eth.baseLogger.Errorf("unable to parse v1 locator: %w", err) + var secretHash [32]byte + switch contractVer { + case 0: + copy(secretHash[:], locator) + case 1: + v, err := dexeth.ParseV1Locator(locator) + if err != nil { + eth.log.Errorf("ValidateSecret locator parsing error: %v", err) + return false + } + secretHash = v.SecretHash + default: + eth.log.Errorf("ValidateSecret received unknown contract version: %d", contractVer) return false } + sh := sha256.Sum256(secret) - return bytes.Equal(sh[:], vec.SecretHash[:]) + return bytes.Equal(sh[:], secretHash[:]) } // Synced is true if the blockchain is ready for action. @@ -796,29 +832,3 @@ func (eth *ETHBackend) run(ctx context.Context) { } } } - -func (eth *baseBackend) txConfirmations(ctx context.Context, txHash common.Hash) (int64, error) { - r, err := eth.node.receipt(ctx, txHash) - if err != nil { - // Could be mempool. - if _, isMempool, err2 := eth.node.transaction(ctx, txHash); err2 != nil { - if errors.Is(err2, ethereum.NotFound) { - return 0, asset.CoinNotFoundError - } - return 0, fmt.Errorf("errors encountered searching for transaction: %v, %v", err, err2) - } else if isMempool { - return 0, nil - } - return 0, err - } - - if r.BlockNumber == nil || r.BlockNumber.Int64() <= 0 { - return 0, nil - } - - bn, err := eth.node.blockNumber(ctx) - if err != nil { - return 0, fmt.Errorf("unable to fetch block number: %v", err) - } - return int64(bn) - r.BlockNumber.Int64() + 1, nil -} diff --git a/server/asset/eth/eth_test.go b/server/asset/eth/eth_test.go index 3085f3d2d7..b4f22166de 100644 --- a/server/asset/eth/eth_test.go +++ b/server/asset/eth/eth_test.go @@ -21,7 +21,6 @@ import ( "decred.org/dcrdex/dex/calc" "decred.org/dcrdex/dex/encode" dexeth "decred.org/dcrdex/dex/networks/eth" - swapv1 "decred.org/dcrdex/dex/networks/eth/contracts/v1" "decred.org/dcrdex/server/asset" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" @@ -34,66 +33,100 @@ var ( _ ethFetcher = (*testNode)(nil) tLogger = dex.StdOutLogger("ETHTEST", dex.LevelTrace) tCtx context.Context - tSwap1 = &swapv1.ETHSwapVector{ - SecretHash: bytesToArray([]byte("1")), - Initiator: common.BytesToAddress([]byte("initiator1")), - RefundTimestamp: 1, - Participant: common.BytesToAddress([]byte("participant1")), - Value: 1, - } - tSwap2 = &swapv1.ETHSwapVector{ - SecretHash: bytesToArray([]byte("2")), - Initiator: common.BytesToAddress([]byte("initiator2")), - RefundTimestamp: 2, - Participant: common.BytesToAddress([]byte("participant2")), - Value: 2, - } - // redeemCalldata encodes [tSwap1, tSwap2] - initCalldata = mustParseHex("64a97bff00000000000000000000000000000000000000" + - "00000000000000000000000020000000000000000000000000000000000000000000000000" + - "00000000000000023100000000000000000000000000000000000000000000000000000000" + - "00000000000000000000000000000000000000000000000000696e69746961746f72310000" + - "00000000000000000000000000000000000000000000000000000000000100000000000000" + - "000000000000000000000000007061727469636970616e7431000000000000000000000000" + - "00000000000000000000000000000000000000013200000000000000000000000000000000" + - "00000000000000000000000000000000000000000000000000000000000000000000000000" + - "696e69746961746f7232000000000000000000000000000000000000000000000000000000" + - "000000000200000000000000000000000000000000000000007061727469636970616e7432" + - "0000000000000000000000000000000000000000000000000000000000000002") - initSecretHashA = mustParseHex("8b3e4acc53b664f9cf6fcac0adcd328e95d62ba1f4379650ae3e1460a0f9d1a1") - initSecretHashB = mustParseHex("ebdc4c31b88d0c8f4d644591a8e00e92b607f920ad8050deb7c7469767d9c561") - initParticipantAddr = common.HexToAddress("345853e21b1d475582E71cC269124eD5e2dD3422") - - tRedeem1 = &swapv1.ETHSwapRedemption{ - V: *tSwap1, - Secret: bytesToArray([]byte("1")), - } - tRedeem2 = &swapv1.ETHSwapRedemption{ - V: *tSwap2, - Secret: bytesToArray([]byte("2")), - } - vector2 = &dexeth.SwapVector{ - From: tRedeem2.V.Initiator, - To: tRedeem2.V.Participant, - Value: tRedeem2.V.Value, - SecretHash: tRedeem2.V.SecretHash, - LockTime: tRedeem2.V.RefundTimestamp, - } - // redeemCalldata encodes [tRedeem1, tRedeem2] - redeemCalldata = mustParseHex("428b16e100000000000000000000000000000000000" + - "0000000000000000000000000002000000000000000000000000000000000000000000" + - "0000000000000000000000231000000000000000000000000000000000000000000000" + - "0000000000000000000000000000000000000000000000000000000000000696e69746" + - "961746f723100000000000000000000000000000000000000000000000000000000000" + - "0000100000000000000000000000000000000000000007061727469636970616e74310" + - "0000000000000000000000000000000000000000000000000000000000000013100000" + - "0000000000000000000000000000000000000000000000000000000003200000000000" + - "0000000000000000000000000000000000000000000000000000000000000000000000" + - "0000000000000000000000000696e69746961746f72320000000000000000000000000" + - "0000000000000000000000000000000000000020000000000000000000000000000000" + - "0000000007061727469636970616e74320000000000000000000000000000000000000" + - "0000000000000000000000000023200000000000000000000000000000000000000000" + - "000000000000000000000") + + initiatorAddr = common.HexToAddress("0x2b84C791b79Ee37De042AD2ffF1A253c3ce9bc27") + participantAddr = common.HexToAddress("345853e21b1d475582E71cC269124eD5e2dD3422") + secretA = mustArray32("557cf82e5e72e8ba23963a5e2832767a7e2a3e0a58ac00d319605f4b34b46de2") + secretHashA = mustArray32("09439d8fdc46a777590a5345704042c2774061d5322c6a94352c98a6f6a3630a") + secretB = mustArray32("87eac09638c0c38b4e735b79f053cb869167ee770640ac5df5c4ab030813122a") + secretHashB = mustArray32("ebdc4c31b88d0c8f4d644591a8e00e92b607f920ad8050deb7c7469767d9c561") + initValue uint64 = 2_500_000_000 + swapVectorA = &dexeth.SwapVector{ + From: initiatorAddr, + To: participantAddr, + Value: dexeth.GweiToWei(initValue), + SecretHash: secretHashA, + LockTime: initLocktime, + } + locatorA = swapVectorA.Locator() + swapVectorB = &dexeth.SwapVector{ + From: initiatorAddr, + To: participantAddr, + Value: dexeth.GweiToWei(initValue), + SecretHash: secretHashB, + LockTime: initLocktime, + } + locatorB = swapVectorB.Locator() + + initCalldataV0 = mustParseHex("a8793f94000000000000000000000000000000000000" + + "0000000000000000000000000020000000000000000000000000000000000000000000" + + "0000000000000000000002000000000000000000000000000000000000000000000000" + + "000000006148111409439d8fdc46a777590a5345704042c2774061d5322c6a94352c98" + + "a6f6a3630a000000000000000000000000345853e21b1d475582e71cc269124ed5e2dd" + + "342200000000000000000000000000000000000000000000000022b1c8c1227a000000" + + "00000000000000000000000000000000000000000000000000000061481114ebdc4c31" + + "b88d0c8f4d644591a8e00e92b607f920ad8050deb7c7469767d9c56100000000000000" + + "0000000000345853e21b1d475582e71cc269124ed5e2dd342200000000000000000000" + + "000000000000000000000000000022b1c8c1227a0000") + /* initCallData parses to: + [ETHSwapInitiation { + RefundTimestamp: 1632112916 + SecretHash: 8b3e4acc53b664f9cf6fcac0adcd328e95d62ba1f4379650ae3e1460a0f9d1a1 + Value: 2.5e9 gwei + Participant: 0x345853e21b1d475582e71cc269124ed5e2dd3422 + }, + ETHSwapInitiation { + RefundTimestamp: 1632112916 + SecretHash: ebdc4c31b88d0c8f4d644591a8e00e92b607f920ad8050deb7c7469767d9c561 + Value: 2.5e9 gwei + Participant: 0x345853e21b1d475582e71cc269124ed5e2dd3422 + }] + */ + initCalldataV1 = mustParseHex("3da59631000000000000000000000000000000000000" + + "0000000000000000000000000020000000000000000000000000000000000000000000" + + "000000000000000000000209439d8fdc46a777590a5345704042c2774061d5322c6a94" + + "352c98a6f6a3630a00000000000000000000000000000000000000000000000022b1c8" + + "c1227a00000000000000000000000000002b84c791b79ee37de042ad2fff1a253c3ce9" + + "bc27000000000000000000000000000000000000000000000000000000006148111400" + + "0000000000000000000000345853e21b1d475582e71cc269124ed5e2dd3422ebdc4c31" + + "b88d0c8f4d644591a8e00e92b607f920ad8050deb7c7469767d9c56100000000000000" + + "000000000000000000000000000000000022b1c8c1227a000000000000000000000000" + + "00002b84c791b79ee37de042ad2fff1a253c3ce9bc2700000000000000000000000000" + + "00000000000000000000000000000061481114000000000000000000000000345853e2" + + "1b1d475582e71cc269124ed5e2dd3422") + + redeemCalldataV0 = mustParseHex("f4fd17f90000000000000000000000000000000000" + + "0000000000000000000000000000200000000000000000000000000000000000000000" + + "000000000000000000000002557cf82e5e72e8ba23963a5e2832767a7e2a3e0a58ac00" + + "d319605f4b34b46de209439d8fdc46a777590a5345704042c2774061d5322c6a94352c" + + "98a6f6a3630a87eac09638c0c38b4e735b79f053cb869167ee770640ac5df5c4ab0308" + + "13122aebdc4c31b88d0c8f4d644591a8e00e92b607f920ad8050deb7c7469767d9c561") + + redeemCalldataV1 = mustParseHex("23f0388b0000000000000000000000000000000000" + + "0000000000000000000000000000200000000000000000000000000000000000000000" + + "00000000000000000000000209439d8fdc46a777590a5345704042c2774061d5322c6a" + + "94352c98a6f6a3630a00000000000000000000000000000000000000000000000022b1" + + "c8c1227a00000000000000000000000000002b84c791b79ee37de042ad2fff1a253c3c" + + "e9bc270000000000000000000000000000000000000000000000000000000061481114" + + "000000000000000000000000345853e21b1d475582e71cc269124ed5e2dd3422557cf8" + + "2e5e72e8ba23963a5e2832767a7e2a3e0a58ac00d319605f4b34b46de2ebdc4c31b88d" + + "0c8f4d644591a8e00e92b607f920ad8050deb7c7469767d9c561000000000000000000" + + "00000000000000000000000000000022b1c8c1227a0000000000000000000000000000" + + "2b84c791b79ee37de042ad2fff1a253c3ce9bc27000000000000000000000000000000" + + "0000000000000000000000000061481114000000000000000000000000345853e21b1d" + + "475582e71cc269124ed5e2dd342287eac09638c0c38b4e735b79f053cb869167ee7706" + + "40ac5df5c4ab030813122a") + /* + redeemCallData parses to: + [ETHSwapRedemption { + SecretHash: 99d971975c09331eb00f5e0dc1eaeca9bf4ee2d086d3fe1de489f920007d6546 + Secret: 2c0a304c9321402dc11cbb5898b9f2af3029ce1c76ec6702c4cd5bb965fd3e73 + } + ETHSwapRedemption { + SecretHash: ebdc4c31b88d0c8f4d644591a8e00e92b607f920ad8050deb7c7469767d9c561 + Secret: 87eac09638c0c38b4e735b79f053cb869167ee770640ac5df5c4ab030813122a + }] + */ ) func mustParseHex(s string) []byte { @@ -104,8 +137,8 @@ func mustParseHex(s string) []byte { return b } -func bytesToArray(b []byte) (a [32]byte) { - copy(a[:], b) +func mustArray32(s string) (b [32]byte) { + copy(b[:], mustParseHex(s)) return } @@ -121,13 +154,12 @@ type testNode struct { syncProgErr error suggGasTipCap *big.Int suggGasTipCapErr error - swp *dexeth.SwapState + swp map[string]*dexeth.SwapState swpErr error tx *types.Transaction txIsMempool bool txErr error - rcpt *types.Receipt - rcptErr error + receipt *types.Receipt acctBal *big.Int acctBalErr error } @@ -162,24 +194,51 @@ func (n *testNode) suggestGasTipCap(ctx context.Context) (*big.Int, error) { return n.suggGasTipCap, n.suggGasTipCapErr } -func (n *testNode) status(ctx context.Context, assetID uint32, vector *dexeth.SwapVector) (*dexeth.SwapStatus, error) { - // return n.swp.State, n.swp.Secret, uint32(n.swp.BlockHeight), n.swpErr - if n.swpErr != nil { - return nil, n.swpErr +func (n *testNode) status(ctx context.Context, assetID uint32, locator []byte) (*dexeth.SwapStatus, error) { + if s := n.swp[string(locator)]; s != nil { + return &dexeth.SwapStatus{ + BlockHeight: s.BlockHeight, + Secret: s.Secret, + Step: s.State, + }, n.swpErr + } + return nil, n.swpErr +} + +func (n *testNode) vector(ctx context.Context, assetID uint32, locator []byte) (*dexeth.SwapVector, error) { + var secretHash [32]byte + switch len(locator) { + case dexeth.LocatorV1Length: + vec, _ := dexeth.ParseV1Locator(locator) + secretHash = vec.SecretHash + default: + copy(secretHash[:], locator) + } + + if s := n.swp[string(locator)]; s != nil { + return &dexeth.SwapVector{ + From: s.Initiator, + To: s.Participant, + Value: s.Value, + SecretHash: secretHash, + LockTime: uint64(s.LockTime.Unix()), + }, n.swpErr } - return &dexeth.SwapStatus{ - BlockHeight: n.swp.BlockHeight, - Secret: n.swp.Secret, - Step: n.swp.State, - }, nil + return nil, n.swpErr } -func (n *testNode) transaction(ctx context.Context, hash common.Hash) (tx *types.Transaction, isMempool bool, err error) { +func (n *testNode) statusAndVector(ctx context.Context, assetID uint32, locator []byte) (*dexeth.SwapStatus, *dexeth.SwapVector, error) { + status, _ := n.status(ctx, assetID, locator) + vec, _ := n.vector(ctx, assetID, locator) + return status, vec, n.swpErr +} + +func (n *testNode) transaction(ctx context.Context, txHash common.Hash) (tx *types.Transaction, isMempool bool, err error) { return n.tx, n.txIsMempool, n.txErr } -func (n *testNode) receipt(context.Context, common.Hash) (*types.Receipt, error) { - return n.rcpt, n.rcptErr +func (n *testNode) transactionReceipt(ctx context.Context, txHash common.Hash) (tx *types.Receipt, err error) { + return n.receipt, nil } func (n *testNode) accountBalance(ctx context.Context, assetID uint32, addr common.Address) (*big.Int, error) { @@ -198,7 +257,9 @@ func tSwap(bn, locktime int64, value uint64, secret [32]byte, state dexeth.SwapS } func tNewBackend(assetID uint32) (*AssetBackend, *testNode) { - node := &testNode{} + node := &testNode{ + swp: make(map[string]*dexeth.SwapState), + } return &AssetBackend{ baseBackend: &baseBackend{ net: dex.Simnet, @@ -218,8 +279,6 @@ func TestMain(m *testing.M) { tCtx, shutdown = context.WithCancel(context.Background()) doIt := func() int { defer shutdown() - dexeth.Tokens[testTokenID].NetTokens[dex.Simnet].SwapContracts[ethContractVersion].Address = common.BytesToAddress(encode.RandomBytes(20)) - dexeth.ContractAddresses[ethContractVersion][dex.Simnet] = common.BytesToAddress(encode.RandomBytes(20)) return m.Run() } os.Exit(doIt()) @@ -271,7 +330,7 @@ func TestDecodeCoinID(t *testing.T) { func TestRun(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) - backend, err := unconnectedETH(BipID, dexeth.ContractAddresses[0][dex.Simnet], registeredTokens, tLogger, dex.Simnet) + backend, err := unconnectedETH(BipID, registeredTokens, tLogger, dex.Simnet) if err != nil { t.Fatalf("unconnectedETH error: %v", err) } @@ -465,61 +524,77 @@ func TestContract(t *testing.T) { copy(txHash[:], encode.RandomBytes(32)) const gasPrice = 30 const gasTipCap = 2 - swapVal := tSwap2.Value - txVal := tSwap1.Value + tSwap2.Value - locator2 := vector2.Locator() - + const swapVal = 25e8 + const txVal = 5e9 + secret0, secret1, secretHash0, secretHash1 := secretA, secretB, secretHashA, secretHashB + locator0, locator1 := locatorA, locatorB + swaps := map[string]*dexeth.SwapState{ + string(secretHash0[:]): tSwap(97, initLocktime, swapVal, secret0, dexeth.SSInitiated, &participantAddr), + string(secretHash1[:]): tSwap(97, initLocktime, swapVal, secret1, dexeth.SSInitiated, &participantAddr), + string(locator1): tSwap(97, initLocktime, swapVal, secret1, dexeth.SSInitiated, &participantAddr), + string(locator0): tSwap(97, initLocktime, swapVal, secret0, dexeth.SSInitiated, &participantAddr), + string(locator1): tSwap(97, initLocktime, swapVal, secret1, dexeth.SSInitiated, &participantAddr), + } tests := []struct { - name string - coinID []byte - contract []byte - tx *types.Transaction - swap *dexeth.SwapState - swapErr, txErr error - wantErr bool - }{{ - name: "ok", - tx: tTx(gasPrice, gasTipCap, txVal, contractAddr, initCalldata), - contract: dexeth.EncodeContractData(1, locator2), - swap: tSwap(97, initLocktime, swapVal, tRedeem2.Secret, dexeth.SSInitiated, &initParticipantAddr), - coinID: txHash[:], - }, { - name: "new coiner error, wrong tx type", - tx: tTx(gasPrice, gasTipCap, txVal, contractAddr, initCalldata), - contract: dexeth.EncodeContractData(1, locator2), - swap: tSwap(97, initLocktime, swapVal, tRedeem2.Secret, dexeth.SSInitiated, &initParticipantAddr), - coinID: txHash[1:], - wantErr: true, - }, { - name: "confirmations error, swap error", - tx: tTx(gasPrice, gasTipCap, txVal, contractAddr, initCalldata), - contract: dexeth.EncodeContractData(1, locator2), - coinID: txHash[:], - swapErr: errors.New(""), - wantErr: true, - }} + name string + ver uint32 + coinID []byte + tx *types.Transaction + locators [][]byte + swapErr error + wantErr bool + }{ + { + name: "ok v0", + tx: tTx(gasPrice, gasTipCap, txVal, contractAddr, initCalldataV0), + locators: [][]byte{secretHash0[:], secretHash1[:]}, + coinID: txHash[:], + }, { + name: "ok v1", + ver: 1, + tx: tTx(gasPrice, gasTipCap, txVal, contractAddr, initCalldataV1), + locators: [][]byte{locator0, locator1}, + coinID: txHash[:], + }, { + name: "new coiner error, wrong tx type", + ver: 1, + tx: tTx(gasPrice, gasTipCap, txVal, contractAddr, initCalldataV1), + locators: [][]byte{locator0, locator1}, + coinID: txHash[1:], + wantErr: true, + }, { + name: "confirmations error, swap error", + ver: 1, + tx: tTx(gasPrice, gasTipCap, txVal, contractAddr, initCalldataV1), + locators: [][]byte{locator0, locator1}, + coinID: txHash[:], + swapErr: errors.New(""), + wantErr: true, + }, + } for _, test := range tests { eth, node := tNewBackend(BipID) node.tx = test.tx - node.txErr = test.txErr - node.swp = test.swap + node.swp = swaps node.swpErr = test.swapErr eth.contractAddr = *contractAddr - contractData := dexeth.EncodeContractData(1, locator2) // matches initCalldata - contract, err := eth.Contract(test.coinID, contractData) - if test.wantErr { - if err == nil { - t.Fatalf("expected error for test %q", test.name) + for _, locator := range test.locators { + contractData := dexeth.EncodeContractData(test.ver, locator) + contract, err := eth.Contract(test.coinID, contractData) + if test.wantErr { + if err == nil { + t.Fatalf("expected error for test %q", test.name) + } + continue + } + if err != nil { + t.Fatalf("unexpected error for test %q: %v", test.name, err) + } + if contract.SwapAddress != participantAddr.String() || + contract.LockTime.Unix() != initLocktime { + t.Fatalf("returns do not match expected for test %q", test.name) } - continue - } - if err != nil { - t.Fatalf("unexpected error for test %q: %v", test.name, err) - } - if contract.SwapAddress != tRedeem2.V.Participant.String() || - contract.LockTime.Unix() != int64(tRedeem2.V.RefundTimestamp) { - t.Fatalf("returns do not match expected for test %q", test.name) } } } @@ -553,29 +628,32 @@ func TestValidateFeeRate(t *testing.T) { } func TestValidateSecret(t *testing.T) { - secret := bytesToArray(encode.RandomBytes(32)) - secretHash := sha256.Sum256(secret[:]) - rightVec := &dexeth.SwapVector{SecretHash: secretHash} - wrongVec := &dexeth.SwapVector{SecretHash: bytesToArray(encode.RandomBytes(32))} + v := &dexeth.SwapVector{SecretHash: sha256.Sum256(secretA[:]), Value: new(big.Int)} + badV := &dexeth.SwapVector{SecretHash: [32]byte{}, Value: new(big.Int)} tests := []struct { name string - secret [32]byte contractData []byte want bool - }{{ - name: "ok", - contractData: dexeth.EncodeContractData(1, rightVec.Locator()), - want: true, - }, { - name: "not the right hash", - contractData: dexeth.EncodeContractData(1, wrongVec.Locator()), - }, { - name: "bad contract data", - }} + }{ + { + name: "ok v0", + contractData: dexeth.EncodeContractData(0, secretHashA[:]), + want: true, + }, { + name: "ok v1", + contractData: dexeth.EncodeContractData(1, v.Locator()), + want: true, + }, { + name: "not the right hash", + contractData: dexeth.EncodeContractData(1, badV.Locator()), + }, { + name: "bad contract data", + }, + } for _, test := range tests { eth, _ := tNewBackend(BipID) - got := eth.ValidateSecret(secret[:], test.contractData) + got := eth.ValidateSecret(secretA[:], test.contractData) if test.want != got { t.Fatalf("expected %v but got %v for test %q", test.want, got, test.name) } @@ -586,53 +664,68 @@ func TestRedemption(t *testing.T) { receiverAddr, contractAddr := new(common.Address), new(common.Address) copy(receiverAddr[:], encode.RandomBytes(20)) copy(contractAddr[:], encode.RandomBytes(20)) - txHash := bytesToArray(encode.RandomBytes(32)) - secret := tRedeem2.Secret - locator := vector2.Locator() + secret, secretHash := secretB, secretHashB + var txHash [32]byte + copy(txHash[:], encode.RandomBytes(32)) const gasPrice = 30 const gasTipCap = 2 - goodContract := dexeth.EncodeContractData(1, locator) + tests := []struct { - name string - coinID, contractID []byte - swp *dexeth.SwapState - tx *types.Transaction - wantErr bool - }{{ - name: "ok", - tx: tTx(gasPrice, gasTipCap, 0, contractAddr, redeemCalldata), - contractID: goodContract, - coinID: txHash[:], - swp: tSwap(0, 0, 0, secret, dexeth.SSRedeemed, receiverAddr), - }, { - name: "new coiner error, wrong tx type", - tx: tTx(gasPrice, gasTipCap, 0, contractAddr, redeemCalldata), - contractID: goodContract, - coinID: txHash[1:], - wantErr: true, - }, { - name: "confirmations error, swap wrong state", - tx: tTx(gasPrice, gasTipCap, 0, contractAddr, redeemCalldata), - contractID: goodContract, - swp: tSwap(0, 0, 0, secret, dexeth.SSRefunded, receiverAddr), - coinID: txHash[:], - wantErr: true, - }, { - name: "bad contract data", - tx: tTx(gasPrice, gasTipCap, 0, contractAddr, redeemCalldata), - contractID: goodContract[:len(goodContract)-1], - coinID: txHash[:], - swp: tSwap(0, 0, 0, secret, dexeth.SSRedeemed, receiverAddr), - wantErr: true, - }} + name string + ver uint32 + coinID []byte + locator []byte + swp *dexeth.SwapState + tx *types.Transaction + wantErr bool + }{ + { + name: "ok v0", + tx: tTx(gasPrice, gasTipCap, 0, contractAddr, redeemCalldataV0), + locator: secretHash[:], + coinID: txHash[:], + swp: tSwap(0, 0, 0, secret, dexeth.SSRedeemed, receiverAddr), + }, { + name: "ok v1", + ver: 1, + tx: tTx(gasPrice, gasTipCap, 0, contractAddr, redeemCalldataV1), + locator: locatorA, + coinID: txHash[:], + swp: tSwap(0, 0, 0, secret, dexeth.SSRedeemed, receiverAddr), + }, { + name: "new coiner error, wrong tx type", + tx: tTx(gasPrice, gasTipCap, 0, contractAddr, redeemCalldataV0), + locator: secretHash[:], + coinID: txHash[1:], + wantErr: true, + }, { + name: "confirmations error, swap wrong state", + tx: tTx(gasPrice, gasTipCap, 0, contractAddr, redeemCalldataV0), + locator: secretHash[:], + swp: tSwap(0, 0, 0, secret, dexeth.SSRefunded, receiverAddr), + coinID: txHash[:], + wantErr: true, + }, { + name: "validate redeem error", + tx: tTx(gasPrice, gasTipCap, 0, contractAddr, redeemCalldataV0), + locator: secretHash[:31], + coinID: txHash[:], + swp: tSwap(0, 0, 0, secret, dexeth.SSRedeemed, receiverAddr), + wantErr: true, + }, + } + for _, test := range tests { eth, node := tNewBackend(BipID) node.tx = test.tx - node.rcpt = &types.Receipt{BlockNumber: new(big.Int)} - node.swp = test.swp + node.receipt = &types.Receipt{ + BlockNumber: big.NewInt(5), + } + node.swp[string(test.locator)] = test.swp eth.contractAddr = *contractAddr - _, err := eth.Redemption(test.coinID, nil, test.contractID) + contract := dexeth.EncodeContractData(test.ver, test.locator) + _, err := eth.Redemption(test.coinID, nil, contract) if test.wantErr { if err == nil { t.Fatalf("expected error for test %q", test.name) @@ -701,41 +794,37 @@ func TestValidateContract(t *testing.T) { } func testValidateContract(t *testing.T, assetID uint32) { - locator := vector2.Locator() + badLoc := append(locatorA, 8) tests := []struct { name string ver uint32 locator []byte wantErr bool - }{{ - name: "ok", - ver: 1, - locator: locator, - }, { - name: "wrong size", - ver: 1, - locator: locator[:len(locator)-1], - wantErr: true, - }, { - name: "wrong version", - ver: 0, - locator: locator, - wantErr: true, - }} + }{ + { + name: "ok v0", + locator: secretHashA[:], + }, { + name: "ok v1", + ver: 1, + locator: locatorA[:], + }, { + name: "wrong size", + ver: 1, + locator: badLoc, + wantErr: true, + }, { + name: "wrong version", + ver: 0, + locator: locatorA[:], // should be secretHashA + wantErr: true, + }, + } type contractValidator interface { ValidateContract([]byte) error } - if assetID != BipID { - c := dexeth.Tokens[testTokenID].NetTokens[dex.Simnet].SwapContracts[0] - ogAddr := c.Address - c.Address = common.Address{0x01} - defer func() { - c.Address = ogAddr - }() - } - for _, test := range tests { eth, _ := tNewBackend(assetID) var cv contractValidator @@ -745,14 +834,14 @@ func testValidateContract(t *testing.T, assetID uint32) { cv = &TokenBackend{ AssetBackend: eth, VersionedToken: &VersionedToken{ - Token: dexeth.Tokens[testTokenID], - Ver: test.ver, + Token: dexeth.Tokens[testTokenID], + ContractVersion: test.ver, }, } } - swapData := dexeth.EncodeContractData(test.ver, test.locator) - err := cv.ValidateContract(swapData) + contractData := dexeth.EncodeContractData(test.ver, test.locator) + err := cv.ValidateContract(contractData) if test.wantErr { if err == nil { t.Fatalf("expected error for test %q", test.name) diff --git a/server/asset/eth/rpcclient.go b/server/asset/eth/rpcclient.go index 7759a27f99..5fc8183af4 100644 --- a/server/asset/eth/rpcclient.go +++ b/server/asset/eth/rpcclient.go @@ -17,6 +17,7 @@ import ( "decred.org/dcrdex/dex" dexeth "decred.org/dcrdex/dex/networks/eth" + swapv0 "decred.org/dcrdex/dex/networks/eth/contracts/v0" swapv1 "decred.org/dcrdex/dex/networks/eth/contracts/v1" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" @@ -47,7 +48,7 @@ type ethConn struct { endpoint string priority uint16 // swapContract is the current ETH swapContract. - swapContract swapContract + swapContracts map[uint32]swapContract // tokens are tokeners for loaded tokens. tokens is not protected by a // mutex, as it is expected that the caller will connect and place calls to // loadToken sequentially in the same thread during initialization. @@ -233,14 +234,25 @@ func (c *rpcclient) connectToEndpoint(ctx context.Context, endpoint endpoint) (* ec.txPoolSupported = true } - es, err := swapv1.NewETHSwap(c.ethContractAddr, ec.Client) + es0, err := swapv0.NewETHSwap(c.ethContractAddr, ec.Client) if err != nil { - return nil, fmt.Errorf("unable to initialize %v contract for %q: %v", c.baseChainName, endpoint, err) + return nil, err + } + sc0 := &swapSourceV0{es0} + + es1, err := swapv1.NewETHSwap(c.ethContractAddr, ec.Client) + if err != nil { + return nil, err + } + sc1 := &swapSourceV1{es1} + + ec.swapContracts = map[uint32]swapContract{ + 0: sc0, + 1: sc1, } - ec.swapContract = &swapSourceV1{es} for assetID, vToken := range c.tokensLoaded { - tkn, err := newTokener(ctx, vToken, c.net, ec.Client) + tkn, err := newTokener(ctx, assetID, vToken, c.net, ec.Client) if err != nil { return nil, fmt.Errorf("error constructing ERC20Swap: %w", err) } @@ -419,7 +431,7 @@ func (c *rpcclient) withClient(f func(ec *ethConn) error, haltOnNotFound ...bool return nil } if len(haltOnNotFound) > 0 && haltOnNotFound[0] && (errors.Is(err, ethereum.NotFound) || strings.Contains(err.Error(), "not found")) { - return err + return ethereum.NotFound } c.log.Errorf("Unpropagated error from %q: %v", ec.endpoint, err) @@ -481,7 +493,7 @@ func (c *rpcclient) loadToken(ctx context.Context, assetID uint32, vToken *Versi c.tokensLoaded[assetID] = vToken for _, cl := range c.clientsCopy() { - tkn, err := newTokener(ctx, vToken, c.net, cl.Client) + tkn, err := newTokener(ctx, assetID, vToken, c.net, cl.Client) if err != nil { return fmt.Errorf("error constructing ERC20Swap: %w", err) } @@ -498,7 +510,21 @@ func (c *rpcclient) withTokener(assetID uint32, f func(*tokener) error) error { } return f(tkn) }) +} +func (c *rpcclient) withSwapContract(assetID uint32, f func(swapContract) error) error { + if assetID == c.baseChainID { + return c.withClient(func(ec *ethConn) error { + sc, found := ec.swapContracts[ProtocolVersion(assetID).ContractVersion()] + if !found { + return fmt.Errorf("no rpc swap contract loaded for asset %d", assetID) + } + return f(sc) + }) + } + return c.withTokener(assetID, func(tkn *tokener) error { + return f(tkn) + }) } // bestHeader gets the best header at the time of calling. @@ -537,20 +563,25 @@ func (c *rpcclient) blockNumber(ctx context.Context) (bn uint64, err error) { }) } -// swap gets a swap keyed by secretHash in the contract. -func (c *rpcclient) status(ctx context.Context, assetID uint32, vector *dexeth.SwapVector) (status *dexeth.SwapStatus, err error) { - if assetID == c.baseChainID { - err = c.withClient(func(ec *ethConn) error { - status, err = ec.swapContract.Status(ctx, vector) - return err - }) - } else { - err = c.withTokener(assetID, func(tkn *tokener) error { - status, err = tkn.Status(ctx, vector) - return err - }) - } - return +func (c *rpcclient) status(ctx context.Context, assetID uint32, locator []byte) (status *dexeth.SwapStatus, err error) { + return status, c.withSwapContract(assetID, func(sc swapContract) error { + status, err = sc.status(ctx, locator) + return err + }) +} + +func (c *rpcclient) vector(ctx context.Context, assetID uint32, locator []byte) (vec *dexeth.SwapVector, err error) { + return vec, c.withSwapContract(assetID, func(sc swapContract) error { + vec, err = sc.vector(ctx, locator) + return err + }) +} + +func (c *rpcclient) statusAndVector(ctx context.Context, assetID uint32, locator []byte) (status *dexeth.SwapStatus, vec *dexeth.SwapVector, err error) { + return status, vec, c.withSwapContract(assetID, func(sc swapContract) error { + status, vec, err = sc.statusAndVector(ctx, locator) + return err + }) } // transaction gets the transaction that hashes to hash from the chain or @@ -562,6 +593,17 @@ func (c *rpcclient) transaction(ctx context.Context, hash common.Hash) (tx *type }, true) // stop on first provider with "not found", because this should be an error if tx does not exist } +func (c *rpcclient) transactionReceipt(ctx context.Context, txHash common.Hash) (r *types.Receipt, err error) { + return r, c.withClient(func(ec *ethConn) error { + r, err = ec.TransactionReceipt(ctx, txHash) + return err + }) +} + +func isNotFoundError(err error) bool { + return strings.Contains(err.Error(), "not found") +} + // dumbBalance gets the account balance, ignoring the effects of unmined // transactions. func (c *rpcclient) dumbBalance(ctx context.Context, ec *ethConn, assetID uint32, addr common.Address) (bal *big.Int, err error) { @@ -576,7 +618,6 @@ func (c *rpcclient) dumbBalance(ctx context.Context, ec *ethConn, assetID uint32 } // smartBalance gets the account balance, including the effects of known -// accountBalance gets the account balance, including the effects of known // unmined transactions. func (c *rpcclient) smartBalance(ctx context.Context, ec *ethConn, assetID uint32, addr common.Address) (bal *big.Int, err error) { tip, err := c.blockNumber(ctx) @@ -649,14 +690,6 @@ func (c *rpcclient) smartBalance(ctx context.Context, ec *ethConn, assetID uint3 return bal, nil } -// receipt fetches the transaction receipt. -func (c *rpcclient) receipt(ctx context.Context, txHash common.Hash) (r *types.Receipt, err error) { - return r, c.withClient(func(ec *ethConn) error { - r, err = ec.TransactionReceipt(ctx, txHash) - return err - }) -} - // accountBalance gets the account balance. If txPool functions are supported by the // client, it will include the effects of unmined transactions, otherwise it will not. func (c *rpcclient) accountBalance(ctx context.Context, assetID uint32, addr common.Address) (bal *big.Int, err error) { diff --git a/server/asset/eth/rpcclient_harness_test.go b/server/asset/eth/rpcclient_harness_test.go index fe7261154a..9114aaf574 100644 --- a/server/asset/eth/rpcclient_harness_test.go +++ b/server/asset/eth/rpcclient_harness_test.go @@ -42,20 +42,20 @@ func TestMain(m *testing.M) { monitorConnectionsInterval = 3 * time.Second // Run in function so that defers happen before os.Exit is called. - dexeth.MaybeReadSimnetAddrs() run := func() (int, error) { var cancel context.CancelFunc ctx, cancel = context.WithCancel(context.Background()) defer cancel() log := dex.StdOutLogger("T", dex.LevelTrace) - netAddrs, found := dexeth.ContractAddresses[ethContractVersion] + const contractVer = 0 + netAddrs, found := dexeth.ContractAddresses[contractVer] if !found { - return 1, fmt.Errorf("no contract address for eth version %d", ethContractVersion) + return 1, fmt.Errorf("no contract address for eth version %d", contractVer) } ethContractAddr, found := netAddrs[dex.Simnet] if !found { - return 1, fmt.Errorf("no contract address for eth version %d on %s", ethContractVersion, dex.Simnet) + return 1, fmt.Errorf("no contract address for eth version %d on %s", contractVer, dex.Simnet) } ethClient = newRPCClient(BipID, dex.Simnet, []endpoint{{url: wsEndpoint}, {url: alphaIPCFile}}, ethContractAddr, log) @@ -112,7 +112,9 @@ func TestSuggestGasTipCap(t *testing.T) { } func TestStatus(t *testing.T) { - _, err := ethClient.status(ctx, BipID, &dexeth.SwapVector{}) + var secretHash [32]byte + copy(secretHash[:], encode.RandomBytes(32)) + _, err := ethClient.status(ctx, BipID, secretHash[:]) if err != nil { t.Fatal(err) } diff --git a/server/asset/eth/tokener.go b/server/asset/eth/tokener.go index f939de0a13..9cee6fdedd 100644 --- a/server/asset/eth/tokener.go +++ b/server/asset/eth/tokener.go @@ -10,8 +10,10 @@ import ( "decred.org/dcrdex/dex" "decred.org/dcrdex/dex/networks/erc20" + erc20v0 "decred.org/dcrdex/dex/networks/erc20/contracts/v0" erc20v1 "decred.org/dcrdex/dex/networks/erc20/contracts/v1" dexeth "decred.org/dcrdex/dex/networks/eth" + swapv0 "decred.org/dcrdex/dex/networks/eth/contracts/v0" swapv1 "decred.org/dcrdex/dex/networks/eth/contracts/v1" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -19,7 +21,9 @@ import ( // swapContract is a generic source of swap contract data. type swapContract interface { - Status(context.Context, *dexeth.SwapVector) (*dexeth.SwapStatus, error) + status(ctx context.Context, locator []byte) (*dexeth.SwapStatus, error) + vector(ctx context.Context, locator []byte) (*dexeth.SwapVector, error) + statusAndVector(ctx context.Context, locator []byte) (*dexeth.SwapStatus, *dexeth.SwapVector, error) } // erc2Contract exposes methods of a token's ERC20 contract. @@ -38,19 +42,39 @@ type tokener struct { // newTokener is a constructor for a tokener. func newTokener( ctx context.Context, + assetID uint32, vToken *VersionedToken, net dex.Network, be bind.ContractBackend, ) (*tokener, error) { - netToken, swapContract, err := networkToken(vToken, net) + netToken, contract, err := networkToken(vToken, net) if err != nil { return nil, err } - es, err := erc20v1.NewERC20Swap(swapContract.Address, be) - if err != nil { - return nil, err + var tokenAddresser interface { + TokenAddress(opts *bind.CallOpts) (common.Address, error) + } + + var sc swapContract + switch vToken.ContractVersion { + case 0: + es, err := erc20v0.NewERC20Swap(contract.Address, be) + if err != nil { + return nil, err + } + sc = &swapSourceV0{es} + tokenAddresser = es + case 1: + es, err := erc20v1.NewERC20Swap(contract.Address, be) + if err != nil { + return nil, err + } + sc = &swapSourceV1{es} + tokenAddresser = es + default: + return nil, fmt.Errorf("unsupported contract version %d", vToken.ContractVersion) } erc20, err := erc20.NewIERC20(netToken.Address, be) @@ -58,22 +82,22 @@ func newTokener( return nil, err } - boundAddr, err := es.TokenAddress(readOnlyCallOpts(ctx, false)) + boundAddr, err := tokenAddresser.TokenAddress(readOnlyCallOpts(ctx, false)) if err != nil { return nil, fmt.Errorf("error retrieving bound address for %s version %d contract: %w", - vToken.Name, vToken.Ver, err) + vToken.Name, vToken.ContractVersion, err) } if boundAddr != netToken.Address { return nil, fmt.Errorf("wrong bound address for %s version %d contract. wanted %s, got %s", - vToken.Name, vToken.Ver, netToken.Address, boundAddr) + vToken.Name, vToken.ContractVersion, netToken.Address, boundAddr) } tkn := &tokener{ VersionedToken: vToken, - swapContract: &swapSourceV1{es}, + swapContract: sc, erc20Contract: erc20, - contractAddr: swapContract.Address, + contractAddr: contract.Address, tokenAddr: netToken.Address, } @@ -92,15 +116,15 @@ func (t *tokener) transferred(txData []byte) *big.Int { // swapped calculates the value sent to the swap contracts initiate method. func (t *tokener) swapped(txData []byte) *big.Int { - vectors, err := dexeth.ParseInitiateDataV1(txData) + inits, err := dexeth.ParseInitiateDataV0(txData) if err != nil { return nil } - var v uint64 - for _, vector := range vectors { - v += vector.Value + v := new(big.Int) + for _, init := range inits { + v.Add(v, init.Value) } - return dexeth.GweiToWei(v) + return v } // balanceOf checks the account's token balance. @@ -108,29 +132,154 @@ func (t *tokener) balanceOf(ctx context.Context, addr common.Address) (*big.Int, return t.BalanceOf(readOnlyCallOpts(ctx, false), addr) } -// swapContractV1 represents a version 0 swap contract for ETH or a token. +// swapContractV0 represents a version 0 swap contract for ETH or a token. +type swapContractV0 interface { + Swap(opts *bind.CallOpts, secretHash [32]byte) (swapv0.ETHSwapSwap, error) +} + +// swapSourceV0 wraps a swapContractV0 and translates the swap data to satisfy +// swapSource. +type swapSourceV0 struct { + contract swapContractV0 // *swapv0.ETHSwap or *erc20v0.ERCSwap +} + +// swap get the swap state for the secretHash on the version 0 contract. +func (s *swapSourceV0) swap(ctx context.Context, secretHash [32]byte) (*dexeth.SwapState, error) { + state, err := s.contract.Swap(readOnlyCallOpts(ctx, true), secretHash) + if err != nil { + return nil, fmt.Errorf("swap error: %w", err) + } + return dexeth.SwapStateFromV0(&state), nil +} + +// status fetches the SwapStatus, which specifies the current state of mutable +// swap data. +func (s *swapSourceV0) status(ctx context.Context, locator []byte) (*dexeth.SwapStatus, error) { + secretHash, err := dexeth.ParseV0Locator(locator) + if err != nil { + return nil, err + } + swap, err := s.swap(ctx, secretHash) + if err != nil { + return nil, err + } + status := &dexeth.SwapStatus{ + Step: swap.State, + Secret: swap.Secret, + BlockHeight: swap.BlockHeight, + } + return status, nil +} + +// vector generates a SwapVector, containing the immutable data that defines +// the swap. +func (s *swapSourceV0) vector(ctx context.Context, locator []byte) (*dexeth.SwapVector, error) { + secretHash, err := dexeth.ParseV0Locator(locator) + if err != nil { + return nil, err + } + swap, err := s.swap(ctx, secretHash) + if err != nil { + return nil, err + } + vector := &dexeth.SwapVector{ + From: swap.Participant, + To: swap.Initiator, + Value: swap.Value, + SecretHash: secretHash, + LockTime: uint64(swap.LockTime.Unix()), + } + return vector, nil +} + +// statusAndVector generates both the status and the vector simultaneously. For +// version 0, this is better than calling status and vector separately, since +// each makes an identical call to c.swap. +func (s *swapSourceV0) statusAndVector(ctx context.Context, locator []byte) (*dexeth.SwapStatus, *dexeth.SwapVector, error) { + secretHash, err := dexeth.ParseV0Locator(locator) + if err != nil { + return nil, nil, err + } + swap, err := s.swap(ctx, secretHash) + if err != nil { + return nil, nil, err + } + vector := &dexeth.SwapVector{ + From: swap.Participant, + To: swap.Initiator, + Value: swap.Value, + SecretHash: secretHash, + LockTime: uint64(swap.LockTime.Unix()), + } + status := &dexeth.SwapStatus{ + Step: swap.State, + Secret: swap.Secret, + BlockHeight: swap.BlockHeight, + } + return status, vector, nil +} + type swapContractV1 interface { Status(opts *bind.CallOpts, c swapv1.ETHSwapVector) (swapv1.ETHSwapStatus, error) } -// swapSourceV1 wraps a swapContractV0 and translates the swap data to satisfy -// swapSource. type swapSourceV1 struct { contract swapContractV1 // *swapv0.ETHSwap or *erc20v0.ERCSwap } -// Swap translates the version 0 swap data to the more general SwapState to -// satisfy the swapSource interface. -func (s *swapSourceV1) Status(ctx context.Context, vector *dexeth.SwapVector) (*dexeth.SwapStatus, error) { - rec, err := s.contract.Status(readOnlyCallOpts(ctx, true), dexeth.SwapVectorToAbigen(vector)) +func (s *swapSourceV1) status(ctx context.Context, locator []byte) (*dexeth.SwapStatus, error) { + v, err := dexeth.ParseV1Locator(locator) if err != nil { - return nil, fmt.Errorf("Swap error: %w", err) + return nil, err + } + rec, err := s.contract.Status(readOnlyCallOpts(ctx, true), dexeth.SwapVectorToAbigen(v)) + if err != nil { + return nil, err } return &dexeth.SwapStatus{ - BlockHeight: rec.BlockNumber.Uint64(), + Step: dexeth.SwapStep(rec.Step), Secret: rec.Secret, + BlockHeight: rec.BlockNumber.Uint64(), + }, err +} + +func (s *swapSourceV1) vector(ctx context.Context, locator []byte) (*dexeth.SwapVector, error) { + return dexeth.ParseV1Locator(locator) +} + +func (s *swapSourceV1) statusAndVector(ctx context.Context, locator []byte) (*dexeth.SwapStatus, *dexeth.SwapVector, error) { + v, err := dexeth.ParseV1Locator(locator) + if err != nil { + return nil, nil, err + } + + rec, err := s.contract.Status(readOnlyCallOpts(ctx, true), dexeth.SwapVectorToAbigen(v)) + if err != nil { + return nil, nil, err + } + return &dexeth.SwapStatus{ Step: dexeth.SwapStep(rec.Step), - }, nil + Secret: rec.Secret, + BlockHeight: rec.BlockNumber.Uint64(), + }, v, err +} + +func (s *swapSourceV1) Status(ctx context.Context, locator []byte) (*dexeth.SwapStatus, error) { + vec, err := dexeth.ParseV1Locator(locator) + if err != nil { + return nil, err + } + + status, err := s.contract.Status(readOnlyCallOpts(ctx, true), dexeth.SwapVectorToAbigen(vec)) + if err != nil { + return nil, err + } + + return &dexeth.SwapStatus{ + Step: dexeth.SwapStep(status.Step), + Secret: status.Secret, + BlockHeight: status.BlockNumber.Uint64(), + }, err } // readOnlyCallOpts is the CallOpts used for read-only contract method calls. diff --git a/server/asset/polygon/polygon.go b/server/asset/polygon/polygon.go index df6c3bca87..b1b2919339 100644 --- a/server/asset/polygon/polygon.go +++ b/server/asset/polygon/polygon.go @@ -5,9 +5,9 @@ package polygon import ( "fmt" - "time" "decred.org/dcrdex/dex" + dexeth "decred.org/dcrdex/dex/networks/eth" dexpolygon "decred.org/dcrdex/dex/networks/polygon" "decred.org/dcrdex/server/asset" "decred.org/dcrdex/server/asset/eth" @@ -15,51 +15,42 @@ import ( var registeredTokens = make(map[uint32]*eth.VersionedToken) -func registerToken(assetID uint32, ver uint32) { +func registerToken(assetID uint32, protocolVersion dexeth.ProtocolVersion) { token, exists := dexpolygon.Tokens[assetID] if !exists { panic(fmt.Sprintf("no token constructor for asset ID %d", assetID)) } asset.RegisterToken(assetID, ð.TokenDriver{ DriverBase: eth.DriverBase{ - Ver: ver, - UI: token.UnitInfo, - Nam: token.Name, + ProtocolVersion: protocolVersion, + UI: token.UnitInfo, + Nam: token.Name, }, Token: token.Token, }) registeredTokens[assetID] = ð.VersionedToken{ - Token: token, - Ver: ver, + Token: token, + ContractVersion: protocolVersion.ContractVersion(), } } func init() { asset.Register(BipID, &Driver{eth.Driver{ DriverBase: eth.DriverBase{ - Ver: version, - UI: dexpolygon.UnitInfo, - Nam: "Polygon", + ProtocolVersion: eth.ProtocolVersion(BipID), + UI: dexpolygon.UnitInfo, + Nam: "Polygon", }, }}) - registerToken(testTokenID, 0) - registerToken(usdcID, 0) - registerToken(wethTokenID, 0) - registerToken(wbtcTokenID, 0) - - if blockPollIntervalStr != "" { - blockPollInterval, _ = time.ParseDuration(blockPollIntervalStr) - if blockPollInterval < time.Second { - panic(fmt.Sprintf("invalid value for blockPollIntervalStr: %q", blockPollIntervalStr)) - } - } + registerToken(testTokenID, eth.ProtocolVersion(testTokenID)) + registerToken(usdcID, eth.ProtocolVersion(usdcID)) + registerToken(wethTokenID, eth.ProtocolVersion(wethTokenID)) + registerToken(wbtcTokenID, eth.ProtocolVersion(wbtcTokenID)) } const ( - BipID = 966 - ethContractVersion = 0 - version = 0 + BipID = 966 ) var ( @@ -67,12 +58,6 @@ var ( usdcID, _ = dex.BipSymbolID("usdc.polygon") wethTokenID, _ = dex.BipSymbolID("weth.polygon") wbtcTokenID, _ = dex.BipSymbolID("wbtc.polygon") - - // blockPollInterval is the delay between calls to bestBlockHash to check - // for new blocks. Modify at compile time via blockPollIntervalStr: - // go build -tags lgpl -ldflags "-X 'decred.org/dcrdex/server/asset/polygon.blockPollIntervalStr=10s'" - blockPollInterval = time.Second - blockPollIntervalStr string ) type Driver struct { diff --git a/server/cmd/dcrdex/evm-protocol-overrides.json b/server/cmd/dcrdex/evm-protocol-overrides.json new file mode 100644 index 0000000000..bdeaea28d9 --- /dev/null +++ b/server/cmd/dcrdex/evm-protocol-overrides.json @@ -0,0 +1,8 @@ +{ + "eth": 0, + "usdc.eth": 0, + "polygon": 0, + "usdc.polygon": 0, + "wbtc.polygon": 0, + "weth.polygon": 0 +} \ No newline at end of file