forked from ethereum-optimism/op-geth
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Modifies the legacypool, list, and priceheap to allow for multi currency txs.
- Loading branch information
Showing
23 changed files
with
1,057 additions
and
229 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,34 @@ | ||
package common | ||
|
||
import ( | ||
"math/big" | ||
) | ||
|
||
var ( | ||
ZeroAddress = BytesToAddress([]byte{}) | ||
) | ||
|
||
type ExchangeRates = map[Address]*big.Rat | ||
|
||
func IsCurrencyWhitelisted(exchangeRates ExchangeRates, feeCurrency *Address) bool { | ||
if feeCurrency == nil { | ||
return true | ||
} | ||
|
||
// Check if fee currency is registered | ||
_, ok := exchangeRates[*feeCurrency] | ||
return ok | ||
} | ||
|
||
func AreSameAddress(a, b *Address) bool { | ||
// both are nil or point to the same address | ||
if a == b { | ||
return true | ||
} | ||
// if only one is nil | ||
if a == nil || b == nil { | ||
return false | ||
} | ||
// if they point to the same | ||
return *a == *b | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package common | ||
|
||
import ( | ||
"math/big" | ||
"testing" | ||
) | ||
|
||
var ( | ||
currA = HexToAddress("0xA") | ||
currB = HexToAddress("0xB") | ||
currX = HexToAddress("0xF") | ||
exchangeRates = ExchangeRates{ | ||
currA: big.NewRat(47, 100), | ||
currB: big.NewRat(45, 100), | ||
} | ||
) | ||
|
||
func TestIsWhitelisted(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
feeCurrency *Address | ||
want bool | ||
}{ | ||
{ | ||
name: "no fee currency", | ||
feeCurrency: nil, | ||
want: true, | ||
}, | ||
{ | ||
name: "valid fee currency", | ||
feeCurrency: &currA, | ||
want: true, | ||
}, | ||
{ | ||
name: "invalid fee currency", | ||
feeCurrency: &currX, | ||
want: false, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
if got := IsCurrencyWhitelisted(exchangeRates, tt.feeCurrency); got != tt.want { | ||
t.Errorf("IsWhitelisted() = %v, want %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
package exchange | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"math/big" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/log" | ||
) | ||
|
||
var ( | ||
unitRate = big.NewRat(1, 1) | ||
// ErrNonWhitelistedFeeCurrency is returned if the currency specified to use for the fees | ||
// isn't one of the currencies whitelisted for that purpose. | ||
ErrNonWhitelistedFeeCurrency = errors.New("non-whitelisted fee currency address") | ||
) | ||
|
||
// ConvertCurrency does an exchange conversion from currencyFrom to currencyTo of the value given. | ||
func ConvertCurrency(exchangeRates common.ExchangeRates, val1 *big.Int, currencyFrom *common.Address, currencyTo *common.Address) *big.Int { | ||
goldAmount, err := ConvertCurrencyToGold(exchangeRates, val1, currencyFrom) | ||
if err != nil { | ||
log.Error("Error trying to convert from currency to gold.", "value", val1, "fromCurrency", currencyFrom.Hex()) | ||
} | ||
toAmount, err := ConvertGoldToCurrency(exchangeRates, currencyTo, goldAmount) | ||
if err != nil { | ||
log.Error("Error trying to convert from gold to currency.", "value", goldAmount, "toCurrency", currencyTo.Hex()) | ||
} | ||
return toAmount | ||
} | ||
|
||
func ConvertCurrencyToGold(exchangeRates common.ExchangeRates, currencyAmount *big.Int, feeCurrency *common.Address) (*big.Int, error) { | ||
if feeCurrency == nil { | ||
return currencyAmount, nil | ||
} | ||
exchangeRate, ok := exchangeRates[*feeCurrency] | ||
if !ok { | ||
return nil, ErrNonWhitelistedFeeCurrency | ||
} | ||
return new(big.Int).Div(new(big.Int).Mul(currencyAmount, exchangeRate.Denom()), exchangeRate.Num()), nil | ||
} | ||
|
||
func ConvertGoldToCurrency(exchangeRates common.ExchangeRates, feeCurrency *common.Address, goldAmount *big.Int) (*big.Int, error) { | ||
if feeCurrency == nil { | ||
return goldAmount, nil | ||
} | ||
exchangeRate, ok := exchangeRates[*feeCurrency] | ||
if !ok { | ||
return nil, ErrNonWhitelistedFeeCurrency | ||
} | ||
return new(big.Int).Div(new(big.Int).Mul(goldAmount, exchangeRate.Num()), exchangeRate.Denom()), nil | ||
} | ||
|
||
func getRate(exchangeRates common.ExchangeRates, feeCurrency *common.Address) (*big.Rat, error) { | ||
if feeCurrency == nil { | ||
return unitRate, nil | ||
} | ||
rate, ok := exchangeRates[*feeCurrency] | ||
if !ok { | ||
return nil, fmt.Errorf("fee currency not registered: %s", feeCurrency.Hex()) | ||
} | ||
return rate, nil | ||
} | ||
|
||
// CompareValue compares values in different currencies (nil currency is native currency) | ||
// returns -1 0 or 1 depending if val1 < val2, val1 == val2, or val1 > val2 respectively. | ||
func CompareValue(exchangeRates common.ExchangeRates, val1 *big.Int, feeCurrency1 *common.Address, val2 *big.Int, feeCurrency2 *common.Address) (int, error) { | ||
// Short circuit if the fee currency is the same. | ||
if feeCurrency1 == feeCurrency2 { | ||
return val1.Cmp(val2), nil | ||
} | ||
|
||
exchangeRate1, err := getRate(exchangeRates, feeCurrency1) | ||
if err != nil { | ||
return 0, err | ||
} | ||
exchangeRate2, err := getRate(exchangeRates, feeCurrency2) | ||
if err != nil { | ||
return 0, err | ||
} | ||
|
||
// Below code block is basically evaluating this comparison: | ||
// val1 * exchangeRate1.denominator / exchangeRate1.numerator < val2 * exchangeRate2.denominator / exchangeRate2.numerator | ||
// It will transform that comparison to this, to remove having to deal with fractional values. | ||
// val1 * exchangeRate1.denominator * exchangeRate2.numerator < val2 * exchangeRate2.denominator * exchangeRate1.numerator | ||
leftSide := new(big.Int).Mul( | ||
val1, | ||
new(big.Int).Mul( | ||
exchangeRate1.Denom(), | ||
exchangeRate2.Num(), | ||
), | ||
) | ||
rightSide := new(big.Int).Mul( | ||
val2, | ||
new(big.Int).Mul( | ||
exchangeRate2.Denom(), | ||
exchangeRate1.Num(), | ||
), | ||
) | ||
|
||
return leftSide.Cmp(rightSide), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
package exchange | ||
|
||
import ( | ||
"math/big" | ||
"testing" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
) | ||
|
||
var ( | ||
currA = common.HexToAddress("0xA") | ||
currB = common.HexToAddress("0xB") | ||
currX = common.HexToAddress("0xF") | ||
exchangeRates = common.ExchangeRates{ | ||
currA: big.NewRat(47, 100), | ||
currB: big.NewRat(45, 100), | ||
} | ||
) | ||
|
||
func TestCompareFees(t *testing.T) { | ||
type args struct { | ||
val1 *big.Int | ||
feeCurrency1 *common.Address | ||
val2 *big.Int | ||
feeCurrency2 *common.Address | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
wantResult int | ||
wantErr bool | ||
}{ | ||
// Native currency | ||
{ | ||
name: "Same amount of native currency", | ||
args: args{ | ||
val1: big.NewInt(1), | ||
feeCurrency1: nil, | ||
val2: big.NewInt(1), | ||
feeCurrency2: nil, | ||
}, | ||
wantResult: 0, | ||
}, { | ||
name: "Different amounts of native currency 1", | ||
args: args{ | ||
val1: big.NewInt(2), | ||
feeCurrency1: nil, | ||
val2: big.NewInt(1), | ||
feeCurrency2: nil, | ||
}, | ||
wantResult: 1, | ||
}, { | ||
name: "Different amounts of native currency 2", | ||
args: args{ | ||
val1: big.NewInt(1), | ||
feeCurrency1: nil, | ||
val2: big.NewInt(5), | ||
feeCurrency2: nil, | ||
}, | ||
wantResult: -1, | ||
}, | ||
// Mixed currency | ||
{ | ||
name: "Same amount of mixed currency", | ||
args: args{ | ||
val1: big.NewInt(1), | ||
feeCurrency1: nil, | ||
val2: big.NewInt(1), | ||
feeCurrency2: &currA, | ||
}, | ||
wantResult: -1, | ||
}, { | ||
name: "Different amounts of mixed currency 1", | ||
args: args{ | ||
val1: big.NewInt(100), | ||
feeCurrency1: nil, | ||
val2: big.NewInt(47), | ||
feeCurrency2: &currA, | ||
}, | ||
wantResult: 0, | ||
}, { | ||
name: "Different amounts of mixed currency 2", | ||
args: args{ | ||
val1: big.NewInt(45), | ||
feeCurrency1: &currB, | ||
val2: big.NewInt(100), | ||
feeCurrency2: nil, | ||
}, | ||
wantResult: 0, | ||
}, | ||
// Two fee currencies | ||
{ | ||
name: "Same amount of same currency", | ||
args: args{ | ||
val1: big.NewInt(1), | ||
feeCurrency1: &currA, | ||
val2: big.NewInt(1), | ||
feeCurrency2: &currA, | ||
}, | ||
wantResult: 0, | ||
}, { | ||
name: "Different amounts of same currency 1", | ||
args: args{ | ||
val1: big.NewInt(3), | ||
feeCurrency1: &currA, | ||
val2: big.NewInt(1), | ||
feeCurrency2: &currA, | ||
}, | ||
wantResult: 1, | ||
}, { | ||
name: "Different amounts of same currency 2", | ||
args: args{ | ||
val1: big.NewInt(1), | ||
feeCurrency1: &currA, | ||
val2: big.NewInt(7), | ||
feeCurrency2: &currA, | ||
}, | ||
wantResult: -1, | ||
}, { | ||
name: "Different amounts of different currencies 1", | ||
args: args{ | ||
val1: big.NewInt(47), | ||
feeCurrency1: &currA, | ||
val2: big.NewInt(45), | ||
feeCurrency2: &currB, | ||
}, | ||
wantResult: 0, | ||
}, { | ||
name: "Different amounts of different currencies 2", | ||
args: args{ | ||
val1: big.NewInt(48), | ||
feeCurrency1: &currA, | ||
val2: big.NewInt(45), | ||
feeCurrency2: &currB, | ||
}, | ||
wantResult: 1, | ||
}, { | ||
name: "Different amounts of different currencies 3", | ||
args: args{ | ||
val1: big.NewInt(47), | ||
feeCurrency1: &currA, | ||
val2: big.NewInt(46), | ||
feeCurrency2: &currB, | ||
}, | ||
wantResult: -1, | ||
}, | ||
// Unregistered fee currency | ||
{ | ||
name: "Different amounts of different currencies", | ||
args: args{ | ||
val1: big.NewInt(1), | ||
feeCurrency1: &currA, | ||
val2: big.NewInt(1), | ||
feeCurrency2: &currX, | ||
}, | ||
wantErr: true, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
got, err := CompareValue(exchangeRates, tt.args.val1, tt.args.feeCurrency1, tt.args.val2, tt.args.feeCurrency2) | ||
|
||
if tt.wantErr && err == nil { | ||
t.Error("Expected error in CompareValue()") | ||
} | ||
if got != tt.wantResult { | ||
t.Errorf("CompareValue() = %v, want %v", got, tt.wantResult) | ||
} | ||
}) | ||
} | ||
} |
Oops, something went wrong.