Skip to content

Commit

Permalink
checkpoint. redid server. tests passing. no v1 tests on server yet.
Browse files Browse the repository at this point in the history
  • Loading branch information
buck54321 committed Aug 7, 2023
1 parent 20a390e commit 6860081
Show file tree
Hide file tree
Showing 12 changed files with 758 additions and 436 deletions.
2 changes: 1 addition & 1 deletion client/asset/eth/contractor.go
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,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)
}
Expand Down
64 changes: 22 additions & 42 deletions client/asset/eth/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,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 (
Expand Down Expand Up @@ -619,14 +616,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()
}

// CreateWallet creates a new internal ETH wallet and stores the private key
Expand Down Expand Up @@ -2149,7 +2139,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))
}
Expand Down Expand Up @@ -2304,7 +2294,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
})
Expand All @@ -2313,7 +2303,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
})
Expand Down Expand Up @@ -2678,7 +2668,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)
}
Expand Down Expand Up @@ -2720,19 +2710,8 @@ 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 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")
if !dexeth.CompareVectors(vec, txVec) {
return nil, fmt.Errorf("tx vector doesn't match expectation. %+v != %+v", txVec, vec)
}
val = vec.Value
participant = vec.To.String()
Expand Down Expand Up @@ -2781,7 +2760,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
}
Expand Down Expand Up @@ -2869,7 +2848,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
}
Expand Down Expand Up @@ -2948,7 +2927,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)
}
Expand Down Expand Up @@ -3046,7 +3025,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
Expand Down Expand Up @@ -3121,7 +3100,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")
}
Expand Down Expand Up @@ -3213,7 +3192,7 @@ func (w *assetWallet) RestorationInfo(seed []byte) ([]*asset.WalletRestoration,
// 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
}
Expand Down Expand Up @@ -3392,7 +3371,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
}
Expand Down Expand Up @@ -3996,7 +3975,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)
}
Expand Down Expand Up @@ -4089,7 +4068,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)
}
Expand Down Expand Up @@ -4393,15 +4372,15 @@ 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")
}
txOpts, err := w.node.txOpts(w.ctx, 0, g.Transfer, nil, nil)
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()
Expand Down Expand Up @@ -4524,7 +4503,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
Expand Down Expand Up @@ -4557,16 +4536,17 @@ 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
})
}

// 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
})
Expand Down
6 changes: 3 additions & 3 deletions client/asset/eth/eth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2149,7 +2149,7 @@ 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)
}
Expand Down Expand Up @@ -2725,7 +2725,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)
}
Expand Down Expand Up @@ -3178,7 +3178,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)
}
Expand Down
2 changes: 1 addition & 1 deletion client/asset/eth/nodeclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ func gases(parentID, assetID uint32, contractVer uint32, net dex.Network) *dexet
return nil
}

if contractVer != contractVersionERC20 {
if contractVer != dexeth.ContractVersionERC20 {
contract, found := netToken.SwapContracts[contractVer]
if !found {
return nil
Expand Down
65 changes: 57 additions & 8 deletions dex/networks/eth/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package eth

import (
"encoding/binary"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
Expand Down Expand Up @@ -124,8 +125,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
Expand Down Expand Up @@ -271,6 +284,17 @@ func (v *SwapVector) Locator() []byte {
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 == v2.Value && 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
Expand Down Expand Up @@ -390,12 +414,37 @@ func ParseV1Locator(locator []byte) (v *SwapVector, err error) {
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
)
Loading

0 comments on commit 6860081

Please sign in to comment.