diff --git a/_test/live_test.mk b/_test/live_test.mk index 59739aa2..50817660 100644 --- a/_test/live_test.mk +++ b/_test/live_test.mk @@ -21,8 +21,8 @@ ADDR_GOV := g1kmat25auuqf0h5qvd4q7s707r8let5sky4tr76 TX_EXPIRE := 9999999999 NOW := $(shell date +%s) -INCENTIVE_START := $(shell expr $(NOW) + 160) # GIVE ENOUGH TIME TO EXECUTE PREVIOUS TXS -INCENTIVE_END := $(shell expr $(NOW) + 160 + 7776000) # 7776000 SECONDS = 90 DAY +INCENTIVE_START := $(shell expr $(NOW) + 360) # GIVE ENOUGH TIME TO EXECUTE PREVIOUS TXS +INCENTIVE_END := $(shell expr $(NOW) + 360 + 7776000) # 7776000 SECONDS = 90 DAY MAKEFILE := $(shell realpath $(firstword $(MAKEFILE_LIST))) GNOLAND_RPC_URL ?= localhost:26657 @@ -38,6 +38,7 @@ help: all: wait deploy faucet approve pool-setup position-mint staker-stake router-swap staker-unstake done .PHONY: deploy +# deploy: deploy-foo deploy-bar deploy-baz deploy-qux deploy-gns deploy-obl deploy-gnft deploy-const deploy-common deploy-gov deploy-pool deploy-position deploy-staker deploy-router deploy-wrapper deploy: deploy-foo deploy-bar deploy-baz deploy-qux deploy-wugnot deploy-gns deploy-obl deploy-gnft deploy-const deploy-common deploy-gov deploy-pool deploy-position deploy-staker deploy-router deploy-wrapper .PHONY: faucet diff --git a/router/_RPC_api.gno b/router/_RPC_api.gno index 4d597f3b..45c3bf2a 100644 --- a/router/_RPC_api.gno +++ b/router/_RPC_api.gno @@ -9,12 +9,12 @@ import ( "gno.land/p/demo/ufmt" "gno.land/r/demo/consts" - p "gno.land/r/demo/pool" + pl "gno.land/r/demo/pool" ) -type TokenPathPrice struct { - Path string `json:"path"` - Price bigint `json:"price"` +type TokenRatio struct { + Token string `json:"token"` + Ratio bigint `json:"ratio"` } type ResponseQueryBase struct { @@ -24,7 +24,7 @@ type ResponseQueryBase struct { type ResponseGetRatiosFromBase struct { Stat ResponseQueryBase `json:"stat"` - Response []TokenPathPrice `json:"response"` + Response []TokenRatio `json:"response"` } func ApiGetRatiosFromBase() string { @@ -33,7 +33,7 @@ func ApiGetRatiosFromBase() string { Timestamp: GetTimestamp(), } - ratios := getRatiosFromBase(3) + ratios := findRatios(3) r := ResponseGetRatiosFromBase{ Stat: qb, Response: ratios, @@ -47,109 +47,105 @@ func ApiGetRatiosFromBase() string { return string(rr) } -func getRatiosFromBase(maxHops int) []TokenPathPrice { - tokenPrice := make(map[string]bigint, 0) - - // BASE - tokenPrice[consts.WRAPPED_WUGNOT] = consts.Q96 // ~= 1 - - // ELSE - tokenList := getTokenList() - for _, token := range tokenList { - if token != consts.WRAPPED_WUGNOT { - _swapPaths := findSwapPaths(token, consts.WRAPPED_WUGNOT, maxHops) - swapPaths := strings.Split(_swapPaths, "_FIN_") - swapPaths = swapPaths[:len(swapPaths)-1] - numSwapPaths := len(swapPaths) - - thisTokenPriceX96 := bigint(0) - if numSwapPaths < 1 { // NO CONNECTION TO BASE - tokenPrice[token] = 0 - } else { - for _, swapPath := range swapPaths { - numPools := strings.Count(swapPath, ",") / 2 - - switch numPools { - case 0: - thisTokenPriceX96 = 0 - case 1: - priceRatio := calculateTokenPrice(token, swapPath, numPools, 0, 1) - thisTokenPriceX96 += priceRatio - case 2: - priceRatio := calculateTokenPrice(token, swapPath, numPools, 0, 1) - thisTokenPriceX96 += priceRatio - case 3: - priceRatio := calculateTokenPrice(token, swapPath, numPools, 0, 1) - thisTokenPriceX96 += priceRatio - default: - thisTokenPriceX96 = 0 - } +func findRatios(maxHops int) []TokenRatio { + var tokenRatio = make(map[string]bigint, 0) + // WGNOT + tokenRatio[consts.WRAPPED_WUGNOT] = consts.Q96 // ~= 1 + + tokens := getTokenList() + + pools := findCandidatePools() + + for _, token := range tokens { + if token == consts.WRAPPED_WUGNOT { + continue + } + + routes := computeAllRoutes(consts.WRAPPED_WUGNOT, token, maxHops, pools) + + if len(routes) == 0 { + // NO ROUTES FOUND => SET RATIO TO 0 + tokenRatio[token] = 0 + } else { + numRoutes := len(routes) + + var _tokenRatioX96 bigint + + for _, route := range routes { + numHops := len(route.route) + + switch numHops { + case 1, 2, 3: + priceRatio := calculateTokenRatio(token, route.route, 0, 1) + _tokenRatioX96 += priceRatio + default: + _tokenRatioX96 = 0 } - avgPriceX96 := thisTokenPriceX96 / bigint(numSwapPaths) - tokenPrice[token] = avgPriceX96 } + avgPriceX96 := _tokenRatioX96 / bigint(numRoutes) + tokenRatio[token] = avgPriceX96 + } - // TOKEN ENDS } + // LOOP FIN - tokenPrices := []TokenPathPrice{} - for token, price := range tokenPrice { - tokenPrices = append(tokenPrices, TokenPathPrice{ - Path: token, - Price: price, + var tokenRatios = []TokenRatio{} + for token, ratio := range tokenRatio { + tokenRatios = append(tokenRatios, TokenRatio{ + Token: token, + Ratio: ratio, }) } - return tokenPrices + return tokenRatios } -func calculateTokenPrice(currentToken, swapPath string, numPools, proceed int, currentPriceX96 bigint) bigint { - currentPoolPathKey := makePoolPath(swapPath, proceed) - currentPool := p.GetPoolFromPoolPath(currentPoolPathKey) +func calculateTokenRatio(currentToken string, routes []PoolWithMeta, proceed int, priceX96 bigint) bigint { + poolPath := routes[len(routes)-proceed-1].poolPath + pool := pl.GetPoolFromPoolPath(poolPath) - poolToken0 := currentPool.PoolGetToken0Path() - poolToken1 := currentPool.PoolGetToken1Path() + token0Path := pool.PoolGetToken0Path() + token1Path := pool.PoolGetToken1Path() - if poolToken0 == currentToken { - currentSqrtPriceX96 := currentPool.PoolGetSlot0SqrtPriceX96() + if token1Path == currentToken { + poolSqrtPriceX96 := pool.PoolGetSlot0SqrtPriceX96() - currentPriceX96 *= currentSqrtPriceX96 * currentSqrtPriceX96 - currentToken = poolToken1 - } else if poolToken1 == currentToken { - currentTick := currentPool.PoolGetSlot0Tick() - oppositeTick := -currentTick + priceX96 *= poolSqrtPriceX96 * poolSqrtPriceX96 + currentToken = token0Path + } else if token0Path == currentToken { + poolTick := pool.PoolGetSlot0Tick() + oppositeTick := -poolTick oppositeSqrtPriceX96 := common.TickMathGetSqrtRatioAtTick(oppositeTick) - currentPriceX96 *= oppositeSqrtPriceX96 * oppositeSqrtPriceX96 - currentToken = poolToken0 + priceX96 *= oppositeSqrtPriceX96 * oppositeSqrtPriceX96 + currentToken = token1Path } else { - panic("[ROUTER] _RPC_api.gno__calculateTokenPrice() || wrong condition") + // wrong condition + // panic("[ROUTER] _RPC_api.gno__calculateTokenRatio() || wrong condition") + return 0 + } - if proceed == numPools-1 { - for { - if currentPriceX96 < (consts.Q96 * 2) { - return currentPriceX96 + proceed += 1 + + if proceed == len(routes) { // numHops + for { // remove as much X96 as possible + tempPriceX96 := priceX96 + priceX96 /= consts.Q96 + + if priceX96 < consts.MIN_PRICE { + return tempPriceX96 } - currentPriceX96 /= consts.Q96 } } - return calculateTokenPrice(currentToken, swapPath, numPools, proceed+1, currentPriceX96) -} - -func sqrt(x bigint, n int) bigint { - result := bigint(1) - for i := 0; i < n; i++ { - result *= x - } - return result + return calculateTokenRatio(currentToken, routes, proceed, priceX96) } func getTokenList() []string { seen := make(map[string]bool) uniqueTokenList := []string{} - poolList := p.PoolGetPoolList() + poolList := pl.PoolGetPoolList() for _, poolPath := range poolList { token0Path, token1Path, _ := poolPathWithFeeDivide(poolPath) @@ -166,26 +162,6 @@ func getTokenList() []string { return uniqueTokenList } -func makePoolPath(poolPath string, poolIndex int) string { - poolDatas := strings.Split(poolPath, ",") - // Calculate the indices for token paths and fee based on poolIndex. - baseIndex := poolIndex * 2 - if baseIndex+2 >= len(poolDatas) { - panic(ufmt.Sprintf("[ROUTER] _RPC_api.gno__makePoolPath() || index out of range for pool index: %d", poolIndex)) - } - - token0Path := poolDatas[baseIndex] - token1Path := poolDatas[baseIndex+2] - fee := poolDatas[baseIndex+1] - - // Ensure the tokens are in a consistent order. - if token0Path > token1Path { - token0Path, token1Path = token1Path, token0Path - } - - return token0Path + ":" + token1Path + ":" + fee -} - func poolPathWithFeeDivide(poolPath string) (string, string, int) { poolPathSplit := strings.Split(poolPath, ":") require(len(poolPathSplit) == 3, ufmt.Sprintf("[ROUTER] _RPC_api.gno__poolPathWithFeeDivide() || len(poolPathSplit) != 3, poolPath: %s", poolPath)) @@ -197,19 +173,3 @@ func poolPathWithFeeDivide(poolPath string) (string, string, int) { return poolPathSplit[0], poolPathSplit[1], feeInt } - -func singlePoolPathWithFeeDivide(poolPath string) (string, string) { - singlePoolPathSplit := strings.Split(poolPath, ":") - require(len(singlePoolPathSplit) == 2, ufmt.Sprintf("[ROUTER] _RPC_api.gno__singlePoolPathWithFeeDivide || len(singlePoolPathSplit) != 2, poolPath: %s", poolPath)) - - return singlePoolPathSplit[0], singlePoolPathSplit[1] -} - -func removeItemFromStringArray(s []string, r string) []string { - for i, v := range s { - if v == r { - return append(s[:i], s[i+1:]...) - } - } - return s -} diff --git a/router/_TEST_INIT_basic_test.gno b/router/_TEST_INIT_basic_test.gno index a91aafa2..c753acca 100644 --- a/router/_TEST_INIT_basic_test.gno +++ b/router/_TEST_INIT_basic_test.gno @@ -14,16 +14,18 @@ import ( "gno.land/r/demo/obl" "gno.land/r/demo/wugnot" + + "gno.land/r/demo/consts" ) var ( - test1 std.Address - poolAddr, posAddr, stakerAddr std.Address + test1 std.Address barPath = "gno.land/r/demo/bar" bazPath = "gno.land/r/demo/baz" fooPath = "gno.land/r/demo/foo" gnsPath = "gno.land/r/demo/gns" + oblPath = "gno.land/r/demo/obl" quxPath = "gno.land/r/demo/qux" wgnotPath = "gno.land/r/demo/wugnot" @@ -36,30 +38,26 @@ var ( func init() { test1 = std.Address("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") + // prepare ugnot testBanker := std.GetBanker(std.BankerTypeRealmIssue) testBanker.IssueCoin(test1, "ugnot", 500_000_000_000_000) - poolAddr = std.DerivePkgAddr("gno.land/r/demo/pool") - posAddr = std.DerivePkgAddr("gno.land/r/demo/position") - stakerAddr = std.DerivePkgAddr("gno.land/r/demo/staker") - std.TestSetPrevAddr(test1) + gns.Approve(a2u(consts.POOL_ADDR), 500_000_000_000_000) - gns.Approve(a2u(poolAddr), 500_000_000_000_000) - - bar.Approve(a2u(poolAddr), 500_000_000_000_000) - baz.Approve(a2u(poolAddr), 500_000_000_000_000) - foo.Approve(a2u(poolAddr), 500_000_000_000_000) - qux.Approve(a2u(poolAddr), 500_000_000_000_000) + bar.Approve(a2u(consts.POOL_ADDR), 500_000_000_000_000) + baz.Approve(a2u(consts.POOL_ADDR), 500_000_000_000_000) + foo.Approve(a2u(consts.POOL_ADDR), 500_000_000_000_000) + qux.Approve(a2u(consts.POOL_ADDR), 500_000_000_000_000) - obl.Approve(a2u(stakerAddr), 500_000_000_000_000) // to create external incentive - wugnot.Approve(a2u(stakerAddr), 500_000_000_000_000) // to create (native) external incentive + obl.Approve(a2u(consts.STAKER_ADDR), 500_000_000_000_000) // to create external incentive + wugnot.Approve(a2u(consts.STAKER_ADDR), 500_000_000_000_000) // to create (native) external incentive - wugnot.Approve(a2u(poolAddr), 500_000_000_000_000) + wugnot.Approve(a2u(consts.POOL_ADDR), 500_000_000_000_000) - std.TestSetPrevAddr(std.Address("g1paqttvcjcluuya9n9twyw7yacv54mt7ld3gvzm")) // IRA, r3v4_xxx: CHANGE WHEN DEPLOYING TO OFFICIAL NETWORK - gns.Approve(a2u(stakerAddr), 500_000_000_000_000) // to create internal incentive + std.TestSetPrevAddr(consts.INTERNAL_REWARD_ACCOUNT) // r3v4_xxx: CHANGE WHEN DEPLOYING TO OFFICIAL NETWORK + gns.Approve(a2u(consts.STAKER_ADDR), 500_000_000_000_000) // to create internal incentive } /* HELPER */ diff --git a/router/_TEST_INIT_register_tokens_test.gno b/router/_TEST_INIT_register_tokens_test.gno index fa469e71..a444627c 100644 --- a/router/_TEST_INIT_register_tokens_test.gno +++ b/router/_TEST_INIT_register_tokens_test.gno @@ -9,6 +9,10 @@ import ( "gno.land/r/demo/qux" + "gno.land/r/demo/fred" + + "gno.land/r/demo/thud" + "gno.land/r/demo/wugnot" "gno.land/r/demo/obl" @@ -80,6 +84,36 @@ func (QuxToken) Approve() func(spender users.AddressOrName, amount uint64) { return qux.Approve } +type FredToken struct{} + +func (FredToken) Transfer() func(to users.AddressOrName, amount uint64) { + return fred.Transfer +} +func (FredToken) TransferFrom() func(from, to users.AddressOrName, amount uint64) { + return fred.TransferFrom +} +func (FredToken) BalanceOf() func(owner users.AddressOrName) uint64 { + return fred.BalanceOf +} +func (FredToken) Approve() func(spender users.AddressOrName, amount uint64) { + return fred.Approve +} + +type ThudToken struct{} + +func (ThudToken) Transfer() func(to users.AddressOrName, amount uint64) { + return thud.Transfer +} +func (ThudToken) TransferFrom() func(from, to users.AddressOrName, amount uint64) { + return thud.TransferFrom +} +func (ThudToken) BalanceOf() func(owner users.AddressOrName) uint64 { + return thud.BalanceOf +} +func (ThudToken) Approve() func(spender users.AddressOrName, amount uint64) { + return thud.Approve +} + type WugnotToken struct{} func (WugnotToken) Transfer() func(to users.AddressOrName, amount uint64) { @@ -134,6 +168,8 @@ func init() { pool.RegisterGRC20Interface("gno.land/r/demo/foo", FooToken{}) pool.RegisterGRC20Interface("gno.land/r/demo/baz", BazToken{}) pool.RegisterGRC20Interface("gno.land/r/demo/qux", QuxToken{}) + pool.RegisterGRC20Interface("gno.land/r/demo/fred", FredToken{}) + pool.RegisterGRC20Interface("gno.land/r/demo/thud", ThudToken{}) pool.RegisterGRC20Interface("gno.land/r/demo/wugnot", WugnotToken{}) pool.RegisterGRC20Interface("gno.land/r/demo/obl", OBLToken{}) pool.RegisterGRC20Interface("gno.land/r/demo/gns", GNSToken{}) @@ -143,6 +179,8 @@ func init() { RegisterGRC20Interface("gno.land/r/demo/foo", FooToken{}) RegisterGRC20Interface("gno.land/r/demo/baz", BazToken{}) RegisterGRC20Interface("gno.land/r/demo/qux", QuxToken{}) + RegisterGRC20Interface("gno.land/r/demo/fred", FredToken{}) + RegisterGRC20Interface("gno.land/r/demo/thud", ThudToken{}) RegisterGRC20Interface("gno.land/r/demo/wugnot", WugnotToken{}) RegisterGRC20Interface("gno.land/r/demo/obl", OBLToken{}) RegisterGRC20Interface("gno.land/r/demo/gns", GNSToken{}) diff --git a/router/_TEST_router_api_getter_test.gnoa b/router/_TEST_router_api_getter_test.gnoa deleted file mode 100644 index 87c4ee4f..00000000 --- a/router/_TEST_router_api_getter_test.gnoa +++ /dev/null @@ -1,60 +0,0 @@ -package router - -import ( - "encoding/gjson" - "std" - "testing" - - p "gno.land/r/demo/pool" - pos "gno.land/r/demo/position" - - wugnot "gno.land/r/demo/wugnot" -) - -func TestInitManual(t *testing.T) { - std.TestSetOrigCaller(test1) - p.InitManual() - std.TestSkipHeights(1) -} - -func TestCreatePool(t *testing.T) { - std.TestSetOrigCaller(test1) - - p.CreatePool(wgnotPath, barPath, fee100, 130621891405341611593710811006) // tick > -9999, ratio = x0.3679346241605614 ( 1 bar = 0.37 wugnot ) - p.CreatePool(barPath, quxPath, fee100, 130621891405341611593710811006) // tick = 10_000, ratio = x2.7181459268252253 ( 1 bar = 2.7 qux ) - p.CreatePool(quxPath, bazPath, fee100, 215353707227994575755767921544) // tick > -20000, ratio = x0.13534881653937755 ( 1 qux = 0.13 baz ) - - jsonOutput := p.ApiGetPools() - jsonStr := gjson.Parse(jsonOutput) - shouldEQ(t, len(jsonStr.Get("response").Array()), 3) -} - -func TestPositionMint(t *testing.T) { - std.TestSetOrigCaller(test1) - - // simulate transfer & decrase - std.TestSetOrigSend(std.Coins{{"ugnot", 10_000_000}}, nil) - testBanker := std.GetBanker(std.BankerTypeRealmIssue) - testBanker.RemoveCoin(std.GetOrigCaller(), "ugnot", 10_000_000) - - // Deposit(wrap) - std.TestSetPrevAddr(test1) - wugnot.Deposit() - - pos.Mint(wgnotPath, barPath, fee100, int32(9000), int32(11000), bigint(10_000_000), bigint(10_000_000), 0, 0, max_timeout) - - pos.Mint(barPath, quxPath, fee100, int32(9000), int32(11000), bigint(10_000_000), bigint(10_000_000), 0, 0, max_timeout) - pos.Mint(quxPath, bazPath, fee100, int32(18000), int32(22000), bigint(10_000_000), bigint(10_000_000), 0, 0, max_timeout) -} - -func TestApiGetRatiosFromBase(t *testing.T) { - jsonOutput := ApiGetRatiosFromBase() - jsonStr := gjson.Parse(jsonOutput) - jsonArr := jsonStr.Get("response").Array() - shouldEQ(t, len(jsonArr), 4) - - shouldEQ(t, jsonArr[0].String(), "{\"path\":\"gno.land/r/demo/wugnot\",\"price\":79228162514264337593543950336}") // 1 - shouldEQ(t, jsonArr[1].String(), "{\"path\":\"gno.land/r/demo/bar\",\"price\":29147869410676662479573841823}") // 0.3678978344 - shouldEQ(t, jsonArr[2].String(), "{\"path\":\"gno.land/r/demo/qux\",\"price\":10723438032895153248244559718}") // 0.1353488165 - shouldEQ(t, jsonArr[3].String(), "{\"path\":\"gno.land/r/demo/baz\",\"price\":1451404646985709758556457134}") // 0.0183193021 -} diff --git a/router/_TEST_router_ratio_test.gno b/router/_TEST_router_ratio_test.gno new file mode 100644 index 00000000..e1542e24 --- /dev/null +++ b/router/_TEST_router_ratio_test.gno @@ -0,0 +1,114 @@ +package router + +import ( + "encoding/gjson" + "std" + "testing" + + pl "gno.land/r/demo/pool" + pn "gno.land/r/demo/position" + + "gno.land/p/demo/common" + + "gno.land/r/demo/wugnot" +) + +func TestInitManual(t *testing.T) { + std.TestSetOrigCaller(test1) + pl.InitManual() + std.TestSkipHeights(1) +} + +func TestPoolCreatePool(t *testing.T) { + std.TestSetOrigCaller(test1) + + // 1 HOPS + pl.CreatePool(barPath, wgnotPath, fee100, common.TickMathGetSqrtRatioAtTick(10_000)) + pl.CreatePool(barPath, wgnotPath, fee500, common.TickMathGetSqrtRatioAtTick(20_000)) + pl.CreatePool(barPath, wgnotPath, fee3000, common.TickMathGetSqrtRatioAtTick(60_000)) // NOT USED BY SMALL LIQ + // -10_000 0.367897 + // -20_000 0.135348 + // 0.367897 + 0.135348 = 0.503245 + // 0.503245 / 2 = 0.2516225 + // 1 WGNOT = 0.2516225 BAR + + // 2 HOPS + pl.CreatePool(wgnotPath, quxPath, fee100, common.TickMathGetSqrtRatioAtTick(0)) // 1:1 + pl.CreatePool(quxPath, fooPath, fee100, common.TickMathGetSqrtRatioAtTick(50_000)) + pl.CreatePool(quxPath, fooPath, fee500, common.TickMathGetSqrtRatioAtTick(60_000)) + pl.CreatePool(quxPath, fooPath, fee3000, common.TickMathGetSqrtRatioAtTick(100_000)) // NOT USED BY SMALL LIQ + // 50_000 148.376062 + // 60_000 403.307791 + // 148.376062 + 403.307791 = 551.683853 + // 551.683853 / 2 = 275.8419265 + // 1 WGNOT = 275.8419265 BAR + + // 3 HOPS + pl.CreatePool(wgnotPath, bazPath, fee100, common.TickMathGetSqrtRatioAtTick(6932)) // 1:2 + pl.CreatePool(bazPath, oblPath, fee100, common.TickMathGetSqrtRatioAtTick(6932)) // 1:2 + pl.CreatePool(oblPath, gnsPath, fee100, common.TickMathGetSqrtRatioAtTick(6932)) // 1:2 + // 1 GNOT = 8 GNS +} + +func TestPositionMint(t *testing.T) { + std.TestSetOrigCaller(test1) + + // wugnot prepare + std.TestSetOrigSend(std.Coins{{"ugnot", 100_000_000_000}}, nil) + testBanker := std.GetBanker(std.BankerTypeRealmIssue) + testBanker.RemoveCoin(std.GetOrigCaller(), "ugnot", 100_000_000_000) + + // Deposit(wrap) + std.TestSetPrevAddr(test1) + wugnot.Deposit() + + pn.Mint(barPath, wgnotPath, fee100, 8000, 12000, 100_000_000, 100_000_000, 0, 0, max_timeout) + pn.Mint(barPath, wgnotPath, fee500, 18000, 22000, 80_000_000, 80_000_000, 0, 0, max_timeout) + pn.Mint(barPath, wgnotPath, fee3000, 58020, 62040, 10_000_000, 10_000_000, 0, 0, max_timeout) + + pn.Mint(quxPath, fooPath, fee100, 48000, 52000, 100_000_000, 100_000_000, 0, 0, max_timeout) + pn.Mint(quxPath, fooPath, fee500, 58000, 62000, 80_000_000, 80_000_000, 0, 0, max_timeout) + pn.Mint(quxPath, fooPath, fee3000, 98040, 10020, 10_000_000, 10_000_000, 0, 0, max_timeout) + + // pn.Mint(fooPath, gnsPath, fee100, 48000, 52000, 100_000_000, 100_000_000, 0, 0, max_timeout) +} + +func TestApiGetRatiosFromBase(t *testing.T) { + std.TestSetOrigCaller(test1) + + ratios := ApiGetRatiosFromBase() + jsonStr := gjson.Parse(ratios) + + responseArr := gjson.Get(jsonStr.String(), "response").Array() + shouldEQ(t, len(responseArr), 7) + /* + {"token":"gno.land/r/demo/wugnot","ratio":79228162514264337593543950336} + {"token":"gno.land/r/demo/bar","ratio":19935653721785907863909200771} + {"token":"gno.land/r/demo/qux","ratio":79228162514264337593543950338} + {"token":"gno.land/r/demo/foo","ratio":21854449020437189859372345675086} + {"token":"gno.land/r/demo/baz","ratio":158459202898910110285447649633} + {"token":"gno.land/r/demo/obl","ratio":316924161643118367991168631863} + {"token":"gno.land/r/demo/gns","ratio":633859835185907382391729498087} + */ + + shouldEQ(t, responseArr[0].Get("token").String(), "gno.land/r/demo/wugnot") + shouldEQ(t, responseArr[0].Get("ratio").String(), "79228162514264337593543950336") + + shouldEQ(t, responseArr[1].Get("token").String(), "gno.land/r/demo/bar") + shouldEQ(t, responseArr[1].Get("ratio").String(), "19935653721785907863909200771") + + shouldEQ(t, responseArr[2].Get("token").String(), "gno.land/r/demo/qux") + shouldEQ(t, responseArr[2].Get("ratio").String(), "79228162514264337593543950338") + + shouldEQ(t, responseArr[3].Get("token").String(), "gno.land/r/demo/foo") + shouldEQ(t, responseArr[3].Get("ratio").String(), "21854449020437189859372345675086") + + shouldEQ(t, responseArr[4].Get("token").String(), "gno.land/r/demo/baz") + shouldEQ(t, responseArr[4].Get("ratio").String(), "158459202898910110285447649633") + + shouldEQ(t, responseArr[5].Get("token").String(), "gno.land/r/demo/obl") + shouldEQ(t, responseArr[5].Get("ratio").String(), "316924161643118367991168631863") + + shouldEQ(t, responseArr[6].Get("token").String(), "gno.land/r/demo/gns") + shouldEQ(t, responseArr[6].Get("ratio").String(), "633859835185907382391729498087") +} diff --git a/router/_TEST_router_swap_route_1route_1hop_out_range_test.gnoa b/router/_TEST_router_swap_route_1route_1hop_out_range_test.gnoa index b0224382..f7450cd1 100644 --- a/router/_TEST_router_swap_route_1route_1hop_out_range_test.gnoa +++ b/router/_TEST_router_swap_route_1route_1hop_out_range_test.gnoa @@ -32,7 +32,7 @@ func TestPositionMint(t *testing.T) { // Mint tokenId, liquidity, amount0, amount1 := pos.Mint(barPath, bazPath, fee500, int32(12000), int32(15000), bigint(100_000), bigint(100_000), 0, 0, max_timeout) shouldEQ(t, tokenId, uint64(1)) - shouldEQ(t, liquidity, bigint(1308150)) + shouldEQ(t, liquidity, bigint(1308151)) shouldEQ(t, amount0, bigint(100000)) // ONLY BAR shouldEQ(t, amount1, bigint(0)) // NO BAZ } diff --git a/router/_TEST_router_swap_route_1route_2hop_native_in_out_test.gnoa b/router/_TEST_router_swap_route_1route_2hop_native_in_out_test.gnoa index c24790f3..c99f049c 100644 --- a/router/_TEST_router_swap_route_1route_2hop_native_in_out_test.gnoa +++ b/router/_TEST_router_swap_route_1route_2hop_native_in_out_test.gnoa @@ -119,5 +119,5 @@ func TestDrySwapRouteGnotBarExactOut(t *testing.T) { "gno.land/r/demo/wugnot:gno.land/r/demo/qux:500*POOL*gno.land/r/demo/qux:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/bar:500", // strRouteArr "100", // quoteArr ) - shouldEQ(t, dryResult, bigint(1998)) + shouldEQ(t, dryResult, bigint(1977)) } diff --git a/router/_TEST_router_swap_route_2route_2hop_test.gno b/router/_TEST_router_swap_route_2route_2hop_test.gnoa similarity index 98% rename from router/_TEST_router_swap_route_2route_2hop_test.gno rename to router/_TEST_router_swap_route_2route_2hop_test.gnoa index da6f4f6e..e60b0134 100644 --- a/router/_TEST_router_swap_route_2route_2hop_test.gno +++ b/router/_TEST_router_swap_route_2route_2hop_test.gnoa @@ -140,7 +140,7 @@ func TestDrySwapRouteQuxBarExactOut(t *testing.T) { "30,70", // quoteArr ) - shouldEQ(t, dryResult, bigint(7292)) + shouldEQ(t, dryResult, bigint(7278)) } func TestwapRouteQuxBarExactOut(t *testing.T) { @@ -156,5 +156,5 @@ func TestwapRouteQuxBarExactOut(t *testing.T) { 99999, // tokenAmountLimit ) - shouldEQ(t, swapResult, bigint(7286)) + shouldEQ(t, swapResult, bigint(7277)) } diff --git a/router/_TEST_routes_find_swap_path_test.gnoa b/router/_TEST_routes_find_swap_path_test.gnoa new file mode 100644 index 00000000..a27d07f4 --- /dev/null +++ b/router/_TEST_routes_find_swap_path_test.gnoa @@ -0,0 +1,124 @@ +package router + +import ( + "std" + "testing" + + pl "gno.land/r/demo/pool" + pn "gno.land/r/demo/position" + + "gno.land/p/demo/common" + + "gno.land/r/demo/wugnot" +) + +func TestInitManual(t *testing.T) { + std.TestSetOrigCaller(test1) + pl.InitManual() + std.TestSkipHeights(1) +} + +func TestPoolCreatePool(t *testing.T) { + std.TestSetOrigCaller(test1) + + // 1 HOPS + pl.CreatePool(barPath, wgnotPath, fee100, common.TickMathGetSqrtRatioAtTick(10_000)) + pl.CreatePool(barPath, wgnotPath, fee500, common.TickMathGetSqrtRatioAtTick(20_000)) + pl.CreatePool(barPath, wgnotPath, fee3000, common.TickMathGetSqrtRatioAtTick(60_000)) // NOT USED BY SMALL LIQ + // -10_000 0.367897 + // -20_000 0.135348 + // 0.367897 + 0.135348 = 0.503245 + // 0.503245 / 2 = 0.2516225 + // 1 WGNOT = 0.2516225 BAR + + // 2 HOPS + pl.CreatePool(wgnotPath, quxPath, fee100, common.TickMathGetSqrtRatioAtTick(0)) // 1:1 + pl.CreatePool(quxPath, fooPath, fee100, common.TickMathGetSqrtRatioAtTick(50_000)) + pl.CreatePool(quxPath, fooPath, fee500, common.TickMathGetSqrtRatioAtTick(60_000)) + pl.CreatePool(quxPath, fooPath, fee3000, common.TickMathGetSqrtRatioAtTick(100_000)) // NOT USED BY SMALL LIQ + // 50_000 148.376062 + // 60_000 403.307791 + // 148.376062 + 403.307791 = 551.683853 + // 551.683853 / 2 = 275.8419265 + // 1 WGNOT = 275.8419265 BAR + + // 3 HOPS + pl.CreatePool(wgnotPath, bazPath, fee100, common.TickMathGetSqrtRatioAtTick(6932)) // 1:2 + pl.CreatePool(bazPath, oblPath, fee100, common.TickMathGetSqrtRatioAtTick(6932)) // 1:2 + pl.CreatePool(oblPath, gnsPath, fee100, common.TickMathGetSqrtRatioAtTick(6932)) // 1:2 + // 1 GNOT = 8 GNS +} + +func TestPositionMint(t *testing.T) { + std.TestSetOrigCaller(test1) + + // wugnot prepare + std.TestSetOrigSend(std.Coins{{"ugnot", 100_000_000_000}}, nil) + testBanker := std.GetBanker(std.BankerTypeRealmIssue) + testBanker.RemoveCoin(std.GetOrigCaller(), "ugnot", 100_000_000_000) + + // Deposit(wrap) + std.TestSetPrevAddr(test1) + wugnot.Deposit() + + pn.Mint(barPath, wgnotPath, fee100, 8000, 12000, 100_000_000, 100_000_000, 0, 0, max_timeout) + pn.Mint(barPath, wgnotPath, fee500, 18000, 22000, 80_000_000, 80_000_000, 0, 0, max_timeout) + pn.Mint(barPath, wgnotPath, fee3000, 58020, 62040, 10_000_000, 10_000_000, 0, 0, max_timeout) + + pn.Mint(quxPath, fooPath, fee100, 48000, 52000, 100_000_000, 100_000_000, 0, 0, max_timeout) + pn.Mint(quxPath, fooPath, fee500, 58000, 62000, 80_000_000, 80_000_000, 0, 0, max_timeout) + pn.Mint(quxPath, fooPath, fee3000, 98040, 10020, 10_000_000, 10_000_000, 0, 0, max_timeout) + + // pn.Mint(fooPath, gnsPath, fee100, 48000, 52000, 100_000_000, 100_000_000, 0, 0, max_timeout) +} + +func TestFindRoutes1(t *testing.T) { + std.TestSetOrigCaller(test1) + + pools := findCandidatePools() + + inputTokenPath := "gno.land/r/demo/wugnot" // FIXED + outputTokenPath := "gno.land/r/demo/bar" + maxHops := 3 + routes := computeAllRoutes( + inputTokenPath, + outputTokenPath, + maxHops, + pools, + ) + shouldEQ(t, len(routes), 2) +} + +func TestFindRoutes2(t *testing.T) { + std.TestSetOrigCaller(test1) + + pools := findCandidatePools() + + inputTokenPath := "gno.land/r/demo/wugnot" // FIXED + outputTokenPath := "gno.land/r/demo/foo" + maxHops := 3 + routes := computeAllRoutes( + inputTokenPath, + outputTokenPath, + maxHops, + pools, + ) + shouldEQ(t, len(routes), 2) +} + +func TestFindRoutes3(t *testing.T) { + std.TestSetOrigCaller(test1) + + pools := findCandidatePools() + + inputTokenPath := "gno.land/r/demo/wugnot" // FIXED + outputTokenPath := "gno.land/r/demo/gns" + maxHops := 3 + routes := computeAllRoutes( + inputTokenPath, + outputTokenPath, + maxHops, + pools, + ) + shouldEQ(t, len(routes), 1) +} diff --git a/router/comptue_routes.gno b/router/comptue_routes.gno new file mode 100644 index 00000000..ea122e64 --- /dev/null +++ b/router/comptue_routes.gno @@ -0,0 +1,218 @@ +package router + +import ( + "sort" + + pl "gno.land/r/demo/pool" +) + +type PoolWithMeta struct { + poolPath string + token0Path string + token1Path string + fee int + tokenPair string + liquidity bigint +} +type ByLiquidity []PoolWithMeta + +func (p ByLiquidity) Len() int { return len(p) } +func (p ByLiquidity) Swap(i, j int) { p[i], p[j] = p[j], p[i] } +func (p ByLiquidity) Less(i, j int) bool { return p[i].liquidity > p[j].liquidity } + +type BuildRoute struct { + route []PoolWithMeta + tokenIn string + tokenOut string +} + +func computeAllRoutes( + inputTokenPath string, + outputTokenPath string, + maxHops int, + pools []PoolWithMeta, +) []BuildRoute { + + routes := _computeAllRoutes( + inputTokenPath, + outputTokenPath, + []BuildRoute{}, + pools, + maxHops, + ) + + return routes +} + +func _computeAllRoutes( + inputTokenPath string, + outputTokenPath string, + buildRoute []BuildRoute, // BuildRoute + pools []PoolWithMeta, + maxHops int, +) []BuildRoute { + poolUsed := make([]bool, len(pools)) + + routes := []BuildRoute{} + + computeRoutes( + inputTokenPath, + outputTokenPath, + []PoolWithMeta{}, // currentRoute + poolUsed, + []string{inputTokenPath}, // tokenVisited + "", // _previousTokenOut + // + maxHops, + pools, + // + &routes, + ) + + return routes +} + +func computeRoutes( + inputTokenPath string, + outputTokenPath string, + currentRoute []PoolWithMeta, + poolsUsed []bool, + tokenVisited []string, // r3v4_xxx: could be map + _previousTokenOut string, + // + maxHops int, + pools []PoolWithMeta, + routes *[]BuildRoute, +) *[]BuildRoute { + + routeLen := len(currentRoute) + + if routeLen > maxHops { + return routes + } + + if (routeLen > 0) && (currentRoute[routeLen-1].hasToken(outputTokenPath)) { + buildRoute := BuildRoute{} + buildRoute.route = append([]PoolWithMeta{}, currentRoute...) + buildRoute.tokenIn = inputTokenPath + buildRoute.tokenOut = outputTokenPath + *routes = append(*routes, buildRoute) + return routes + } + + for i, pool := range pools { + if poolsUsed[i] { + continue + } + + curPool := pools[i] + + var previousTokenOut string + if _previousTokenOut == "" { // first iteration + previousTokenOut = inputTokenPath + } else { + previousTokenOut = _previousTokenOut + } + + if !curPool.hasToken(previousTokenOut) { + continue + } + + var currentTokenOut string + if curPool.token0Path == previousTokenOut { + currentTokenOut = curPool.token1Path + } else { + currentTokenOut = curPool.token0Path + } + + if isStringInStringArr(tokenVisited, currentTokenOut) { + continue + } + + tokenVisited = append(tokenVisited, currentTokenOut) + currentRoute = append(currentRoute, curPool) + poolsUsed[i] = true + + computeRoutes( + inputTokenPath, + outputTokenPath, + currentRoute, + poolsUsed, + tokenVisited, + currentTokenOut, + // + maxHops, + pools, + // + routes, + ) + + poolsUsed[i] = false + currentRoute = currentRoute[:len(currentRoute)-1] + tokenVisited = removeStringFromStringArr(tokenVisited, currentTokenOut) + } + + return routes +} + +func (pool PoolWithMeta) hasToken(token string) bool { + return pool.token0Path == token || pool.token1Path == token +} + +func findCandidatePools() []PoolWithMeta { + + poolList := pl.PoolGetPoolList() + + poolWithMetas := []PoolWithMeta{} + for _, poolPath := range poolList { + token0Path, token1Path, pFee := poolPathWithFeeDivide(poolPath) + + pool := pl.GetPoolFromPoolPath(poolPath) + liquidity := pool.PoolGetLiquidity() + poolWithMetas = append(poolWithMetas, PoolWithMeta{ + poolPath, + token0Path, + token1Path, + pFee, + token0Path + ":" + token1Path, + liquidity, + }) + } + + groupedPools := groupPoolsByTokenPair(poolWithMetas) + top2ByGroup := selectTop2ByGroup(groupedPools) + + candidatePools := []PoolWithMeta{} + for _, pools := range top2ByGroup { + candidatePools = append(candidatePools, pools...) + } + + return candidatePools +} + +// group pools by tokenPair +func groupPoolsByTokenPair(pools []PoolWithMeta) map[string][]PoolWithMeta { + groupedPools := make(map[string][]PoolWithMeta) + + for _, pool := range pools { + groupedPools[pool.tokenPair] = append(groupedPools[pool.tokenPair], pool) + } + + return groupedPools +} + +// select the top 2 liquidity values per each group +func selectTop2ByGroup(groupedPools map[string][]PoolWithMeta) map[string][]PoolWithMeta { + top2ByGroup := make(map[string][]PoolWithMeta) + + for tokenPair, pools := range groupedPools { + // Use sort.Sort with ByLiquidity interface + sort.Sort(ByLiquidity(pools)) + + // Select the top 2 liquidity values + top2 := pools[:min(2, len(pools))] + top2ByGroup[tokenPair] = top2 + } + + return top2ByGroup +} diff --git a/router/find_path.gno b/router/find_path.gno deleted file mode 100644 index 17f20a11..00000000 --- a/router/find_path.gno +++ /dev/null @@ -1,107 +0,0 @@ -package router - -import ( - "strconv" - "strings" - - p "gno.land/r/demo/pool" - - "gno.land/p/demo/ufmt" -) - -func findSwapPaths( - inputTokenPath string, - outputTokenPath string, - maxHops int, -) string { - tokenPairs := TokenPairs{} - poolList := p.PoolGetPoolList() - - for i, poolPath := range poolList { - token0Path, token1Path, pFee := poolPathWithFeeDivide(poolPath) - - { - k := token0Path - v := token1Path + ":" + strconv.Itoa(pFee) - - tokenPairs[k] = append(tokenPairs[k], v) - } - - { - k := token1Path - v := token0Path + ":" + strconv.Itoa(pFee) - - tokenPairs[k] = append(tokenPairs[k], v) - } - } - - swapPaths := getSwapPaths(tokenPairs, inputTokenPath, outputTokenPath, maxHops) - return swapPaths -} - -func getSwapPaths( - tokenPairs TokenPairs, - inputTokenPath string, - outputTokenPath string, - maxHops int, -) string { - - swapPaths := "" - - // check if there is path that starts with input - require(len(tokenPairs[inputTokenPath]) != 0, ufmt.Sprintf("[ROUTER] find_path.gno__getSwapPaths() || len(tokenPairs[inputTokenPath]) == 0, inputTokenPath: %s", inputTokenPath)) - - // find direct path - for _, output := range tokenPairs[inputTokenPath] { - if strings.HasPrefix(output, outputTokenPath) { - outputPath, outputFee := singlePoolPathWithFeeDivide(output) - directPath := inputTokenPath + "," + outputFee + "," + outputPath - swapPaths += directPath + "_FIN_" - - tokenPairs[inputTokenPath] = removeItemFromStringArray(tokenPairs[inputTokenPath], output) - } - } - - firstToken := "" - for i := 1; i <= maxHops; i++ { - findPath(tokenPairs, inputTokenPath, outputTokenPath, "", i, &swapPaths, &firstToken) - } - - return swapPaths -} - -func findPath( - tokenPairs TokenPairs, - currentTokenPath string, - outputTokenPath string, - currentPath string, - remainingHops int, - swapPaths *string, - firstToken *string, -) { - if *firstToken == "" { - *firstToken = currentTokenPath - } - - if remainingHops == 0 { - if strings.HasPrefix(currentTokenPath, outputTokenPath) { - *swapPaths += (*firstToken + "," + currentPath) + "_FIN_" - } - return - } - - for _, next := range tokenPairs[currentTokenPath] { - nextPath, nextFee := singlePoolPathWithFeeDivide(next) - newPath := currentPath - if currentPath != "" { - newPath += "," - } - newPath += nextFee + "," + nextPath - // remove found path - tokenPairs[currentTokenPath] = removeItemFromStringArray(tokenPairs[currentTokenPath], newPath) - // remove opposite path - tokenPairs[nextPath] = removeItemFromStringArray(tokenPairs[nextPath], (currentTokenPath + ":" + nextFee)) - - findPath(tokenPairs, nextPath, outputTokenPath, newPath, remainingHops-1, swapPaths, firstToken) - } -} diff --git a/router/gno.mod b/router/gno.mod index 4c7de9c6..24e3aa05 100644 --- a/router/gno.mod +++ b/router/gno.mod @@ -1,19 +1 @@ -module gno.land/r/demo/router - -require ( - gno.land/p/demo/common v0.0.0-latest - gno.land/p/demo/ufmt v0.0.0-latest - gno.land/r/demo/bar v0.0.0-latest - gno.land/r/demo/baz v0.0.0-latest - gno.land/r/demo/consts v0.0.0-latest - gno.land/r/demo/foo v0.0.0-latest - gno.land/r/demo/fred v0.0.0-latest - gno.land/r/demo/gns v0.0.0-latest - gno.land/r/demo/obl v0.0.0-latest - gno.land/r/demo/pool v0.0.0-latest - gno.land/r/demo/position v0.0.0-latest - gno.land/r/demo/qux v0.0.0-latest - gno.land/r/demo/thud v0.0.0-latest - gno.land/r/demo/users v0.0.0-latest - gno.land/r/demo/wugnot v0.0.0-latest -) +module gno.land/r/demo/router \ No newline at end of file diff --git a/router/gno_helper.gno b/router/gno_helper.gno index 4547c19d..c9a8296d 100644 --- a/router/gno_helper.gno +++ b/router/gno_helper.gno @@ -3,6 +3,8 @@ package router import ( "std" "time" + + "gno.land/r/demo/consts" ) func GetHeight() int64 { @@ -14,5 +16,5 @@ func GetTimestamp() int64 { } func GetOrigPkgAddr() std.Address { - return std.DerivePkgAddr("gno.land/r/demo/router") + return consts.ROUTER_ADDR } diff --git a/router/router_register.gno b/router/router_register.gno index 12f1e4c1..b3db724c 100644 --- a/router/router_register.gno +++ b/router/router_register.gno @@ -3,9 +3,8 @@ package router import ( "std" - "gno.land/r/demo/users" - "gno.land/r/demo/consts" + "gno.land/r/demo/users" ) var registered = []GRC20Pair{} diff --git a/router/swap_inner.gno b/router/swap_inner.gno index e6d303f6..349498e5 100644 --- a/router/swap_inner.gno +++ b/router/swap_inner.gno @@ -3,7 +3,7 @@ package router import ( "std" - p "gno.land/r/demo/pool" + pl "gno.land/r/demo/pool" "gno.land/r/demo/consts" ) @@ -30,7 +30,7 @@ func _swap( approveByRegisterCall(data.tokenIn, consts.POOL_ADDR, uint64(toApproveAmount)) approveByRegisterCall(data.tokenOut, consts.POOL_ADDR, uint64(toApproveAmount)) - amount0, amount1 := p.Swap( + amount0, amount1 := pl.Swap( data.tokenIn, data.tokenOut, data.fee, @@ -63,7 +63,7 @@ func _swapDry( } // check possible - amount0, amount1, ok := p.DrySwap( + amount0, amount1, ok := pl.DrySwap( data.tokenIn, data.tokenOut, data.fee, diff --git a/router/swap_multi.gno b/router/swap_multi.gno index 620619a7..5ad6a614 100644 --- a/router/swap_multi.gno +++ b/router/swap_multi.gno @@ -2,6 +2,8 @@ package router import ( "std" + + "gno.land/r/demo/consts" ) func multiSwap(params SwapParams, currentPoolIndex, numPools int, swapPath string) (firstAmountIn, lastAmountOut bigint) { @@ -12,7 +14,7 @@ func multiSwap(params SwapParams, currentPoolIndex, numPools int, swapPath strin currentPoolIndex++ if currentPoolIndex < numPools { - recipient = std.DerivePkgAddr("gno.land/r/demo/router") + recipient = consts.ROUTER_ADDR } else { recipient = params.recipient // user ~= std.GetOrigCaller() } @@ -34,7 +36,7 @@ func multiSwap(params SwapParams, currentPoolIndex, numPools int, swapPath strin } if currentPoolIndex < numPools { - payer = std.DerivePkgAddr("gno.land/r/demo/router") + payer = consts.ROUTER_ADDR nextInput, nextOutput, nextFee := getDataForMultiPath(swapPath, currentPoolIndex) params.tokenIn = nextInput @@ -93,7 +95,7 @@ func multiSwapNegative(params SwapParams, numPools int, swapPath string) (fisrtA if currentPoolIndex == 0 { recipient = std.GetOrigCaller() // params.recipient // user ~= std.GetOrigCaller() } else { - recipient = std.DerivePkgAddr("gno.land/r/demo/router") + recipient = consts.ROUTER_ADDR } amountIn, amountOut := _swap( @@ -116,7 +118,7 @@ func multiSwapNegative(params SwapParams, numPools int, swapPath string) (fisrtA if currentPoolIndex == 0 { return fisrtAmountIn, amountOut } else { - payer = std.DerivePkgAddr("gno.land/r/demo/router") + payer = consts.ROUTER_ADDR swapInfo[currentPoolIndex-1].amountSpecified = amountOut } } @@ -130,7 +132,7 @@ func multiSwapDry(params SwapParams, currentPoolIndex, numPool int, swapPath str currentPoolIndex++ if currentPoolIndex < numPool { - recipient = std.DerivePkgAddr("gno.land/r/demo/router") + recipient = consts.ROUTER_ADDR } else { recipient = params.recipient // user ~= std.GetOrigCaller() } @@ -152,7 +154,7 @@ func multiSwapDry(params SwapParams, currentPoolIndex, numPool int, swapPath str } if currentPoolIndex < numPool { - payer = std.DerivePkgAddr("gno.land/r/demo/router") + payer = consts.ROUTER_ADDR nextInput, nextOutput, nextFee := getDataForMultiPath(swapPath, currentPoolIndex) params.tokenIn = nextInput @@ -168,7 +170,7 @@ func multiSwapDry(params SwapParams, currentPoolIndex, numPool int, swapPath str } func multiSwapNegativeDry(params SwapParams, currentPoolIndex int, swapPath string) (firstAmountIn, lastAmountOut bigint) { - payer := std.DerivePkgAddr("gno.land/r/demo/router") + payer := consts.ROUTER_ADDR numPools := currentPoolIndex for { @@ -177,7 +179,7 @@ func multiSwapNegativeDry(params SwapParams, currentPoolIndex int, swapPath stri if currentPoolIndex == numPools-1 { recipient = params.recipient } else { - recipient = std.DerivePkgAddr("gno.land/r/demo/router") + recipient = consts.ROUTER_ADDR } amountIn, amountOut := _swapDry( diff --git a/router/type.gno b/router/type.gno index 1fdff15c..5cb85551 100644 --- a/router/type.gno +++ b/router/type.gno @@ -3,17 +3,17 @@ package router import "std" // SWAP TYPE -type SwapType string // r3v4_xxx: private? +type SwapType string const ( - ExactIn SwapType = "EXACT_IN" // r3v4_xxx: private? - ExactOut SwapType = "EXACT_OUT" // r3v4_xxx: private? + ExactIn SwapType = "EXACT_IN" + ExactOut SwapType = "EXACT_OUT" ) // PRICE -type SwapPaths map[int]string // r3v4_xxx: private? -type TokenPairs map[string][]string // r3v4_xxx: private? -type QuoterTarget struct { // r3v4_xxx: private? +type SwapPaths map[int]string +type TokenPairs map[string][]string +type QuoterTarget struct { pct int pctAmount bigint targetPath string @@ -21,7 +21,7 @@ type QuoterTarget struct { // r3v4_xxx: private? } // SINGLE SWAP -type SingleSwapParams struct { // r3v4_xxx: private? +type SingleSwapParams struct { tokenIn string tokenOut string fee uint16 @@ -29,7 +29,7 @@ type SingleSwapParams struct { // r3v4_xxx: private? } // MUTLI SWAP -type SwapParams struct { // r3v4_xxx: private? +type SwapParams struct { tokenIn string tokenOut string fee uint16 @@ -38,7 +38,7 @@ type SwapParams struct { // r3v4_xxx: private? } // SWAP DATA -type SwapCallbackData struct { // r3v4_xxx: private? +type SwapCallbackData struct { tokenIn string tokenOut string fee uint16 diff --git a/router/util.gno b/router/util.gno index 6f7937c8..3366be4e 100644 --- a/router/util.gno +++ b/router/util.gno @@ -38,6 +38,24 @@ func getDataForMultiPath(possiblePath string, poolIdx int) (token0, token1 strin return token0, token1, fee } +func isStringInStringArr(arr []string, str string) bool { + for _, a := range arr { + if a == str { + return true + } + } + return false +} + +func removeStringFromStringArr(arr []string, str string) []string { + for i, a := range arr { + if a == str { + return append(arr[:i], arr[i+1:]...) + } + } + return arr +} + func a2u(addr std.Address) users.AddressOrName { return users.AddressOrName(addr) } @@ -56,6 +74,13 @@ func abs(x bigint) uint64 { return uint64(x) } +func min(a, b int) int { + if a < b { + return a + } + return b +} + func absBigint(x bigint) bigint { if x < 0 { return -x diff --git a/staker/utils.gno b/staker/utils.gno index b66cc74a..2673572d 100644 --- a/staker/utils.gno +++ b/staker/utils.gno @@ -29,12 +29,6 @@ func poolKeyDivide(poolKey string) string { return ufmt.Sprintf("%s:%s:%s", pToken1, pToken0, fee) } -func require(condition bool, message string) { - if !condition { - panic(message) - } -} - func a2u(addr std.Address) users.AddressOrName { return users.AddressOrName(addr) } @@ -79,3 +73,15 @@ func requireUnsigned(x bigint, msg string) { panic(msg) } } + +func require(condition bool, message string) { + if !condition { + panic(message) + } +} + +func requireExist(exist bool, msg string) { + if !exist { + panic(msg) + } +}