Skip to content

Commit

Permalink
more version clarification. base supported versions on available cont…
Browse files Browse the repository at this point in the history
…racts
  • Loading branch information
buck54321 committed Feb 3, 2025
1 parent 97c2cae commit 5e0a1b5
Show file tree
Hide file tree
Showing 19 changed files with 103 additions and 118 deletions.
17 changes: 13 additions & 4 deletions client/asset/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import (
// networks enables filtering out tokens via the package's SetNetwork.
type nettedToken struct {
*Token
addrs map[dex.Network]string
erc20NetAddrs map[dex.Network]string
netSupportedAssetVersions map[dex.Network][]uint32
}

var (
Expand Down Expand Up @@ -85,7 +86,13 @@ func Register(assetID uint32, driver Driver) {
// RegisterToken should be called to register tokens. If no nets are specified
// the token will be registered for all networks. The user must invoke
// SetNetwork to enable net-based filtering of package function output.
func RegisterToken(tokenID uint32, token *dex.Token, walletDef *WalletDefinition, addrs map[dex.Network]string) {
func RegisterToken(
tokenID uint32,
token *dex.Token,
walletDef *WalletDefinition,
erc20NetAddrs map[dex.Network]string,
netSupportedAssetVersions map[dex.Network][]uint32,
) {
driversMtx.Lock()
defer driversMtx.Unlock()
if _, exists := tokens[tokenID]; exists {
Expand All @@ -101,7 +108,8 @@ func RegisterToken(tokenID uint32, token *dex.Token, walletDef *WalletDefinition
Definition: walletDef,
// ContractAddress specified in SetNetwork.
},
addrs: addrs,
erc20NetAddrs: erc20NetAddrs,
netSupportedAssetVersions: netSupportedAssetVersions,
}
}

Expand Down Expand Up @@ -262,12 +270,13 @@ func UnitInfo(assetID uint32) (dex.UnitInfo, error) {
// network. SetNetwork need only be called once during initialization.
func SetNetwork(net dex.Network) {
for assetID, nt := range tokens {
addr, exists := nt.addrs[net]
addr, exists := nt.erc20NetAddrs[net]
if !exists {
delete(tokens, assetID)
continue
}
nt.Token.ContractAddress = addr
nt.Token.SupportedAssetVersions = nt.netSupportedAssetVersions[net]
}
}

Expand Down
74 changes: 35 additions & 39 deletions client/asset/eth/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,19 @@ func registerToken(tokenID uint32, desc string) {
panic("token " + strconv.Itoa(int(tokenID)) + " not known")
}
netAddrs := make(map[dex.Network]string)
netAssetVersions := make(map[dex.Network][]uint32, 3)
for net, netToken := range token.NetTokens {
netAddrs[net] = netToken.Address.String()
netAssetVersions[net] = make([]uint32, 0, 1)
for ver := range netToken.SwapContracts {
netAssetVersions[net] = append(netAssetVersions[net], ver)
}
}
asset.RegisterToken(tokenID, token.Token, &asset.WalletDefinition{
Type: walletTypeToken,
Tab: "Ethereum token",
Description: desc,
}, netAddrs)
}, netAddrs, netAssetVersions)
}

func init() {
Expand Down Expand Up @@ -1231,11 +1236,13 @@ func (w *ETHWallet) OpenTokenWallet(tokenCfg *asset.TokenConfig) (asset.Wallet,
return nil, fmt.Errorf("could not find token with ID %d on network %s", w.assetID, w.net)
}

supportedAssetVersions := make([]uint32, 0, 1)
contracts := make(map[uint32]common.Address)
gases := make(map[uint32]*dexeth.Gases)
for ver, c := range netToken.SwapContracts {
contracts[ver] = c.Address
gases[ver] = &c.Gas
supportedAssetVersions = append(supportedAssetVersions, ver)
}

aw := &assetWallet{
Expand All @@ -1254,7 +1261,7 @@ func (w *ETHWallet) OpenTokenWallet(tokenCfg *asset.TokenConfig) (asset.Wallet,
ui: token.UnitInfo,
wi: asset.WalletInfo{
Name: token.Name,
SupportedVersions: w.wi.SupportedVersions,
SupportedVersions: supportedAssetVersions,
UnitInfo: token.UnitInfo,
},
tokenAddr: netToken.Address,
Expand Down Expand Up @@ -1671,8 +1678,7 @@ func (w *TokenWallet) FundOrder(ord *asset.Order) (asset.Coins, []dex.Bytes, uin
dex.BipIDSymbol(w.assetID), ord.MaxFeeRate, w.gasFeeLimit())
}

contractVer := contractVersion(ord.AssetVersion)
approvalStatus, err := w.approvalStatus(contractVer)
approvalStatus, err := w.approvalStatus(ord.AssetVersion)
if err != nil {
return nil, nil, 0, fmt.Errorf("error getting approval status: %v", err)
}
Expand All @@ -1686,7 +1692,7 @@ func (w *TokenWallet) FundOrder(ord *asset.Order) (asset.Coins, []dex.Bytes, uin
return nil, nil, 0, fmt.Errorf("unknown approval status %d", approvalStatus)
}

g, err := w.initGasEstimate(int(ord.MaxSwapCount), contractVer,
g, err := w.initGasEstimate(int(ord.MaxSwapCount), contractVersion(ord.AssetVersion),
ord.RedeemVersion, ord.RedeemAssetID, ord.MaxFeeRate)
if err != nil {
return nil, nil, 0, fmt.Errorf("error estimating swap gas: %v", err)
Expand Down Expand Up @@ -1724,7 +1730,7 @@ func (w *ETHWallet) FundMultiOrder(ord *asset.MultiOrder, maxLock uint64) ([]ass
dex.BipIDSymbol(w.assetID), ord.MaxFeeRate, w.gasFeeLimit())
}

g, err := w.initGasEstimate(1, ord.Version, ord.RedeemVersion, ord.RedeemAssetID, ord.MaxFeeRate)
g, err := w.initGasEstimate(1, ord.AssetVersion, ord.RedeemVersion, ord.RedeemAssetID, ord.MaxFeeRate)
if err != nil {
return nil, nil, 0, fmt.Errorf("error estimating swap gas: %v", err)
}
Expand Down Expand Up @@ -1762,7 +1768,7 @@ func (w *TokenWallet) FundMultiOrder(ord *asset.MultiOrder, maxLock uint64) ([]a
dex.BipIDSymbol(w.assetID), ord.MaxFeeRate, w.gasFeeLimit())
}

approvalStatus, err := w.approvalStatus(ord.Version)
approvalStatus, err := w.approvalStatus(ord.AssetVersion)
if err != nil {
return nil, nil, 0, fmt.Errorf("error getting approval status: %v", err)
}
Expand All @@ -1776,7 +1782,7 @@ func (w *TokenWallet) FundMultiOrder(ord *asset.MultiOrder, maxLock uint64) ([]a
return nil, nil, 0, fmt.Errorf("unknown approval status %d", approvalStatus)
}

g, err := w.initGasEstimate(1, ord.Version,
g, err := w.initGasEstimate(1, ord.AssetVersion,
ord.RedeemVersion, ord.RedeemAssetID, ord.MaxFeeRate)
if err != nil {
return nil, nil, 0, fmt.Errorf("error estimating swap gas: %v", err)
Expand Down Expand Up @@ -1936,7 +1942,7 @@ func (w *assetWallet) approvalGas(newGas *big.Int, contractVer uint32) (uint64,

approveGas := ourGas.Approve

if approveEst, err := w.estimateApproveGas(newGas); err != nil {
if approveEst, err := w.estimateApproveGas(contractVer, newGas); err != nil {
return 0, fmt.Errorf("error estimating approve gas: %v", err)
} else if approveEst > approveGas {
w.log.Warnf("Approve gas estimate %d is greater than the expected value %d. Using live estimate + 10%%.", approveEst, approveGas)
Expand Down Expand Up @@ -2495,8 +2501,8 @@ 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, dexeth.ContractVersionERC20, func(c tokenContractor) error {
func (w *assetWallet) tokenAllowance(contractVer uint32) (allowance *big.Int, err error) {
return allowance, w.withTokenContractor(w.assetID, contractVer, func(c tokenContractor) error {
allowance, err = c.allowance(w.ctx)
return err
})
Expand All @@ -2523,41 +2529,43 @@ func (w *assetWallet) approveToken(ctx context.Context, amount *big.Int, gasLimi
})
}

func (w *assetWallet) approvalStatus(version uint32) (asset.ApprovalStatus, error) {
func (w *assetWallet) approvalStatus(assetVer uint32) (asset.ApprovalStatus, error) {
if w.assetID == w.baseChainID {
return asset.Approved, nil
}

contractVer := contractVersion(assetVer)

// If the result has been cached, return what is in the cache.
// The cache is cleared if an approval/unapproval tx is done.
w.approvalsMtx.RLock()
if approved, cached := w.approvalCache[version]; cached {
w.approvalsMtx.RUnlock()
approved, cached := w.approvalCache[contractVer]
_, pending := w.pendingApprovals[contractVer]
w.approvalsMtx.RUnlock()
if cached {
if approved {
return asset.Approved, nil
} else {
return asset.NotApproved, nil
}
}

if _, pending := w.pendingApprovals[version]; pending {
w.approvalsMtx.RUnlock()
if pending {
return asset.Pending, nil
}
w.approvalsMtx.RUnlock()

w.approvalsMtx.Lock()
defer w.approvalsMtx.Unlock()

currentAllowance, err := w.tokenAllowance()
currentAllowance, err := w.tokenAllowance(contractVer)
if err != nil {
return asset.NotApproved, fmt.Errorf("error retrieving current allowance: %w", err)
}
if currentAllowance.Cmp(unlimitedAllowanceReplenishThreshold) >= 0 {
w.approvalCache[version] = true
w.approvalCache[contractVer] = true
return asset.Approved, nil
}
w.approvalCache[version] = false
w.approvalCache[contractVer] = false
return asset.NotApproved, nil
}

Expand Down Expand Up @@ -2687,16 +2695,14 @@ func (w *TokenWallet) ApprovalFee(assetVer uint32, approve bool) (uint64, error)
// ApprovalStatus returns the approval status for each version of the
// token's swap contract.
func (w *TokenWallet) ApprovalStatus() map[uint32]asset.ApprovalStatus {
versions := w.Info().SupportedVersions

statuses := map[uint32]asset.ApprovalStatus{}
for _, version := range versions {
status, err := w.approvalStatus(version)
for _, assetVer := range w.wi.SupportedVersions {
status, err := w.approvalStatus(assetVer)
if err != nil {
w.log.Errorf("error checking approval status for version %d: %w", version, err)
w.log.Errorf("error checking approval status for swap contract version %d: %w", assetVer, err)
continue
}
statuses[version] = status
statuses[assetVer] = status
}

return statuses
Expand Down Expand Up @@ -4456,31 +4462,21 @@ func (w *assetWallet) withTokenContractor(assetID, contractVer uint32, f func(to
return w.withContractor(contractVer, func(c contractor) error {
tc, is := c.(tokenContractor)
if !is {
return fmt.Errorf("contractor for %d %T is not a tokenContractor", assetID, c)
return fmt.Errorf("contractor for %s version %d is not a tokenContractor. type = %T", w.ui.Conventional.Unit, contractVer, c)
}
return f(tc)
})
}

// 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, dexeth.ContractVersionERC20, func(c tokenContractor) error {
func (w *assetWallet) estimateApproveGas(contractVer uint32, newGas *big.Int) (gas uint64, err error) {
return gas, w.withTokenContractor(w.assetID, contractVer, 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, dexeth.ContractVersionERC20, func(c tokenContractor) error {
gas, err = c.estimateTransferGas(w.ctx, w.evmify(val))
return err
})
}

// Can uncomment here and in redeem to test rejected redemption reauthorization.
// var firstRedemptionBorked atomic.Bool

Expand Down
32 changes: 16 additions & 16 deletions client/asset/eth/eth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2189,8 +2189,8 @@ func testFundMultiOrder(t *testing.T, assetID uint32) {
tokenBal: uint64(dexeth.GweiFactor),
parentBal: uint64(dexeth.GweiFactor),
multiOrder: &asset.MultiOrder{
Version: fromAsset.Version,
MaxFeeRate: fromAsset.MaxFeeRate,
AssetVersion: fromAsset.Version,
MaxFeeRate: fromAsset.MaxFeeRate,
Values: []*asset.MultiOrderValue{
{
Value: uint64(dexeth.GweiFactor) / 2,
Expand All @@ -2209,8 +2209,8 @@ func testFundMultiOrder(t *testing.T, assetID uint32) {
tokenBal: uint64(dexeth.GweiFactor),
parentBal: uint64(dexeth.GweiFactor),
multiOrder: &asset.MultiOrder{
Version: fromAsset.Version,
MaxFeeRate: fromAsset.MaxFeeRate,
AssetVersion: fromAsset.Version,
MaxFeeRate: fromAsset.MaxFeeRate,
Values: []*asset.MultiOrderValue{
{
Value: uint64(dexeth.GweiFactor) / 2,
Expand All @@ -2231,8 +2231,8 @@ func testFundMultiOrder(t *testing.T, assetID uint32) {
tokenBal: uint64(dexeth.GweiFactor),
parentBal: uint64(dexeth.GweiFactor),
multiOrder: &asset.MultiOrder{
Version: fromAsset.Version,
MaxFeeRate: fromAsset.MaxFeeRate,
AssetVersion: fromAsset.Version,
MaxFeeRate: fromAsset.MaxFeeRate,
Values: []*asset.MultiOrderValue{
{
Value: uint64(dexeth.GweiFactor) / 2,
Expand All @@ -2254,8 +2254,8 @@ func testFundMultiOrder(t *testing.T, assetID uint32) {
tokenBal: uint64(dexeth.GweiFactor),
parentBal: uint64(dexeth.GweiFactor),
multiOrder: &asset.MultiOrder{
Version: fromAsset.Version,
MaxFeeRate: fromAsset.MaxFeeRate,
AssetVersion: fromAsset.Version,
MaxFeeRate: fromAsset.MaxFeeRate,
Values: []*asset.MultiOrderValue{
{
Value: uint64(dexeth.GweiFactor) / 2,
Expand All @@ -2276,8 +2276,8 @@ func testFundMultiOrder(t *testing.T, assetID uint32) {
tokenBal: uint64(dexeth.GweiFactor),
parentBal: uint64(dexeth.GweiFactor),
multiOrder: &asset.MultiOrder{
Version: fromAsset.Version,
MaxFeeRate: fromAsset.MaxFeeRate,
AssetVersion: fromAsset.Version,
MaxFeeRate: fromAsset.MaxFeeRate,
Values: []*asset.MultiOrderValue{
{
Value: uint64(dexeth.GweiFactor) / 2,
Expand All @@ -2298,8 +2298,8 @@ func testFundMultiOrder(t *testing.T, assetID uint32) {
tokenBal: uint64(dexeth.GweiFactor) - 1,
parentBal: uint64(dexeth.GweiFactor),
multiOrder: &asset.MultiOrder{
Version: fromAsset.Version,
MaxFeeRate: fromAsset.MaxFeeRate,
AssetVersion: fromAsset.Version,
MaxFeeRate: fromAsset.MaxFeeRate,
Values: []*asset.MultiOrderValue{
{
Value: uint64(dexeth.GweiFactor) / 2,
Expand All @@ -2319,8 +2319,8 @@ func testFundMultiOrder(t *testing.T, assetID uint32) {
tokenBal: uint64(dexeth.GweiFactor),
parentBal: swapGas * 4 * fromAsset.MaxFeeRate,
multiOrder: &asset.MultiOrder{
Version: fromAsset.Version,
MaxFeeRate: fromAsset.MaxFeeRate,
AssetVersion: fromAsset.Version,
MaxFeeRate: fromAsset.MaxFeeRate,
Values: []*asset.MultiOrderValue{
{
Value: uint64(dexeth.GweiFactor) / 2,
Expand All @@ -2339,8 +2339,8 @@ func testFundMultiOrder(t *testing.T, assetID uint32) {
tokenBal: uint64(dexeth.GweiFactor),
parentBal: swapGas*4*fromAsset.MaxFeeRate - 1,
multiOrder: &asset.MultiOrder{
Version: fromAsset.Version,
MaxFeeRate: fromAsset.MaxFeeRate,
AssetVersion: fromAsset.Version,
MaxFeeRate: fromAsset.MaxFeeRate,
Values: []*asset.MultiOrderValue{
{
Value: uint64(dexeth.GweiFactor) / 2,
Expand Down
11 changes: 6 additions & 5 deletions client/asset/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,9 @@ type WalletDefinition struct {
// Token combines the generic dex.Token with a WalletDefinition.
type Token struct {
*dex.Token
Definition *WalletDefinition `json:"definition"`
ContractAddress string `json:"contractAddress"` // Set in SetNetwork
Definition *WalletDefinition `json:"definition"`
ContractAddress string `json:"contractAddress"` // Set in SetNetwork
SupportedAssetVersions []uint32 `json:"supportedAssetVersions"`
}

// WalletInfo is auxiliary information about an ExchangeWallet.
Expand Down Expand Up @@ -1440,10 +1441,10 @@ type MultiOrderValue struct {

// MultiOrder is order details needed for FundMultiOrder.
type MultiOrder struct {
// Version is the asset version of the "from" asset with the init
// AssetVersion is the asset version of the "from" asset with the init
// transaction.
Version uint32
Values []*MultiOrderValue
AssetVersion uint32
Values []*MultiOrderValue
// MaxFeeRate is the largest possible fee rate for the init transaction (of
// this "from" asset) specific to and provided by a particular server, and
// is used to calculate the funding required to cover fees.
Expand Down
Loading

0 comments on commit 5e0a1b5

Please sign in to comment.