diff --git a/package.json b/package.json index b6b0750c1..cef7d3808 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "clean": "rm -rf dist", "example1-user": "ts-node ts/client/src/scripts/example1-user.ts", "example1-admin": "ts-node ts/client/src/scripts/example1-admin.ts", - "scratch": "ts-node ts/client/src/scripts/scratch.ts", + "scratch": "ts-node ts/client/src/scripts/scratch/scratch.ts", "format": "prettier --check .", "lint": "eslint . --ext ts --ext tsx --ext js --quiet", "type-check": "tsc --pretty --noEmit", diff --git a/ts/client/src/accounts/mangoAccount.ts b/ts/client/src/accounts/mangoAccount.ts index 5e5c3ee48..f8a1c8eda 100644 --- a/ts/client/src/accounts/mangoAccount.ts +++ b/ts/client/src/accounts/mangoAccount.ts @@ -3,6 +3,7 @@ import { utf8 } from '@project-serum/anchor/dist/cjs/utils/bytes'; import { PublicKey } from '@solana/web3.js'; import { MangoClient } from '../client'; import { Bank } from './bank'; +import { Group } from './group'; import { I80F48, I80F48Dto, ZERO_I80F48 } from './I80F48'; export class MangoAccount { public tokens: TokenAccount[]; @@ -77,23 +78,27 @@ export class MangoAccount { return this.serum3.find((sa) => sa.marketIndex == marketIndex); } - getNativeDeposit(bank: Bank): I80F48 { + getNative(bank: Bank): I80F48 { const ta = this.findToken(bank.tokenIndex); - return ta ? bank.depositIndex.mul(ta?.indexedValue) : ZERO_I80F48; + return ta ? ta.native(bank) : ZERO_I80F48; } - getNativeBorrow(bank: Bank): I80F48 { + getUi(bank: Bank): number { const ta = this.findToken(bank.tokenIndex); - return ta ? bank.borrowIndex.mul(ta?.indexedValue) : ZERO_I80F48; + return ta ? ta.ui(bank) : 0; } - toString(): string { + tokens_active(): TokenAccount[] { + return this.tokens.filter((token) => token.isActive()); + } + + toString(group?: Group): string { return ( 'tokens:' + JSON.stringify( - this.tokens.filter( - (token) => token.tokenIndex != TokenAccount.TokenIndexUnset, - ), + this.tokens + .filter((token) => token.tokenIndex != TokenAccount.TokenIndexUnset) + .map((token) => token.toString(group)), null, 4, ) + @@ -134,9 +139,44 @@ export class TokenAccount { public inUseCount: number, ) {} - isActive(): boolean { + public isActive(): boolean { return this.tokenIndex !== 65535; } + + public native(bank: Bank): I80F48 { + if (this.indexedValue.isPos()) { + return bank.depositIndex.mul(this.indexedValue); + } else { + return bank.borrowIndex.mul(this.indexedValue); + } + } + + public ui(bank: Bank): number { + return this.native(bank).toNumber() / Math.pow(10, bank.mintDecimals); + } + + public toString(group?: Group): String { + let extra: string = ''; + if (group) { + let bank = group.findBank(this.tokenIndex); + if (bank) { + let native = this.native(bank); + extra += ', native: ' + native.toNumber(); + extra += ', ui: ' + this.ui(bank); + extra += ', tokenName: ' + bank.name; + } + } + + return ( + 'tokenIndex: ' + + this.tokenIndex + + ', inUseCount: ' + + this.inUseCount + + ', indexedValue: ' + + this.indexedValue.toNumber() + + extra + ); + } } export class TokenAccountDto { diff --git a/ts/client/src/client.ts b/ts/client/src/client.ts index b44b34402..58692dcc5 100644 --- a/ts/client/src/client.ts +++ b/ts/client/src/client.ts @@ -385,7 +385,7 @@ export class MangoClient { await this.buildHealthRemainingAccounts(group, mangoAccount, [bank]); return await this.program.methods - .withdraw(new BN(amount), allowBorrow) + .withdraw(toNativeDecimals(amount, bank.mintDecimals), allowBorrow) .accounts({ group: group.publicKey, account: mangoAccount.publicKey, diff --git a/ts/client/src/scripts/example1-user.ts b/ts/client/src/scripts/example1-user.ts index 392f7a9be..8a2ff8f28 100644 --- a/ts/client/src/scripts/example1-user.ts +++ b/ts/client/src/scripts/example1-user.ts @@ -54,16 +54,16 @@ async function main() { if (true) { // deposit and withdraw - console.log(`Depositing...5000000 USDC`); - await client.deposit(group, mangoAccount, 'USDC', 50_000000); + console.log(`Depositing...5 USDC`); + await client.deposit(group, mangoAccount, 'USDC', 5); await mangoAccount.reload(client); - console.log(`Depositing...5000000 BTC`); - await client.deposit(group, mangoAccount, 'BTC', 5000000); + console.log(`Depositing...0.0005 BTC`); + await client.deposit(group, mangoAccount, 'BTC', 0.0005); await mangoAccount.reload(client); - console.log(`Withdrawing...1000000 USDC`); - await client.withdraw(group, mangoAccount, 'USDC', 1_000000, false); + console.log(`Withdrawing...1 USDC`); + await client.withdraw(group, mangoAccount, 'USDC', 1, false); await mangoAccount.reload(client); // serum3 diff --git a/ts/client/src/scripts/example1-ob.ts b/ts/client/src/scripts/scratch/example1-ob.ts similarity index 95% rename from ts/client/src/scripts/example1-ob.ts rename to ts/client/src/scripts/scratch/example1-ob.ts index ebfaa424a..60463efc9 100644 --- a/ts/client/src/scripts/example1-ob.ts +++ b/ts/client/src/scripts/scratch/example1-ob.ts @@ -1,8 +1,8 @@ import { AnchorProvider, Wallet } from '@project-serum/anchor'; import { Connection, Keypair } from '@solana/web3.js'; import fs from 'fs'; -import { MangoClient } from '../client'; -import { DEVNET_SERUM3_PROGRAM_ID } from '../constants'; +import { MangoClient } from '../../client'; +import { DEVNET_SERUM3_PROGRAM_ID } from '../../constants'; // // An example for users based on high level api i.e. the client diff --git a/ts/client/src/scripts/example1-user-account.ts b/ts/client/src/scripts/scratch/example1-user-account.ts similarity index 94% rename from ts/client/src/scripts/example1-user-account.ts rename to ts/client/src/scripts/scratch/example1-user-account.ts index 59c684890..c7a8caed4 100644 --- a/ts/client/src/scripts/example1-user-account.ts +++ b/ts/client/src/scripts/scratch/example1-user-account.ts @@ -1,8 +1,8 @@ import { AnchorProvider, Wallet } from '@project-serum/anchor'; import { Connection, Keypair } from '@solana/web3.js'; import fs from 'fs'; -import { TokenAccount } from '../accounts/mangoAccount'; -import { MangoClient } from '../client'; +import { TokenAccount } from '../../accounts/mangoAccount'; +import { MangoClient } from '../../client'; // // An example for users based on high level api i.e. the client diff --git a/ts/client/src/scripts/scratch/example1-withdraw-max.ts b/ts/client/src/scripts/scratch/example1-withdraw-max.ts new file mode 100644 index 000000000..034c88653 --- /dev/null +++ b/ts/client/src/scripts/scratch/example1-withdraw-max.ts @@ -0,0 +1,97 @@ +import { AnchorProvider, Wallet } from '@project-serum/anchor'; +import { Connection, Keypair } from '@solana/web3.js'; +import fs from 'fs'; +import { MangoClient } from '../../client'; + +async function main() { + const options = AnchorProvider.defaultOptions(); + const connection = new Connection( + 'https://mango.devnet.rpcpool.com', + options, + ); + + /// user1 + const user1 = Keypair.fromSecretKey( + Buffer.from( + JSON.parse(fs.readFileSync(process.env.PAYER_KEYPAIR!, 'utf-8')), + ), + ); + const user1Wallet = new Wallet(user1); + const user1Provider = new AnchorProvider(connection, user1Wallet, options); + const user1Client = await MangoClient.connect(user1Provider, true); + console.log(`user1 ${user1Wallet.publicKey.toBase58()}`); + + /// fetch group + const admin = Keypair.fromSecretKey( + Buffer.from( + JSON.parse(fs.readFileSync(process.env.ADMIN_KEYPAIR!, 'utf-8')), + ), + ); + const group = await user1Client.getGroupForAdmin(admin.publicKey, 0); + console.log(`Found group ${group.publicKey.toBase58()}`); + + /// fetch user1 account + const user1MangoAccount = await user1Client.getOrCreateMangoAccount( + group, + user1.publicKey, + 0, + 'my_mango_account', + ); + + console.log(`...created/found mangoAccount ${user1MangoAccount.publicKey}`); + + /// user1 deposits some btc, so user2 can borrow it + let amount = 0.001; + let token = 'BTC'; + + // console.log(`Depositing...${amount} 'BTC'`); + // await user1Client.deposit(group, user1MangoAccount, token, amount); + // await user1MangoAccount.reload(user1Client); + // console.log(`${user1MangoAccount.toString(group)}`); + + console.log('---'); + + /// user2 deposits some collateral and borrows BTC + + const user2 = Keypair.fromSecretKey( + Buffer.from( + JSON.parse(fs.readFileSync(process.env.USER_KEYPAIR!, 'utf-8')), + ), + ); + const user2Wallet = new Wallet(user2); + const user2Provider = new AnchorProvider(connection, user2Wallet, options); + const user2Client = await MangoClient.connect(user2Provider, true); + console.log(`user2 ${user2Wallet.publicKey.toBase58()}`); + + // create + fetch account + console.log(`Creating mangoaccount...`); + const user2MangoAccount = await user2Client.getOrCreateMangoAccount( + group, + user2.publicKey, + 0, + 'my_mango_account', + ); + console.log(`...created/found mangoAccount ${user2MangoAccount.publicKey}`); + + // console.log(`Depositing...${300} 'USDC'`); + // await user2Client.deposit(group, user2MangoAccount, 'USDC', 300); + // await user2MangoAccount.reload(user2Client); + // console.log(`${user2MangoAccount.toString(group)}`); + + amount = amount / 10; + while (true) { + try { + console.log(`Withdrawing...${amount} 'BTC'`); + await user2Client.withdraw(group, user2MangoAccount, token, amount, true); + } catch (error) { + console.log(error); + break; + } + } + await user2MangoAccount.reload(user2Client); + console.log(`${user2MangoAccount.toString(group)}`); + + process.exit(); +} + +main(); diff --git a/ts/client/src/scripts/scratch.ts b/ts/client/src/scripts/scratch/scratch.ts similarity index 96% rename from ts/client/src/scripts/scratch.ts rename to ts/client/src/scripts/scratch/scratch.ts index 4187bbd9a..6bd197abc 100644 --- a/ts/client/src/scripts/scratch.ts +++ b/ts/client/src/scripts/scratch/scratch.ts @@ -4,7 +4,7 @@ import { AnchorProvider, Wallet } from '@project-serum/anchor'; import { Market } from '@project-serum/serum'; import { Connection, Keypair, PublicKey } from '@solana/web3.js'; -import { MangoClient } from '../client'; +import { MangoClient } from '../../client'; const main = async () => { const options = AnchorProvider.defaultOptions();