From 08c0b3fc0789cb3967f9ee57315d4ace199da9fb Mon Sep 17 00:00:00 2001 From: 0xbigz <83473873+0xbigz@users.noreply.github.com> Date: Thu, 11 Jan 2024 00:20:31 -0500 Subject: [PATCH 1/3] bigz/typescript-anchor-bankrun (wip) --- package.json | 4 +- test-scripts/single-anchor-test.sh | 2 +- tests/simTest1.ts | 198 +++++++++++++++++++++++++++++ yarn.lock | 44 +++++++ 4 files changed, 246 insertions(+), 2 deletions(-) create mode 100644 tests/simTest1.ts diff --git a/package.json b/package.json index b6fe41f6d..ee97de39d 100644 --- a/package.json +++ b/package.json @@ -25,9 +25,11 @@ }, "dependencies": { "@ellipsis-labs/phoenix-sdk": "^1.4.2", + "anchor-bankrun": "^0.3.0", "chai-bn": "^0.2.2", "csvtojson": "^2.0.10", - "json2csv": "^5.0.7" + "json2csv": "^5.0.7", + "solana-bankrun": "^0.2.0" }, "scripts": { "generate-docs": "typedoc", diff --git a/test-scripts/single-anchor-test.sh b/test-scripts/single-anchor-test.sh index 9a9bcef68..8fe1a67bd 100644 --- a/test-scripts/single-anchor-test.sh +++ b/test-scripts/single-anchor-test.sh @@ -4,7 +4,7 @@ if [ "$1" != "--skip-build" ] cp target/idl/drift.json sdk/src/idl/ fi -test_files=(perpLpJit.ts) +test_files=(simTest1.ts) for test_file in ${test_files[@]}; do ANCHOR_TEST_FILE=${test_file} anchor test --skip-build || exit 1; diff --git a/tests/simTest1.ts b/tests/simTest1.ts new file mode 100644 index 000000000..0aee5dcd2 --- /dev/null +++ b/tests/simTest1.ts @@ -0,0 +1,198 @@ +import { startAnchor } from 'solana-bankrun'; +import { BankrunProvider } from 'anchor-bankrun'; +import { Keypair, PublicKey } from '@solana/web3.js'; +import { Program } from '@coral-xyz/anchor'; +import { Drift, IDL as DriftIDL } from '../target/types/drift'; + +import { DriftClient, DRIFT_PROGRAM_ID } from '../sdk/src'; +import * as anchor from '@coral-xyz/anchor'; +import { assert } from 'chai'; + +import { + TestClient, + BN, + EventSubscriber, + SPOT_MARKET_RATE_PRECISION, + OracleSource, + SPOT_MARKET_WEIGHT_PRECISION, + SPOT_MARKET_CUMULATIVE_INTEREST_PRECISION, + OracleInfo, +} from '../sdk/src'; + +import { + createUserWithUSDCAccount, + mockOracle, + mockUSDCMint, + mockUserUSDCAccount, + printTxLogs, + sleep, +} from './testHelpers'; +import { + QUOTE_PRECISION, + BulkAccountLoader, + getUserAccountPublicKey, +} from '../sdk'; +import { calculateInitUserFee } from '../sdk/lib/math/state'; + +describe('surge pricing', () => { + let solOracle: PublicKey; + let admin: TestClient; + let usdcMint; + + const usdcAmount = new BN(10 * 10 ** 6); + const largeUsdcAmount = new BN(10_000 * 10 ** 6); + + let marketIndexes: number[]; + let spotMarketIndexes: number[]; + let oracleInfos: OracleInfo[]; + + before(async () => { + const context = await startAnchor('"./"', [], []); + + const provider = new BankrunProvider(context); + const connection = provider.connection; + + const chProgram = new Program(DriftIDL, DRIFT_PROGRAM_ID, provider); + + const eventSubscriber = new EventSubscriber(connection, chProgram, { + commitment: 'recent', + }); + eventSubscriber.subscribe(); + + const bulkAccountLoader = new BulkAccountLoader(connection, 'confirmed', 1); + + usdcMint = await mockUSDCMint(provider); + await mockUserUSDCAccount(usdcMint, largeUsdcAmount, provider); + + solOracle = await mockOracle(30); + + marketIndexes = []; + spotMarketIndexes = [0, 1]; + oracleInfos = [{ publicKey: solOracle, source: OracleSource.PYTH }]; + + admin = new TestClient({ + connection, + wallet: provider.wallet, + programID: chProgram.programId, + opts: { + commitment: 'confirmed', + }, + activeSubAccountId: 0, + perpMarketIndexes: marketIndexes, + spotMarketIndexes: spotMarketIndexes, + oracleInfos, + accountSubscription: { + type: 'polling', + accountLoader: bulkAccountLoader, + }, + }); + + await admin.initialize(usdcMint.publicKey, true); + await admin.subscribe(); + }); + + after(async () => { + await admin.unsubscribe(); + await eventSubscriber.unsubscribe(); + }); + + it('Initialize USDC Market', async () => { + const optimalUtilization = SPOT_MARKET_RATE_PRECISION.div( + new BN(2) + ).toNumber(); // 50% utilization + const optimalRate = SPOT_MARKET_RATE_PRECISION.mul(new BN(20)).toNumber(); // 2000% APR + const maxRate = SPOT_MARKET_RATE_PRECISION.mul(new BN(50)).toNumber(); // 5000% APR + const initialAssetWeight = SPOT_MARKET_WEIGHT_PRECISION.toNumber(); + const maintenanceAssetWeight = SPOT_MARKET_WEIGHT_PRECISION.toNumber(); + const initialLiabilityWeight = SPOT_MARKET_WEIGHT_PRECISION.toNumber(); + const maintenanceLiabilityWeight = SPOT_MARKET_WEIGHT_PRECISION.toNumber(); + await admin.initializeSpotMarket( + usdcMint.publicKey, + optimalUtilization, + optimalRate, + maxRate, + PublicKey.default, + OracleSource.QUOTE_ASSET, + initialAssetWeight, + maintenanceAssetWeight, + initialLiabilityWeight, + maintenanceLiabilityWeight + ); + const txSig = await admin.updateWithdrawGuardThreshold( + 0, + new BN(10 ** 10).mul(QUOTE_PRECISION) + ); + await printTxLogs(connection, txSig); + await admin.fetchAccounts(); + const spotMarket = await admin.getSpotMarketAccount(0); + assert(spotMarket.marketIndex === 0); + assert(spotMarket.optimalUtilization === optimalUtilization); + assert(spotMarket.optimalBorrowRate === optimalRate); + assert(spotMarket.maxBorrowRate === maxRate); + assert( + spotMarket.cumulativeBorrowInterest.eq( + SPOT_MARKET_CUMULATIVE_INTEREST_PRECISION + ) + ); + assert( + spotMarket.cumulativeDepositInterest.eq( + SPOT_MARKET_CUMULATIVE_INTEREST_PRECISION + ) + ); + assert(spotMarket.initialAssetWeight === initialAssetWeight); + assert(spotMarket.maintenanceAssetWeight === maintenanceAssetWeight); + assert(spotMarket.initialLiabilityWeight === initialLiabilityWeight); + assert(spotMarket.maintenanceAssetWeight === maintenanceAssetWeight); + + assert(admin.getStateAccount().numberOfSpotMarkets === 1); + + await admin.updateStateMaxNumberOfSubAccounts(5); + await admin.updateStateMaxInitializeUserFee(1); + }); + + it('Create users', async () => { + for (let i = 0; i < 5; i++) { + const expectedFee = calculateInitUserFee(admin.getStateAccount()); + const [driftClient, _, keyPair] = await createUserWithUSDCAccount( + provider, + usdcMint, + chProgram, + usdcAmount, + marketIndexes, + spotMarketIndexes, + oracleInfos, + bulkAccountLoader + ); + + const userAccount = await getUserAccountPublicKey( + driftClient.program.programId, + keyPair.publicKey, + 0 + ); + + const accountInfo = await connection.getAccountInfo(userAccount); + const baseLamports = 31347840; + console.log('expected fee', expectedFee.toNumber()); + if (i === 4) { + // assert(expectedFee.toNumber() === LAMPORTS_PER_SOL / 100); + } + console.log('account info', accountInfo.lamports); + assert(accountInfo.lamports === baseLamports + expectedFee.toNumber()); + await sleep(1000); + + if (i === 4) { + await admin.updateStateMaxNumberOfSubAccounts(0); + await driftClient.reclaimRent(0); + const accountInfoAfterReclaim = await connection.getAccountInfo( + userAccount + ); + console.log( + 'account info after reclaim', + accountInfoAfterReclaim.lamports + ); + assert(accountInfoAfterReclaim.lamports === baseLamports); + } + await driftClient.unsubscribe(); + } + }); +}); diff --git a/yarn.lock b/yarn.lock index e2f614a5e..dc0126a42 100644 --- a/yarn.lock +++ b/yarn.lock @@ -516,6 +516,11 @@ ajv@^8.0.1: require-from-string "^2.0.2" uri-js "^4.2.2" +anchor-bankrun@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/anchor-bankrun/-/anchor-bankrun-0.3.0.tgz#3789fcecbc201a2334cff228b99cc0da8ef0167e" + integrity sha512-PYBW5fWX+iGicIS5MIM/omhk1tQPUc0ELAnI/IkLKQJ6d75De/CQRh8MF2bU/TgGyFi6zEel80wUe3uRol9RrQ== + ansi-colors@^4.1.1: version "4.1.3" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" @@ -1706,6 +1711,45 @@ snake-case@^3.0.4: dot-case "^3.0.4" tslib "^2.0.3" +solana-bankrun-darwin-arm64@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/solana-bankrun-darwin-arm64/-/solana-bankrun-darwin-arm64-0.2.0.tgz#747e27f38e30d9022c9cccdead2e8d37cf006d55" + integrity sha512-ENQ5Z/CYeY8ZVWIc2VutY/gMlBaHi93/kDw9w0iVwewoV+/YpQmP2irwrshIKu6ggRPTF3Ehlh2V6fGVIYWcXw== + +solana-bankrun-darwin-universal@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/solana-bankrun-darwin-universal/-/solana-bankrun-darwin-universal-0.2.0.tgz#5b325b49578d7a9d74b02f7a05741658e46fd073" + integrity sha512-HE45TvZXzBipm1fMn87+fkHeIuQ/KFAi5G/S29y/TLuBYt4RDI935RkWiT0rEQ7KwnwO6Y1aTsOaQXldY5R7uQ== + +solana-bankrun-darwin-x64@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/solana-bankrun-darwin-x64/-/solana-bankrun-darwin-x64-0.2.0.tgz#d03eafd69c8dd9a53c84e993660c67cc71d531de" + integrity sha512-42UsVrnac2Oo4UaIDo60zfI3Xn1i8W6fmcc9ixJQZNTtdO8o2/sY4mFxcJx9lhLMhda5FPHrQbGYgYdIs0kK0g== + +solana-bankrun-linux-x64-gnu@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/solana-bankrun-linux-x64-gnu/-/solana-bankrun-linux-x64-gnu-0.2.0.tgz#eb133902e78afc5271ba034bd5353ad5f4005c10" + integrity sha512-WnqQjfBBdcI0ZLysjvRStI8gX7vm1c3CI6CC03lgkUztH+Chcq9C4LI9m2M8mXza8Xkn9ryeKAmX36Bx/yoVzg== + +solana-bankrun-linux-x64-musl@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/solana-bankrun-linux-x64-musl/-/solana-bankrun-linux-x64-musl-0.2.0.tgz#a99c5187f34ab5979c708281da74093c64baab4a" + integrity sha512-8mtf14ZBoah30+MIJBUwb5BlGLRZyK5cZhCkYnC/ROqaIDN8RxMM44NL63gTUIaNHsFwWGA9xR0KSeljeh3PKQ== + +solana-bankrun@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/solana-bankrun/-/solana-bankrun-0.2.0.tgz#e1df2126ee887b9eae17962f09db18aaa25d736f" + integrity sha512-TS6vYoO/9YJZng7oiLOVyuz8V7yLow5Hp4SLYWW71XM3702v+z9f1fvUBKudRfa4dfpta4tRNufApSiBIALxJQ== + dependencies: + "@solana/web3.js" "^1.68.0" + bs58 "^4.0.1" + optionalDependencies: + solana-bankrun-darwin-arm64 "0.2.0" + solana-bankrun-darwin-universal "0.2.0" + solana-bankrun-darwin-x64 "0.2.0" + solana-bankrun-linux-x64-gnu "0.2.0" + solana-bankrun-linux-x64-musl "0.2.0" + spok@^1.4.3: version "1.5.5" resolved "https://registry.yarnpkg.com/spok/-/spok-1.5.5.tgz#a51f7f290a53131d7b7a922dfedc461dda0aed72" From 13e8bd523411d27e134e49fa819dab65f3e8b121 Mon Sep 17 00:00:00 2001 From: 0xbigz <83473873+0xbigz@users.noreply.github.com> Date: Thu, 11 Jan 2024 00:31:42 -0500 Subject: [PATCH 2/3] fix path --- tests/simTest1.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/simTest1.ts b/tests/simTest1.ts index 0aee5dcd2..1eded3b12 100644 --- a/tests/simTest1.ts +++ b/tests/simTest1.ts @@ -47,7 +47,7 @@ describe('surge pricing', () => { let oracleInfos: OracleInfo[]; before(async () => { - const context = await startAnchor('"./"', [], []); + const context = await startAnchor('', [], []); const provider = new BankrunProvider(context); const connection = provider.connection; From e14ee68bced877992a6b0daeff34332860803927 Mon Sep 17 00:00:00 2001 From: 0xbigz <83473873+0xbigz@users.noreply.github.com> Date: Thu, 11 Jan 2024 01:09:17 -0500 Subject: [PATCH 3/3] add types --- tests/simTest1.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/simTest1.ts b/tests/simTest1.ts index 1eded3b12..b9466974b 100644 --- a/tests/simTest1.ts +++ b/tests/simTest1.ts @@ -1,6 +1,6 @@ import { startAnchor } from 'solana-bankrun'; import { BankrunProvider } from 'anchor-bankrun'; -import { Keypair, PublicKey } from '@solana/web3.js'; +import { Connection, Keypair, PublicKey } from '@solana/web3.js'; import { Program } from '@coral-xyz/anchor'; import { Drift, IDL as DriftIDL } from '../target/types/drift'; @@ -49,8 +49,8 @@ describe('surge pricing', () => { before(async () => { const context = await startAnchor('', [], []); - const provider = new BankrunProvider(context); - const connection = provider.connection; + const provider: BankrunProvider = new BankrunProvider(context); + const connection: Connection = provider.connection; const chProgram = new Program(DriftIDL, DRIFT_PROGRAM_ID, provider);