From 35c6dcdebc19e08606e872accdbe6101d4f458f7 Mon Sep 17 00:00:00 2001 From: Zishan Date: Sun, 3 Dec 2023 11:49:31 +0530 Subject: [PATCH] feat(test): unit tests --- contracts/hello-world.clar | 6 ++ contracts/keys.clar | 43 ++++++++-- history.txt | 17 ++++ tests/fake.test.ts | 7 -- tests/keys.test.ts | 166 +++++++++++++++++++++++++++++++++++-- 5 files changed, 218 insertions(+), 21 deletions(-) delete mode 100644 tests/fake.test.ts diff --git a/contracts/hello-world.clar b/contracts/hello-world.clar index 1625d08..9e98ba6 100644 --- a/contracts/hello-world.clar +++ b/contracts/hello-world.clar @@ -21,9 +21,15 @@ ;; public functions ;; +(define-public (pay (recipient principal)) +(stx-transfer? u0 tx-sender recipient) +) ;; read only functions ;; +(define-read-only (get-price (supply uint) (amount uint)) +(/ (* (* (+ (- amount u1) supply) (+ supply amount)) (+ (* u2 (+ (- amount u1) supply )) u1)) u6) +) ;; private functions ;; diff --git a/contracts/keys.clar b/contracts/keys.clar index e898ea6..932fe57 100644 --- a/contracts/keys.clar +++ b/contracts/keys.clar @@ -116,6 +116,7 @@ (asserts! (or (> supply u0) (is-eq tx-sender subject)) err-first-buy) (asserts! (> (stx-get-balance tx-sender) (+ price protocolFee subjectFee)) err-insufficient-payment) ;; Retain base amount in contract itself + (print {supply: supply, price:price, protocolFee:protocolFee, subjectFee:subjectFee}) (try! (stx-transfer? price tx-sender (as-contract tx-sender))) ;; Send protocol fee to protocol contract (try! (stx-transfer? protocolFee tx-sender (var-get protocolFeeDestination))) @@ -184,14 +185,29 @@ ;; read only functions ;; +;; (define-read-only (get-price (supply uint) (amount uint)) +;; (let +;; ( +;; (base-price u10) +;; (price-change-factor u100) +;; (adjusted-supply (+ supply amount)) +;; ) +;; (+ base-price (* amount (/ (* adjusted-supply adjusted-supply) price-change-factor))) +;; ) +;; ) (define-read-only (get-price (supply uint) (amount uint)) - (let + (let ( - (base-price u10) - (price-change-factor u100) - (adjusted-supply (+ supply amount)) + (sum1 (if (is-eq supply u0) + u0 + (/ (* (* (- supply u1) supply) (+ (* u2 (- supply u1)) u1)) u6))) + (sum2 (if (and (is-eq supply u0) (is-eq amount u1)) + u0 + (/ (* (* (+ (- supply u1) amount) (+ supply amount)) (+ (* u2 (+ (- supply u1) amount )) u1)) u6))) + (summation (- sum2 sum1)) ) - (+ base-price (* amount (/ (* adjusted-supply adjusted-supply) price-change-factor))) + (/ (* summation u1000000000000000000) u16000) ;; equivalent to 'summation * 1 ether / 16000' in Solidity + ) ) @@ -253,6 +269,23 @@ ) ) +;; helper functions +(define-read-only (get-owner) + (ok contract-owner) +) + +(define-read-only (get-protocol-fee-destination) + (ok (var-get protocolFeeDestination)) +) + +(define-read-only (get-protocol-fee-percent) + (ok (var-get protocolFeePercent)) +) + +(define-read-only (get-subject-fee-percent) + (ok (var-get subjectFeePercent)) +) + ;; private functions ;; diff --git a/history.txt b/history.txt index d77f3be..eee6efc 100644 --- a/history.txt +++ b/history.txt @@ -1,2 +1,19 @@ #V2 (contract-call? .keys set-protocol-fee-percent u5) +::help +::set_tx_sender ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM +(contract-call? .keys set-protocol-fee-destination ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5) +(contract-call? .keys set-protocol-fee-destination 'ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5) +::set_tx_sender ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG +(contract-call? .keys get-protocol-fee-destination) +(contract-call? .keys get-protocol-fee-destination tx-sender) +(contract-call? .keys get-protocol-fee-destination) +::set_tx_sender ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM +(contract-call? .keys get-protocol-fee-destination) +::functions +::set_tx_sender ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG +(contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.keys get-protocol-fee-destination) +(contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.keys get-protocol-fee-destination tx-sender) +(contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.keys get-protocol-destination tx-sender) +(contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.keys get-protocol-destination) +(contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.keys get-owner) diff --git a/tests/fake.test.ts b/tests/fake.test.ts deleted file mode 100644 index cc66655..0000000 --- a/tests/fake.test.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { describe, expect, it } from 'vitest'; - -describe('some fake test', () => { - it('should succeed', () => { - expect(true).toBeTruthy(); - }); -}); diff --git a/tests/keys.test.ts b/tests/keys.test.ts index 4202a3f..951380c 100644 --- a/tests/keys.test.ts +++ b/tests/keys.test.ts @@ -1,23 +1,171 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ import { Cl } from '@stacks/transactions'; import { describe, expect, it } from 'vitest'; import { initSimnet } from '@hirosystems/clarinet-sdk'; const simnet = await initSimnet(); const accounts = simnet.getAccounts(); -// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -const address1 = accounts.get('wallet_1')!; +const deployer = accounts.get('deployer')!; +const protocolFessDestination = accounts.get('wallet_1')!; +const address2 = accounts.get('wallet_2')!; +const address3 = accounts.get('wallet_3')!; -describe('test `get-price` public function', () => { - it('should get price of key', () => { +describe('Should initialise keys contract', () => { + it('only contract owner can set protocol fee destination', () => { + const setProtocolFeeDestination = simnet.callPublicFn( + 'keys', + 'set-protocol-fee-destination', + [Cl.standardPrincipal(protocolFessDestination)], + address2 + ); + + //@ts-ignore + expect(setProtocolFeeDestination.result).toBeErr(Cl.uint(401)); + }); + + it('should set protocol fee destination', () => { + const setProtocolFeeDestination = simnet.callPublicFn( + 'keys', + 'set-protocol-fee-destination', + [Cl.standardPrincipal(protocolFessDestination)], + deployer + ); + + //@ts-ignore + expect(setProtocolFeeDestination.result).toBeOk(Cl.bool(true)); + + const getProtocolDestinationResponse = simnet.callReadOnlyFn( + 'keys', + 'get-protocol-fee-destination', + [], + address2 + ); + + //@ts-ignore + expect(getProtocolDestinationResponse.result).toBeOk( + Cl.standardPrincipal(protocolFessDestination) + ); + }); + + it('should set protocol fee percent', () => { + const setProtocolFeePercent = simnet.callPublicFn( + 'keys', + 'set-protocol-fee-percent', + [Cl.uint(10)], + deployer + ); + + //@ts-ignore + expect(setProtocolFeePercent.result).toBeOk(Cl.bool(true)); + + const getProtocolFeePercentResponse = simnet.callReadOnlyFn( + 'keys', + 'get-protocol-fee-percent', + [], + address2 + ); + + //@ts-ignore + expect(getProtocolFeePercentResponse.result).toBeOk(Cl.uint(10)); + }); + + it('should set subject fee percent', () => { + const setSubjectFeePercent = simnet.callPublicFn( + 'keys', + 'set-subject-fee-percent', + [Cl.uint(10)], + deployer + ); + + //@ts-ignore + expect(setSubjectFeePercent.result).toBeOk(Cl.bool(true)); + + const getSubjectFeeResponse = simnet.callReadOnlyFn( + 'keys', + 'get-subject-fee-percent', + [], + address2 + ); + + //@ts-ignore + expect(getSubjectFeeResponse.result).toBeOk(Cl.uint(10)); + }); +}); + +describe('Core trade functionality', () => { + it('should get price for supply 1 and amount 2', () => { + const getPriceResponse = simnet.callReadOnlyFn( + 'keys', + 'get-price', + [Cl.uint(1), Cl.uint(2)], + address2 + ); + + console.log(Cl.prettyPrint(getPriceResponse.result)); + //@ts-ignore + expect(getPriceResponse.result).toBeUint(312500000000000); + }); + + it('should get price for supply 2 and amount 6', () => { + const getPriceResponse = simnet.callReadOnlyFn( + 'keys', + 'get-price', + [Cl.uint(2), Cl.uint(6)], + address2 + ); + + console.log(Cl.prettyPrint(getPriceResponse.result)); + //@ts-ignore + expect(getPriceResponse.result).toBeUint(8687500000000000); + }); + + it('should get price for supply 0 and amount 1', () => { const getPriceResponse = simnet.callReadOnlyFn( 'keys', 'get-price', - [Cl.uint(0), Cl.uint(100)], - address1 + [Cl.uint(0), Cl.uint(1)], + address2 + ); + + console.log(Cl.prettyPrint(getPriceResponse.result)); + //@ts-ignore + expect(getPriceResponse.result).toBeUint(0); + }); + + it('test Tx', () => { + const txResponse = simnet.callPublicFn( + 'hello-world', + 'pay', + [Cl.standardPrincipal(address3)], + address2 + ); + + console.log(Cl.prettyPrint(txResponse.result)); + // //@ts-ignore + // expect(txResponse.result).toBeOk(Cl.bool(true)); + }); + + it('should not allow non subject to buy first share', () => { + const buyNonSubjectShareResponse = simnet.callPublicFn( + 'keys', + 'buy-keys', + [Cl.standardPrincipal(address3), Cl.uint(1)], + address2 + ); + //@ts-ignore + expect(buyNonSubjectShareResponse.result).toBeErr(Cl.uint(500)); + }); + + it('should allow subject to buy first share', () => { + const buySubjectShareResponse = simnet.callPublicFn( + 'keys', + 'buy-keys', + [Cl.standardPrincipal(address2), Cl.uint(1)], + address2 ); - console.log(Cl.prettyPrint(getPriceResponse.result)); // u10010 - // eslint-disable-next-line @typescript-eslint/ban-ts-comment + console.log(Cl.prettyPrint(buySubjectShareResponse.result)); //@ts-ignore - expect(getPriceResponse.result).toBeUint(10010); + expect(buySubjectShareResponse.result).toBeOk(Cl.bool(true)); }); });