Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Router의 PoC 추가 #9

Merged
merged 4 commits into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 45 additions & 50 deletions core/alpha_router.go
Original file line number Diff line number Diff line change
@@ -1,55 +1,50 @@
package core

//import (
// "router/core/coins/fractions"
// "router/core/currency"
//)
//
//type AlphaRouter struct {
// portionProvider IPortionProvider
//}
//
//func NewAlphaRouter(params AlphaRouterParams) *AlphaRouter {
// return &AlphaRouter{}
//}
//
//// TODO: 원본 코드에서는 async 함수
//// 라우트 한 결과는 SwapRoute
//func (a AlphaRouter) route(
// amount fractions.CurrencyAmount,
// quoteCurrency currency.Currency,
// tradeType TradeType,
// swapConfig SwapOptions,
//) SwapRoute {
// //originalAmount := amount
// //
// //currencyIn, currencyOut := a.determineCurrencyInOutFromTradeType(tradeType, amount, quoteCurrency)
// //
// //// currencyIn, currencyOut은 Currency 타입이고
// //// Currency 타입은 NativeCurrency(GNOT)이거나 Token 타입이다.
// //// 아래에서 Token 타입이길 원하는 듯하다.
// //tokenIn := currencyIn.Wrapped()
// //tokenOut := currencyOut.Wrapped()
// //
// //// core 패키지를 TradeType 패키지로 변경하면 가독성이 더 좋아질 듯 하다.
// //if tradeType == EXACT_OUTPUT {
// // // TODO: GetPortionAmount에서 반환 값인 CurrencyAmount을 반환하지 못할 경우가 있을 수도 있다.(높은 확률로)
// // portionAmount := a.portionProvider.GetPortionAmount(
// // amount,
// // tradeType,
// // swapConfig,
// // )
// //
// // //result := portionAmount.GreaterThan(0)
// // //if result {
// // // amount = amount.add(portionAmount)
// // //}
// //}
// //
// //swapRoute := SwapRoute{}
// //return swapRoute
// return SwapRoute{}
//}
import "router/core/currency"

type AlphaRouter struct {
//chainId ChainId
//portionProvider IPortionProvider
}

func NewAlphaRouter(params AlphaRouterParams) *AlphaRouter {
return &AlphaRouter{}
}

func (a AlphaRouter) route(
baseCurrency currency.Currency, // currencyIn
quoteCurrency currency.Currency, // currencyOut으로 바꿔도 될 것 같다.
amount float64,
// amount fractions.CurrencyAmount,
// tradeType TradeType,
// swapConfig SwapOptions,
) SwapRoute {
//originalAmount := amount

// currencyIn, currencyOut은 Currency 타입이고
// Currency 타입은 NativeCurrency(GNOT)이거나 Token 타입이다.
// 아래에서 Token 타입이길 원하는 듯하다.
//tokenIn := currencyIn.Wrapped()
//tokenOut := currencyOut.Wrapped()

//core 패키지를 TradeType 패키지로 변경하면 가독성이 더 좋아질 듯 하다.
//if tradeType == EXACT_OUTPUT {
// // TODO: GetPortionAmount에서 반환 값인 CurrencyAmount을 반환하지 못할 경우가 있을 수도 있다.(높은 확률로)
// portionAmount := a.portionProvider.GetPortionAmount(
// amount,
// tradeType,
// swapConfig,
// )
//
//result := portionAmount.GreaterThan(0)
//if result {
// amount = amount.add(portionAmount)
//}
//}

return SwapRoute{}
}

//
//func (a AlphaRouter) determineCurrencyInOutFromTradeType(
// tradeType TradeType,
Expand Down
10 changes: 6 additions & 4 deletions core/currency/base_currency.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@ package currency

type BaseCurrency struct {
// The chain ID on which this currency resides
chainId int
ChainId int64
// The decimals used in representing currency amounts
decimals int
decimals int64

// 이 아래 필드는 옵션

// The symbol of the currency, i.e. a short textual non-unique identifier
symbol string
// The name of the currency, i.e. a descriptive textual non-unique identifier
name string
address string
}

func NewBaseCurrency(chainId int, decimals int, symbol string, name string) *BaseCurrency {
// 이게 필요할까??
func NewBaseCurrency(chainId int64, decimals int64, symbol string, name string) *BaseCurrency {
// 아래 코드는 원문
//invariant(Number.isSafeInteger(chainId), 'CHAIN_ID');
//invariant(
Expand All @@ -28,7 +30,7 @@ func NewBaseCurrency(chainId int, decimals int, symbol string, name string) *Bas
}

return &BaseCurrency{
chainId: chainId,
ChainId: chainId,
decimals: decimals,
symbol: symbol,
name: name,
Expand Down
1 change: 0 additions & 1 deletion core/currency/currency.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@ package currency

// Currency는 Token | NativeCurrency
type Currency interface {
Wrapped() Token
}
1 change: 1 addition & 0 deletions core/currency/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ package currency

type Token struct {
BaseCurrency
address string
}
33 changes: 7 additions & 26 deletions core/math/fraction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ func TestNewFraction(t *testing.T) {
tests := []struct {
numerator, denominator int64
expectedNumerator, expectedDenominator int64
expectedError bool
expectedPanic bool
}{
{1, 1, 1, 1, false},
{2, 2, 1, 1, false},
Expand All @@ -25,7 +25,7 @@ func TestNewFraction(t *testing.T) {
t.Run("", func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
if !test.expectedError {
if !test.expectedPanic {
t.Fatalf("NewFraction: unexpected panic: %v", r)
}
}
Expand Down Expand Up @@ -109,7 +109,7 @@ func TestFraction_Mul(t *testing.T) {
numerator1, denominator1 int64
numerator2, denominator2 int64
expectedNumerator, expectedDenominator int64
shouldPanic bool
expectedPanic bool
}{
{1, 2, 1, 3, 1, 6, false},
{-100, 10, 256, -10, 256, 1, false},
Expand All @@ -128,32 +128,15 @@ func TestFraction_Mul(t *testing.T) {
t.Run("", func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
if tt.shouldPanic {
if tt.expectedPanic {
return
}
t.Fatalf("Mul: unexpected panic: %v", r)
}
}()
fraction1 := NewFraction(tt.numerator1, tt.denominator1)

defer func() {
if r := recover(); r != nil {
if tt.shouldPanic {
return
}
t.Fatalf("Mul: unexpected panic: %v", r)
}
}()
fraction2 := NewFraction(tt.numerator2, tt.denominator2)

defer func() {
if r := recover(); r != nil {
if tt.shouldPanic {
return
}
t.Fatalf("Mul: unexpected panic: %v", r)
}
}()
result := fraction1.Mul(fraction2)
expected := NewFraction(tt.expectedNumerator, tt.expectedDenominator)

Expand All @@ -170,7 +153,7 @@ func TestFraction_Div(t *testing.T) {
numerator1, denominator1 int64
numerator2, denominator2 int64
expectedNumerator, expectedDenominator int64
expectedError bool
expectedPanic bool
}{
{1, 2, 1, 3, 3, 2, false},
{-100, 10, 256, -10, 100, 256, false},
Expand All @@ -186,10 +169,8 @@ func TestFraction_Div(t *testing.T) {
t.Run("", func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
if tt.denominator2 == 0 {
if !tt.expectedError {
t.Fatalf("Div: unexpected panic: %v", r)
}
if !tt.expectedPanic {
t.Fatalf("Div: unexpected panic: %v", r)
}
}
}()
Expand Down
17 changes: 17 additions & 0 deletions core/tokens/gnot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package tokens

import "router/core/currency"

type Gnot struct {
currency.NativeCurrency
}

func NewGnot(chainId1 int64) *Gnot {
return &Gnot{
NativeCurrency: currency.NativeCurrency{
BaseCurrency: currency.BaseCurrency{
ChainId: chainId1,
},
},
}
}
87 changes: 87 additions & 0 deletions poc/my_router.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package poc

import (
"fmt"
"math"
)

type MyRouter struct {
network map[string]*Pool
}

func NewMyRouter(edges []*Pool) *MyRouter {
router := &MyRouter{
network: make(map[string]*Pool),
}

for _, edge := range edges {
router.network[edge.Address] = edge
}

return router
}

func (m MyRouter) Swap(request SwapRequest) SwapResult {
// poolName은 from:to가 아니라 to:from일 수 있다.
poolName := request.FromToken + ":" + request.ToToken

if pool, ok := m.network[poolName]; ok {
fmt.Printf("pool found: %v\n", pool)

reserveFromToken, reserveToToken := m.getReserveOfTokenFromPool(request.FromToken, request.ToToken, *pool)
exchangedAmount := m.calculateAmountOfToToken(reserveFromToken, reserveToToken, request.AmountIn, *pool)

//saveSwap()
// TODO: 지금은 간이로 코드 작성하고 나중에 함수로 빼든 리팩토링 할 것
// get by value라 적용이 안되는 중
if pool.TokenA.Symbol == request.FromToken {
pool.ReserveA += request.AmountIn
pool.ReserveB += exchangedAmount
} else {
pool.ReserveA += exchangedAmount
pool.ReserveB += request.AmountIn
}

return SwapResult{
AmountIn: request.AmountIn,
AmountOut: math.Abs(exchangedAmount),
}
} else {
fmt.Println("pool not found")
}

return SwapResult{}
}

func (m MyRouter) getReserveOfTokenFromPool(fromTokenName string, toTokenName string, pool Pool) (float64, float64) {
if fromTokenName == pool.TokenA.Symbol {
return pool.ReserveA, pool.ReserveB
} else {
return pool.ReserveB, pool.ReserveA
}
}

func (m MyRouter) calculateAmountOfToToken(reserveFromToken, reserveToToken, amountIn float64, pool Pool) float64 {
X := reserveFromToken
Y := reserveToToken
dX := amountIn

K := X * Y
L := math.Sqrt(K)
P := X / Y

X_ := X + dX
P_ := (X_ / L) * (X_ / L)

dY := L * (1/math.Sqrt(P_) - 1/math.Sqrt(P))

// X 코인이 dX개 만큼 증가했을 때
// Y 코인은 dY개 만큼 감소해야 한다.
// X -> X + dX, Y -> Y + dY

return dY
}

func (m MyRouter) dijkrtra() {

}
51 changes: 51 additions & 0 deletions poc/my_router_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package poc

import (
"fmt"
"math"
"testing"
)

func TestMyRouter(t *testing.T) {
tokens := map[string]Token{
"a": Token{Symbol: "a"},
"b": Token{Symbol: "b"},
}

tests := []struct {
edges []*Pool
requests []SwapRequest
results []SwapResult
}{
{
[]*Pool{
{"a:b", tokens["a"], tokens["b"], 4000, 1000}},
[]SwapRequest{
{"a", "b", 2000}},
[]SwapResult{
{2000.0, 2000.0 / 6.0},
},
},
}

for _, test := range tests {
t.Run("", func(t *testing.T) {
router := NewMyRouter(test.edges)

for i, request := range test.requests {
result := router.Swap(request)

diff := math.Abs(result.AmountOut - test.results[i].AmountOut)
tolerance := 0.00000001
if diff > tolerance {
t.Fatalf("Swap: Unexpected Token output number, expected: %v, got %v", test.results[i].AmountOut, result.AmountOut)
}
fmt.Println(result)

for _, pool := range router.network {
fmt.Println(pool)
}
}
})
}
}
Loading
Loading