Skip to content

Commit

Permalink
More Torus tests and error checking
Browse files Browse the repository at this point in the history
  • Loading branch information
mikera committed Jul 17, 2024
1 parent 22fd9d4 commit 884ce48
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 11 deletions.
21 changes: 14 additions & 7 deletions convex-core/src/main/cvx/torus/exchange.cvx
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
[amount]

(let [amount (int amount)
_ (cond (< amount 0) (fail :ARGUMENT "Cannot buy negative coin quantity"))
required-tokens (or (buy-cvx-quote amount)
(fail :LIQUIDITY "Pool cannot supply this amount of CVX"))]
(asset/accept *caller*
Expand All @@ -115,7 +116,10 @@
^{:callable true}
[amount]
;; Security: check pool can provide.
(when-not (<= 0 amount *balance*) (return nil))
(cond
(< amount 0) (return nil)
(>= amount *balance*) (return nil))

(let [;; Computes pool and fees/
cvx-balance *balance*
pool (* (double token-balance) cvx-balance)
Expand All @@ -128,14 +132,14 @@
amount))
token-balance))))))


(defn buy-tokens

^{:callable true}

[amount]

(let [amount (int amount)
_ (cond (< amount 0) (fail :ARGUMENT "Cannot buy negative token quantity"))
required-cvx (or (buy-tokens-quote amount)
(fail :LIQUIDITY "Pool cannot supply this amount of tokens"))]
(core/accept required-cvx)
Expand All @@ -157,7 +161,9 @@
[amount]

;; Security: check pool can provide.
(when-not (<= 0 amount token-balance) (return nil))
(cond
(< amount 0) (return nil)
(>= amount token-balance) (return nil))

(let [;; Computes pool and fees.
cvx-balance *balance*
Expand Down Expand Up @@ -199,7 +205,7 @@

(let [amount (int amount)
gained-tokens (or (sell-cvx-quote amount)
(fail "Cannot sell this amount into pool"))]
(fail :ARGUMENT "Cannot sell negative coin amount"))]
(core/accept amount)
(def token-balance
(- token-balance
Expand All @@ -220,7 +226,8 @@

;; Security: check amount is positive.
;;
(when (<= amount 0) (return nil))
(cond (< amount 0) (return nil))

(let [;; Computes pool and fees.
cvx-balance *balance*
pool (* (double token-balance)
Expand All @@ -244,7 +251,7 @@

(let [amount (int amount)
gained-cvx (or (sell-tokens-quote amount)
(fail "Cannot sell this amount into pool"))]
(fail :ARGUMENT "Cannot sell this negative token amount"))]
(asset/accept *caller*
[token
amount])
Expand All @@ -265,7 +272,7 @@
[amount]

;; Security: check amount is positive.
(when-not (<= 0 amount) (return nil))
(cond (< amount 0) (return nil))

(let [;; Computes pool and fees.
cvx-balance *balance*
Expand Down
5 changes: 5 additions & 0 deletions convex-core/src/main/java/convex/core/ErrorCodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -213,5 +213,10 @@ public class ErrorCodes {
*/
public static final Keyword SYNTAX = Keyword.create("SYNTAX");

/**
* Error code indicating insufficient liquidity in state for a Torus or other trade
*/
public static final Keyword LIQUIDITY = Keyword.create("LIQUIDITY");


}
54 changes: 50 additions & 4 deletions convex-core/src/test/java/convex/actors/TorusTest.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package convex.actors;

import static convex.test.Assertions.assertCVMEquals;
import static convex.test.Assertions.assertError;
import static convex.test.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
Expand All @@ -10,6 +9,7 @@

import org.junit.jupiter.api.Test;

import convex.core.ErrorCodes;
import convex.core.data.AVector;
import convex.core.data.Address;
import convex.core.data.prim.CVMDouble;
Expand Down Expand Up @@ -56,23 +56,69 @@ public class TorusTest extends ACVMTest {
long STK=1000000;
Context baseContext=context();
baseContext=exec(baseContext,"(torus/add-liquidity USD "+STK+" "+STK+")");
long USDBAL = evalL(baseContext,"(fun/balance USD)");
assertEquals(USDBAL,SUPPLY-STK);

{ // Buy 100 USD
Context ctx=baseContext;
ctx=exec(ctx,"(torus/buy-tokens USD 100)");
assertEquals(101L,RT.ensureLong(ctx.getResult()).longValue()); ;; // price should be 101
assertEquals(1000000000-STK+100,evalL(ctx,"(fun/balance USD)")); // should have gained 100 USD
assertEquals(USDBAL+100,evalL(ctx,"(fun/balance USD)")); // should have gained 100 USD
assertEquals(STK,evalL(ctx,"(fun/balance USDM)")); // market shares unchanged
assertTrue(evalB(ctx,"(< 1.0 (torus/price USD))")); // price has increased
}

{ // Buy whole pool
Context ctx=baseContext;
ctx=step(ctx,"(torus/buy-tokens USD "+STK+")");
assertEquals(ErrorCodes.LIQUIDITY,ctx.getErrorCode());
}

{ // Buy 0 USD
Context ctx=baseContext;
ctx=exec(ctx,"(torus/buy-tokens USD 0)");
assertEquals(0L,RT.ensureLong(ctx.getResult()).longValue()); ;; // price should be 0
assertEquals(1000000000-STK,evalL(ctx,"(fun/balance USD)")); // should have gained 100 USD
assertEquals(USDBAL,evalL(ctx,"(fun/balance USD)")); // no balance change
assertEquals(STK,evalL(ctx,"(fun/balance USDM)")); // market shares unchanged
assertTrue(evalB(ctx,"(= 1.0 (torus/price USD))")); // price should be unchanged
}

{ // Buy -100 USD
Context ctx=baseContext;
ctx=step(ctx,"(torus/buy-tokens USD -100)");
assertArgumentError(ctx);
}

{ // Sell 100 USD
Context ctx=baseContext;
ctx=exec(ctx,"(torus/sell-tokens USD 100)");
assertEquals(99L,RT.ensureLong(ctx.getResult()).longValue()); ;; // price should be 99
assertEquals(USDBAL-100,evalL(ctx,"(fun/balance USD)")); // should have gained 100 USD
assertEquals(STK,evalL(ctx,"(fun/balance USDM)")); // market shares unchanged
assertTrue(evalB(ctx,"(> 1.0 (torus/price USD))")); // price has decreased
}

{ // Sell whole USD holding
Context ctx=baseContext;
ctx=step(ctx,"(torus/sell-tokens USD (fun/balance USD))");
assertEquals(0,evalL(ctx,"(fun/balance USD)")); // should have no USD left
}

{ // Sell 0 USD
Context ctx=baseContext;
ctx=exec(ctx,"(torus/sell-tokens USD 0)");
assertEquals(0L,RT.ensureLong(ctx.getResult()).longValue()); ;; // price should be 0
assertEquals(USDBAL,evalL(ctx,"(fun/balance USD)")); // no balance change
assertEquals(STK,evalL(ctx,"(fun/balance USDM)")); // market shares unchanged
assertTrue(evalB(ctx,"(= 1.0 (torus/price USD))")); // price should be unchanged
}

{ // Sell -100 USD
Context ctx=baseContext;
ctx=step(ctx,"(torus/sell-tokens USD -100)");
assertArgumentError(ctx);
}

}

@Test public void testMissingMarket() {
Expand Down

0 comments on commit 884ce48

Please sign in to comment.