Skip to content

Commit

Permalink
feat: Basic Fraction Entity Added (#2)
Browse files Browse the repository at this point in the history
* feat: fraction entity added

* resolve dependency cycle

change router/router -> router/core

* fix

* delete router/main.go

* Apply suggestions from code review

Co-authored-by: Lee ByeongJun <[email protected]>

---------

Co-authored-by: tolelom <[email protected]>
Co-authored-by: Lee ByeongJun <[email protected]>
  • Loading branch information
3 people authored Aug 27, 2024
1 parent 396a333 commit 1523bd5
Show file tree
Hide file tree
Showing 20 changed files with 354 additions and 76 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package router
package core

type AlphaRouterParams struct {
}
64 changes: 64 additions & 0 deletions core/alpha-router.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package core

import (
"router/core/entities"
"router/core/entities/fractions"
)

type AlphaRouter struct {
portionProvider IPortionProvider
}

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

// TODO: 원본 코드에서는 async 함수
// 라우트 한 결과는 SwapRoute
func (a AlphaRouter) route(
amount fractions.CurrencyAmount,
quoteCurrency entities.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{}
}

func (a AlphaRouter) determineCurrencyInOutFromTradeType(
tradeType TradeType,
amount fractions.CurrencyAmount,
quoteCurrency entities.Currency,
) (entities.Currency, entities.Currency) {
if tradeType == EXACT_INPUT {
return amount.Currency, quoteCurrency
} else {
return quoteCurrency, amount.Currency
}
}
File renamed without changes.
29 changes: 29 additions & 0 deletions core/entities/baseCurrency.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package entities

type BaseCurrency struct {
isNative bool
isToken bool

chainId int
decimals int

symbol string
name string
address string
}

func NewBaseCurrency(chainId int, decimals int, symbol string, name string) *BaseCurrency {
return &BaseCurrency{
// 아래 코드는 원문
//invariant(Number.isSafeInteger(chainId), 'CHAIN_ID');
//invariant(
// decimals >= 0 && decimals < 255 && Number.isInteger(decimals),
// 'DECIMALS',
//);

chainId: chainId,
decimals: decimals,
symbol: symbol,
name: name,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ package entities
// Token과 NativeCurrency 모두 BaseCurrency를 상속받는다.
// 하지만 여기서의 Currency는 NativeCurrency와 Token에 포함된다.
type Currency interface {
wrapped() Token
Wrapped() Token
}
16 changes: 16 additions & 0 deletions core/entities/fractions/currencyAmount.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package fractions

import (
"router/core/entities"
)

type CurrencyAmount struct {
Fraction
Currency entities.Currency
}

//func (c CurrencyAmount) add(other CurrencyAmount) CurrencyAmount {
// added := c.Fraction.add(other)
//
// return CurrencyAmount.fromFractionAmount()
//}
119 changes: 119 additions & 0 deletions core/entities/fractions/fraction.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package fractions

import (
"errors"
"math/big"
)

type Fraction struct {
Numerator *big.Int
Denominator *big.Int
}

func NewFraction(numerator int64, denominator int64) *Fraction {
return &Fraction{
Numerator: big.NewInt(numerator),
Denominator: big.NewInt(denominator),
}
}

func tryParseFraction(value interface{}) (Fraction, error) {
switch v := value.(type) {
case Fraction:
return v, nil
case *big.Int:
return Fraction{Numerator: v, Denominator: big.NewInt(1)}, nil
case big.Int:
return Fraction{Numerator: &v, Denominator: big.NewInt(1)}, nil
// TODO: int64 등 추가 바람
default:
return Fraction{}, errors.New("not a fraction")
}
}

// ---------------------------
// TODO: 형을 자유롭게 받은 다음 tryParseFraction으로 한 번 거르고 사용하도록 하기
// 덧셈
func (f Fraction) Add(other *Fraction) *Fraction {
numerator1 := new(big.Int).Mul(f.Numerator, other.Denominator)
numerator2 := new(big.Int).Mul(other.Numerator, f.Denominator)
denominator := new(big.Int).Mul(f.Denominator, other.Denominator)
resultNumerator := new(big.Int).Add(numerator1, numerator2)

// TODO: 약분
//g := utils.Gcd(resultNumerator, denominator)

return &Fraction{
Numerator: resultNumerator,
Denominator: denominator,
}
}

// 뺄셈
// TODO: 덧셈 활용해서 코드 단순화 할 수도 있을지도...
func (f Fraction) Sub(other *Fraction) *Fraction {
numerator1 := new(big.Int).Mul(f.Numerator, other.Denominator)
numerator2 := new(big.Int).Mul(other.Numerator, f.Denominator)
denominator := new(big.Int).Mul(f.Denominator, other.Denominator)
resultNumerator := new(big.Int).Sub(numerator1, numerator2)

// TODO: 약분
//g := utils.Gcd(resultNumerator, denominator)

return &Fraction{
Numerator: resultNumerator,
Denominator: denominator,
}
}

func (f Fraction) LessThan(other *Fraction) bool {
leftValue := new(big.Int).Mul(f.Numerator, other.Denominator)
rightValue := new(big.Int).Mul(other.Numerator, f.Denominator)
return leftValue.Cmp(rightValue) < 0
}

func (f Fraction) GreaterThan(other *Fraction) bool {
leftValue := new(big.Int).Mul(f.Numerator, other.Denominator)
rightValue := new(big.Int).Mul(other.Numerator, f.Denominator)
return leftValue.Cmp(rightValue) > 0
}

// 약분이 완료되었다는 가정
// WARN: 약분이 안되었다는 가정이라면 약분하는 로직 추가해야 함
func (f Fraction) Equals(other *Fraction) bool {
return f.Numerator.Cmp(other.Numerator) == 0 &&
f.Denominator.Cmp(other.Denominator) == 0
}

// 몫
func (f Fraction) Quotient() *big.Int {
return new(big.Int).Quo(f.Numerator, f.Denominator)
}

// NOTE: 단순 나머지가 아니라 분수 형태로 표시한다
// 좋은 형태의 함수는 아니라 생각
func (f Fraction) Remainder() Fraction {
return Fraction{
Numerator: new(big.Int).Rem(f.Numerator, f.Denominator),
Denominator: f.Denominator,
}
}

// 역
func (f Fraction) Invert() Fraction {
return Fraction{
Numerator: f.Denominator,
Denominator: f.Numerator,
}
}

//func (f Fraction) GreaterThan(other interface{}) (bool, error) {
// otherParsed, err := tryParseFraction(other)
// if err != nil {
// return false, err
// }
//left := f.Numerator * otherParsed.Denominator
//right := otherParsed.Denominator * f.Numerator
//
// return left > right, nil
//}
39 changes: 39 additions & 0 deletions core/entities/fractions/fraction_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package fractions

import (
"testing"
)

func TestFraction_Add(t *testing.T) {
fraction1 := NewFraction(1, 2)
fraction2 := NewFraction(1, 3)

result := fraction1.Add(fraction2)

expected := NewFraction(5, 6)

if result.Numerator.Cmp(expected.Numerator) != 0 || result.Denominator.Cmp(expected.Denominator) != 0 {
t.Fatalf("Add: expected %v, got %v", expected, result)
}
}

func TestFraction_Sub(t *testing.T) {
fraction1 := NewFraction(1, 2)
fraction2 := NewFraction(1, 3)
result := fraction1.Sub(fraction2)
expected := NewFraction(1, 6)
if result.Numerator.Cmp(expected.Numerator) != 0 || result.Denominator.Cmp(expected.Denominator) != 0 {
t.Fatalf("Sub: expected %v, got %v", expected, result)
}
}

func TestFraction_LessThan(t *testing.T) {
fraction1 := NewFraction(1, 2)
fraction2 := NewFraction(1, 3)
result := fraction1.LessThan(fraction2)
expected := false

if result != expected {
t.Fatalf("LessThan: expected %v, got %v", expected, result)
}
}
21 changes: 21 additions & 0 deletions core/entities/gnot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package entities

type Gnot struct {
NativeCurrency
}

func NewGnot(chainId int) *Gnot {
return &Gnot{
NativeCurrency: NativeCurrency{
BaseCurrency: BaseCurrency{
chainId: chainId,
},
},
}
}

func (g Gnot) Wrapped() Token {
wgnot := WGNOT[g.chainId]
// invariant(!!wgnot, 'WRAPPED')
return wgnot
}
6 changes: 6 additions & 0 deletions core/entities/nativeCurrency.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package entities

// Gnot이 NativeCurrency를 상속한다.
type NativeCurrency struct {
BaseCurrency
}
13 changes: 13 additions & 0 deletions core/entities/token.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package entities

type Token struct {
BaseCurrency
}

func NewToken() *Token {
return &Token{}
}

func (t Token) Wrapped() Token {
return t
}
8 changes: 8 additions & 0 deletions core/entities/utils/math.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package utils

import "math/big"

func Gcd(a, b *big.Int) *big.Int {

return a
}
10 changes: 10 additions & 0 deletions core/entities/wgnot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package entities

var WGNOT = map[int]Token{
//1: NewToken(),
//2: NewToken(),
//3: NewToken(),
//4: NewToken(),
//5: NewToken(),
//99: NewToken(),
}
14 changes: 14 additions & 0 deletions core/router.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package core

type SwapRoute struct {
}

type IRouter interface {
}

// TODO: 원문: type SwapOptions = SwapOptionsUniversalRouter | SwapOptionsSwapRouter02
type SwapOptions struct {
}

type SwapOptionsUniversalRouter struct {
}
13 changes: 13 additions & 0 deletions core/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package core

import (
"router/core/entities/fractions"
)

// interface는 I 접두사를 붙이는 것이 관행인가?
type IPortionProvider interface {
GetPortionAmount(tokenOutAmount fractions.CurrencyAmount, tradeType TradeType, swapConfig SwapOptions) fractions.CurrencyAmount
}

type PortionProvider struct {
}
11 changes: 0 additions & 11 deletions main.go

This file was deleted.

Loading

0 comments on commit 1523bd5

Please sign in to comment.