Skip to content

Commit

Permalink
Add catch for shared escrow insufficient rent (#98)
Browse files Browse the repository at this point in the history
* add catch for shared escrow insufficient rent

* remove only

* fix test

* fix test again
  • Loading branch information
madergaser authored May 28, 2024
1 parent 56c30e5 commit e0da28e
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 17 deletions.
14 changes: 13 additions & 1 deletion programs/mmm/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,18 @@ pub fn withdraw_m2<'info>(
&[pool_bump],
]];

let no_data_rent = Rent::get()?.minimum_balance(0);
let withdraw_amount = if m2_buyer_escrow.lamports().saturating_sub(
no_data_rent
.checked_add(amount)
.ok_or(MMMErrorCode::NumericOverflow)?,
) > 0
{
amount
} else {
m2_buyer_escrow.lamports()
};

let ix = withdraw_by_mmm_ix_with_program_id(
M2_PROGRAM,
WithdrawByMmmKeys {
Expand All @@ -659,7 +671,7 @@ pub fn withdraw_m2<'info>(
args: WithdrawByMMMArgs {
wallet,
auction_house: M2_AUCTION_HOUSE,
amount,
amount: withdraw_amount,
mmm_pool_uuid: pool.uuid,
},
},
Expand Down
55 changes: 39 additions & 16 deletions tests/mmm-fulfill-shared-escrow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
ASSOCIATED_TOKEN_PROGRAM_ID,
TOKEN_PROGRAM_ID,
getAssociatedTokenAddress,
getAccount as getTokenAccount,
} from '@solana/spl-token';
import {
ComputeBudgetProgram,
Expand Down Expand Up @@ -428,21 +427,34 @@ describe('shared-escrow mmm-fulfill-linear', () => {
};
const seller = Keypair.generate();
const nftCreator = Keypair.generate();
await airdrop(connection, nftCreator.publicKey, 10);
// generate new wallet and keypair to simuluate closing behavior when not enough rent
// and when cap is reached
const newWallet = new anchor.Wallet(Keypair.generate());
const newProgram = new anchor.Program(
IDL,
MMMProgramID,
new anchor.AnchorProvider(connection, newWallet, {
commitment: 'processed',
}),
) as anchor.Program<Mmm>;
await Promise.all([
airdrop(connection, newWallet.publicKey, 10),
airdrop(connection, nftCreator.publicKey, 10),
]);
const rulesRes = await createDefaultTokenAuthorizationRules(
connection,
nftCreator,
'test',
);
const defaultRules = rulesRes.ruleSetAddress;
const buyerSharedEscrow = getM2BuyerSharedEscrow(wallet.publicKey).key;
await airdrop(connection, buyerSharedEscrow, 10);
const buyerSharedEscrow = getM2BuyerSharedEscrow(newWallet.publicKey).key;
const extraLamports = 10;

const [poolData] = await Promise.all([
createPoolWithExampleMip1Deposits(
program,
newProgram,
{
owner: wallet.publicKey,
owner: newWallet.publicKey,
cosigner,
spotPrice: new anchor.BN(2.2 * LAMPORTS_PER_SOL),
curveDelta: new anchor.BN(1 * LAMPORTS_PER_SOL),
Expand All @@ -459,21 +471,22 @@ describe('shared-escrow mmm-fulfill-linear', () => {
1, // just enough sol to cover the first fulfilment
),
airdrop(connection, seller.publicKey, 10),
airdrop(connection, buyerSharedEscrow, 2.2 + extraLamports * 1e-9),
]);

const [
initPoolOwnerBalance,
poolRent,
initSellerBalance,
initPaymentEscrowBalance,
initCreatorBalance,
initReferralBalance,
sellStateAccountRent,
initBuyerSharedEscrowBalance,
] = await Promise.all([
connection.getBalance(newWallet.publicKey),
connection.getBalance(poolData.poolKey),
connection.getBalance(seller.publicKey),
connection.getBalance(poolData.poolPaymentEscrow),
connection.getBalance(poolData.nftCreator.publicKey),
connection.getBalance(poolData.referral.publicKey),
getSellStatePDARent(connection),
connection.getBalance(buyerSharedEscrow),
]);

Expand All @@ -485,7 +498,7 @@ describe('shared-escrow mmm-fulfill-linear', () => {

const ownerExtraNftAtaAddress = await getAssociatedTokenAddress(
poolData.extraNft.mintAddress,
wallet.publicKey,
newWallet.publicKey,
);

// sale price should be 2.2 SOL
Expand All @@ -496,20 +509,20 @@ describe('shared-escrow mmm-fulfill-linear', () => {
metadataRoyaltyBp: 150,
buysideCreatorRoyaltyBp: 10000,
lpFeeBp: 0,
makerFeeBp: 350,
makerFeeBp: 0,
});

const tx = await program.methods
const tx = await newProgram.methods
.solMip1FulfillBuy({
assetAmount: new anchor.BN(1),
minPaymentAmount: expectedBuyPrices.sellerReceives,
allowlistAux: null,
makerFeeBp: 350,
makerFeeBp: 0,
takerFeeBp: 50,
})
.accountsStrict({
payer: seller.publicKey,
owner: wallet.publicKey,
owner: newWallet.publicKey,
cosigner: cosigner.publicKey,
referral: poolData.referral.publicKey,
pool: poolData.poolKey,
Expand Down Expand Up @@ -569,13 +582,15 @@ describe('shared-escrow mmm-fulfill-linear', () => {
expectedBuyPrices.makerFeePaid.toNumber() +
expectedBuyPrices.takerFeePaid.toNumber();
const [
poolOwnerBalance,
sellerBalance,
paymentEscrowAccount,
paymentEscrowBalance,
creatorBalance,
referralBalance,
afterBuyerSharedEscrowBalance,
] = await Promise.all([
connection.getBalance(newWallet.publicKey),
connection.getBalance(seller.publicKey),
connection.getAccountInfo(poolData.poolPaymentEscrow),
connection.getBalance(poolData.poolPaymentEscrow),
Expand All @@ -584,6 +599,11 @@ describe('shared-escrow mmm-fulfill-linear', () => {
connection.getBalance(buyerSharedEscrow),
]);

assert.equal(
poolOwnerBalance,
// pool rent + extra lamports that would cause rent error
initPoolOwnerBalance + poolRent + extraLamports,
);
assert.equal(
sellerBalance,
initSellerBalance +
Expand All @@ -592,8 +612,11 @@ describe('shared-escrow mmm-fulfill-linear', () => {
);
assert.equal(
initBuyerSharedEscrowBalance - afterBuyerSharedEscrowBalance,
2.2 * LAMPORTS_PER_SOL + expectedBuyPrices.makerFeePaid.toNumber(),
2.2 * LAMPORTS_PER_SOL +
expectedBuyPrices.makerFeePaid.toNumber() +
extraLamports,
);
assert.equal(afterBuyerSharedEscrowBalance, 0);
assert.equal(paymentEscrowBalance, 0);
assert.isNull(paymentEscrowAccount);
assert.equal(
Expand Down

0 comments on commit e0da28e

Please sign in to comment.