Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prod deploy #403

Merged
merged 27 commits into from
Dec 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
00d6f8d
Auto-merge master back to develop
Nov 22, 2024
a62929a
solana allow owner off curve (#372)
shan-57blocks Nov 25, 2024
f0dc3bc
Fix points month text (#374)
mliu Nov 26, 2024
0ff208a
Stellar mainnet
mliu Nov 26, 2024
bb2f24c
Merge pull request #377 from 00labs/stellar-mainnet
mliu Nov 26, 2024
449f26d
Solana autoredeem upgrade
mliu Nov 27, 2024
a608e28
Update USDC decimals
mliu Dec 1, 2024
6972fad
Merge pull request #382 from 00labs/fix-decimals
PlayJok3r Dec 1, 2024
a51ee63
update scroll pool config addresses (#384)
shan-57blocks Dec 2, 2024
fd43c7c
Add SDK method for reading available credit from Solana pool
mliu Dec 5, 2024
0aa85fd
Merge pull request #391 from 00labs/solana-avail-balance
mliu Dec 6, 2024
bcb6793
Handling pool cap of 0
mliu Dec 6, 2024
efaca45
Merge pull request #392 from 00labs/pool-cap-0
mliu Dec 6, 2024
835c7fb
Check receivable uri is valid before fetching
mliu Dec 10, 2024
c802b4b
Update
mliu Dec 10, 2024
e3f8dc0
Merge pull request #394 from 00labs/check-valid-uri
mliu Dec 10, 2024
a28a3ce
Handle 0 liquidity cap when clicking max in supply
mliu Dec 10, 2024
cd8ae08
Merge pull request #395 from 00labs/handle-0-cap-max
mliu Dec 10, 2024
cdd7c4d
Show decimals for money val under 100k
mliu Dec 10, 2024
9a96a3c
Fix tests
mliu Dec 10, 2024
eb29b8b
Merge pull request #396 from 00labs/change-money-rounding
mliu Dec 10, 2024
fe64275
Upgrade stellar contract interface
mliu Dec 22, 2024
da635aa
Update sdk ver
mliu Dec 24, 2024
9aa80fd
Merge pull request #402 from 00labs/stellar-update
mliu Dec 24, 2024
91b0e3c
Merge branch 'develop' into solana-autoredeem-upgrade
mliu Dec 27, 2024
8bd49c5
Yield withdraw
mliu Dec 30, 2024
d51c0f4
Merge pull request #378 from 00labs/solana-autoredeem-upgrade
mliu Dec 31, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions packages/examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@
"solanaDeclarePayment": "ts-node src/solana/declarePayment.ts",
"solanaSubmitReceivable": "ts-node src/solana/submitReceivable.ts",
"solanaFetchReceivable": "ts-node src/solana/fetchReceivable.ts",
"solanaFetchAvailableCredit": "ts-node src/solana/fetchAvailableCredit.ts",
"solanaFetchBorrowerDetails": "ts-node src/solana/fetchBorrowerDetails.ts",
"solanaDrawdown": "ts-node src/solana/drawdown.ts",
"solanaWithdrawYield": "ts-node src/solana/withdrawYield.ts",
"solanaPayback": "ts-node src/solana/payback.ts",
"lint-staged": "lint-staged"
},
Expand All @@ -42,12 +44,12 @@
"@solana/wallet-adapter-react-ui": "^0.9.35",
"@solana/wallet-adapter-wallets": "^0.19.32",
"@stellar/freighter-api": "^3.0.0",
"@huma-finance/soroban-credit-storage": "0.0.15",
"@huma-finance/soroban-huma-config": "0.0.15",
"@huma-finance/soroban-pool-storage": "0.0.15",
"@huma-finance/soroban-sdk": "^0.0.15",
"@huma-finance/soroban-tranche-vault": "0.0.15",
"@stellar/stellar-sdk": "^12.3.0",
"@huma-finance/soroban-credit-storage": "0.0.18",
"@huma-finance/soroban-huma-config": "0.0.18",
"@huma-finance/soroban-pool-storage": "0.0.18",
"@huma-finance/soroban-sdk": "^0.0.18",
"@huma-finance/soroban-tranche-vault": "0.0.18",
"@stellar/stellar-sdk": "13.0.0",
"@coral-xyz/borsh": "^0.30.1",
"@mui/icons-material": "^5.3.0",
"@mui/material": "^5.0.6",
Expand Down
48 changes: 48 additions & 0 deletions packages/examples/src/solana/fetchAvailableCredit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {
Connection,
Keypair,
PublicKey,
sendAndConfirmTransaction,
} from '@solana/web3.js'
import {
AnchorProvider,
BN,
setProvider,
Wallet,
web3,
} from '@coral-xyz/anchor'
import { POOL_NAME, SolanaChainEnum } from '@huma-finance/shared'
import { HumaSolanaContext, HumaSolanaProgramHelper } from '@huma-finance/sdk'

require('dotenv').config()

async function main() {
const TEST_PRIVATE_KEY = process.env.TEST_PRIVATE_KEY
const connection = new Connection(
'https://api.devnet.solana.com',
'confirmed',
)

const keypair = web3.Keypair.fromSecretKey(
Buffer.from(JSON.parse(TEST_PRIVATE_KEY)),
)
const wallet = new Wallet(keypair)
setProvider(new AnchorProvider(connection, wallet))

const solanaHumaContext = new HumaSolanaContext({
publicKey: new PublicKey('4PxkeCBfCCPYWMgV2g9URsMqkp3VR1S5ABuB1ZbrRpVz'),
connection: connection,
chainId: SolanaChainEnum.SolanaDevnet,
poolName: POOL_NAME.ArfCreditPool3Months,
})

const humaSolanaProgramHelper = new HumaSolanaProgramHelper({
solanaContext: solanaHumaContext,
})

const data = await humaSolanaProgramHelper.getAvailableCreditForPool()

console.log(data)
}

main()
46 changes: 46 additions & 0 deletions packages/examples/src/solana/withdrawYield.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Connection, Keypair, sendAndConfirmTransaction } from '@solana/web3.js'
import {
AnchorProvider,
BN,
setProvider,
Wallet,
web3,
} from '@coral-xyz/anchor'
import { POOL_NAME, SolanaChainEnum } from '@huma-finance/shared'
import { HumaSolanaContext, HumaSolanaProgramHelper } from '@huma-finance/sdk'

require('dotenv').config()

async function main() {
const TEST_PRIVATE_KEY = process.env.TEST_PRIVATE_KEY
const connection = new Connection(
'https://api.devnet.solana.com',
'confirmed',
)

const keypair = web3.Keypair.fromSecretKey(
Buffer.from(JSON.parse(TEST_PRIVATE_KEY)),
)
const wallet = new Wallet(keypair)
setProvider(new AnchorProvider(connection, wallet))

const solanaHumaContext = new HumaSolanaContext({
publicKey: wallet.publicKey,
connection: connection,
chainId: SolanaChainEnum.SolanaDevnet,
poolName: POOL_NAME.ArfCreditPool3Months,
})

const humaSolanaProgramHelper = new HumaSolanaProgramHelper({
solanaContext: solanaHumaContext,
})

const tx = await humaSolanaProgramHelper.buildWithdrawYieldsTransaction()

console.log(tx)

const txResult = await sendAndConfirmTransaction(connection, tx, [keypair])
console.log(txResult)
}

main()
164 changes: 162 additions & 2 deletions packages/huma-sdk/src/helpers/solana/HumaSolanaProgramHelper.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BN } from '@coral-xyz/anchor'
import { BN, utils } from '@coral-xyz/anchor'
import {
getCreditAccounts,
getHumaProgram,
Expand All @@ -11,6 +11,7 @@ import {
createApproveCheckedInstruction,
createAssociatedTokenAccountInstruction,
getAccount,
TOKEN_2022_PROGRAM_ID,
TOKEN_PROGRAM_ID,
TokenAccountNotFoundError,
} from '@solana/spl-token'
Expand All @@ -33,6 +34,42 @@ export class HumaSolanaProgramHelper {
this.#solanaContext = solanaContext
}

async getAvailableCreditForPool(): Promise<BN> {
const { chainId, poolName } = this.#solanaContext
const poolInfo = getSolanaPoolInfo(chainId, poolName)

if (!poolInfo) {
throw new Error('Could not find pool')
}

const accountInfo = await this.getAccountInfo()
if (accountInfo === null) {
throw new Error('Could not get account info for this pool.')
}

const tokenAccount = await getAccount(
this.#solanaContext.connection,
new PublicKey(poolInfo.poolUnderlyingTokenAccount),
undefined,
TOKEN_PROGRAM_ID,
)

const { creditConfig, creditState } = accountInfo
const principalAmount = creditState.creditRecord.unbilledPrincipal
.add(creditState.creditRecord.nextDue)
.sub(creditState.creditRecord.yieldDue)
.add(creditState.dueDetail.principalPastDue)
const unusedCredit = creditConfig.creditLimit.sub(principalAmount)
const poolTokenBalanceBN = new BN(tokenAccount.amount.toString())
// Set available credit to the minimum of the pool balance or the credit available amount,
// since both are upper bounds on the amount of credit that can be borrowed.
// If either is negative, cap the available credit to 0.
const creditAvailable = unusedCredit.lt(poolTokenBalanceBN)
? unusedCredit
: poolTokenBalanceBN
return creditAvailable.ltn(0) ? new BN(0) : creditAvailable
}

async buildSubmitReceivableTransaction(
referenceId: string,
): Promise<Transaction> {
Expand Down Expand Up @@ -91,6 +128,100 @@ export class HumaSolanaProgramHelper {
return tx
}

async buildWithdrawYieldsTransaction(): Promise<Transaction> {
const { publicKey, connection, chainId, poolName } = this.#solanaContext
const program = getHumaProgram(chainId, connection)
const poolInfo = getSolanaPoolInfo(chainId, poolName)

if (!poolInfo) {
throw new Error('Could not find pool')
}

const tx: Transaction = new Transaction()

const { underlyingTokenATA, seniorTrancheATA, juniorTrancheATA } =
getTokenAccounts(poolInfo, publicKey)
const [juniorYieldDistributingLenderAccount] =
PublicKey.findProgramAddressSync(
[
utils.bytes.utf8.encode('yield_distributing_lender'),
new PublicKey(poolInfo.juniorTrancheMint).toBuffer(),
publicKey.toBuffer(),
],
program.programId,
)
const programTx = await program.methods
.withdrawYields()
.accountsPartial({
lender: publicKey,
humaConfig: poolInfo.humaConfig,
poolConfig: poolInfo.poolConfig,
yieldDistributingLender: juniorYieldDistributingLenderAccount,
underlyingMint: poolInfo.underlyingMint.address,
poolUnderlyingToken: poolInfo.poolUnderlyingTokenAccount,
lenderUnderlyingToken: underlyingTokenATA,
trancheMint: poolInfo.juniorTrancheMint,
lenderTrancheToken: juniorTrancheATA,
underlyingTokenProgram: TOKEN_PROGRAM_ID,
trancheTokenProgram: TOKEN_2022_PROGRAM_ID,
})
.transaction()
const txAccounts: PublicKey[] = [
publicKey,
new PublicKey(poolInfo.humaConfig),
new PublicKey(poolInfo.poolConfig),
juniorYieldDistributingLenderAccount,
new PublicKey(poolInfo.underlyingMint.address),
new PublicKey(poolInfo.poolUnderlyingTokenAccount),
underlyingTokenATA,
new PublicKey(poolInfo.juniorTrancheMint),
juniorTrancheATA,
TOKEN_PROGRAM_ID,
TOKEN_2022_PROGRAM_ID,
]
tx.add(programTx)

if (poolInfo.seniorTrancheMint) {
const [seniorYieldDistributingLenderAccount] =
PublicKey.findProgramAddressSync(
[
utils.bytes.utf8.encode('yield_distributing_lender'),
new PublicKey(poolInfo.seniorTrancheMint).toBuffer(),
publicKey.toBuffer(),
],
program.programId,
)
const programTx = await program.methods
.withdrawYields()
.accountsPartial({
lender: publicKey,
humaConfig: poolInfo.humaConfig,
poolConfig: poolInfo.poolConfig,
yieldDistributingLender: seniorYieldDistributingLenderAccount,
underlyingMint: poolInfo.underlyingMint.address,
poolUnderlyingToken: poolInfo.poolUnderlyingTokenAccount,
lenderUnderlyingToken: underlyingTokenATA,
trancheMint: poolInfo.seniorTrancheMint,
lenderTrancheToken: seniorTrancheATA,
underlyingTokenProgram: TOKEN_PROGRAM_ID,
trancheTokenProgram: TOKEN_2022_PROGRAM_ID,
})
.transaction()
txAccounts.push(
...[
seniorYieldDistributingLenderAccount,
new PublicKey(poolInfo.seniorTrancheMint),
seniorTrancheATA,
],
)
tx.add(programTx)
}

await buildOptimalTransaction(tx, txAccounts, this.#solanaContext)

return tx
}

async buildDrawdownTransaction(amount: BN): Promise<Transaction> {
const { publicKey, connection, chainId, poolName } = this.#solanaContext
const program = getHumaProgram(chainId, connection)
Expand Down Expand Up @@ -306,7 +437,36 @@ export class HumaSolanaProgramHelper {
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
async getAccountInfo(): Promise<any> {
async getAccountInfo(): Promise<{
creditConfig: {
creditLimit: BN
committedAmount: BN
numPeriods: number
yieldBps: number
}
creditState: {
creditRecord: {
status: unknown
nextDue: BN
yieldDue: BN
nextDueDate: BN
totalPastDue: BN
missedPeriods: number
remainingPeriods: number
unbilledPrincipal: BN
}
dueDetail: {
paid: BN
accrued: BN
lateFee: BN
committed: BN
yieldPastDue: BN
principalPastDue: BN
lateFeeUpdatedDate: BN
}
receivableAvailableCredits: BN
}
} | null> {
const { publicKey, chainId, poolName } = this.#solanaContext
const program = getHumaProgram(chainId, this.#solanaContext.connection)
const poolInfo = getSolanaPoolInfo(chainId, poolName)
Expand Down
3 changes: 2 additions & 1 deletion packages/huma-sdk/src/services/ReceivableService.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { TransactionResponse } from '@ethersproject/providers'
import { BigNumberish, ethers, Overrides } from 'ethers'
import {
isValidHttpUrl,
POOL_NAME,
POOL_TYPE,
PoolContractMap,
Expand Down Expand Up @@ -445,7 +446,7 @@ async function loadReceivablesOfOwnerWithMetadata<T>(
}

const fetchMetadata = async (rwrInfoBase: RealWorldReceivableInfoBase) => {
if (!rwrInfoBase.tokenURI) {
if (!isValidHttpUrl(rwrInfoBase.tokenURI) || !rwrInfoBase.tokenURI) {
return null
}
return ARWeaveService.fetchMetadataFromUrl(rwrInfoBase.tokenURI)
Expand Down
Loading
Loading