Skip to content

Commit

Permalink
Merge pull request #184 from metaplex-foundation/fix/fee-math
Browse files Browse the repository at this point in the history
Simplifying fee math
  • Loading branch information
blockiosaurus authored Aug 7, 2024
2 parents 8a53809 + f096073 commit a8d6807
Show file tree
Hide file tree
Showing 2 changed files with 312 additions and 42 deletions.
314 changes: 308 additions & 6 deletions clients/js/test/collect.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,23 @@ import {
} from '@metaplex-foundation/umi';
import test from 'ava';

import { fixedAccountInit } from '@metaplex-foundation/mpl-core-oracle-example';
import {
CheckResult,
ExternalPluginAdapterSchema,
ExternalValidationResult,
PluginType,
addPlugin,
addPluginV1,
burnV1,
collect,
createPlugin,
pluginAuthorityPair,
removePlugin,
removePluginV1,
transfer,
} from '../src';
import { assertAsset, createAsset, createUmi } from './_setupRaw';
import { assertAsset, createUmi } from './_setupRaw';
import { createAsset } from './_setupSdk';

const recipient1 = publicKey('8AT6o8Qk5T9QnZvPThMrF9bcCQLTGkyGvVZZzHgCw11v');
const recipient2 = publicKey('MmHsqX4LxTfifxoH8BVRLUKrwDn1LPCac6YcCZTHhwt');
Expand All @@ -39,6 +45,15 @@ const hasCollectAmount = async (umi: Umi, address: PublicKey) => {
return false;
};

const assertNoExcessRent = async (umi: Umi, address: PublicKey) => {
const account = await umi.rpc.getAccount(address);
if (account.exists) {
const rent = await umi.rpc.getRent(account.data.length);
return account.lamports.basisPoints === rent.basisPoints;
}
return false;
};

test('it can create a new asset with collect amount', async (t) => {
const umi = await createUmi();
const asset = await createAsset(umi);
Expand All @@ -65,14 +80,33 @@ test('it can add asset plugin with collect amount', async (t) => {
);
});

test('it can add remove asset plugin with collect amount', async (t) => {
test('it can add asset external plugin with collect amount', async (t) => {
const umi = await createUmi();
const asset = await createAsset(umi);

await addPlugin(umi, {
asset: asset.publicKey,
plugin: {
type: 'AppData',
dataAuthority: { type: 'UpdateAuthority' },
schema: ExternalPluginAdapterSchema.Json,
},
}).sendAndConfirm(umi);

t.assert(
await hasCollectAmount(umi, asset.publicKey),
'Collect amount not found'
);
});

test('it can remove asset plugin with collect amount', async (t) => {
const umi = await createUmi();
const asset = await createAsset(umi, {
plugins: [
pluginAuthorityPair({
{
type: 'FreezeDelegate',
data: { frozen: false },
}),
frozen: false,
},
],
});

Expand All @@ -91,6 +125,33 @@ test('it can add remove asset plugin with collect amount', async (t) => {
);
});

test('it can remove asset external plugin with collect amount', async (t) => {
const umi = await createUmi();
const asset = await createAsset(umi, {
plugins: [
{
type: 'AppData',
dataAuthority: { type: 'UpdateAuthority' },
schema: ExternalPluginAdapterSchema.Json,
},
],
});

t.assert(
await hasCollectAmount(umi, asset.publicKey),
'Collect amount not found'
);

await removePlugin(umi, {
asset: asset.publicKey,
plugin: { type: 'AppData', dataAuthority: { type: 'UpdateAuthority' } },
}).sendAndConfirm(umi);
t.assert(
await hasCollectAmount(umi, asset.publicKey),
'Collect amount not found'
);
});

test.serial('it can collect', async (t) => {
const umi = await createUmi();
const asset = await createAsset(umi);
Expand All @@ -110,6 +171,236 @@ test.serial('it can collect', async (t) => {
t.deepEqual(subtractAmounts(balEnd2, balStart2), sol(0.0015 / 2));
});

test.serial('it can collect from an asset with plugins', async (t) => {
const umi = await createUmi();
const asset = await createAsset(umi, {
plugins: [
{
type: 'FreezeDelegate',
frozen: false,
},
{
type: 'Attributes',
attributeList: [
{
key: 'Test',
value: 'Test',
},
],
},
],
});
const balStart1 = await umi.rpc.getBalance(recipient1);
const balStart2 = await umi.rpc.getBalance(recipient2);
await collect(umi, {})
.addRemainingAccounts({
isSigner: false,
isWritable: true,
pubkey: asset.publicKey,
})
.sendAndConfirm(umi);
const balEnd1 = await umi.rpc.getBalance(recipient1);
const balEnd2 = await umi.rpc.getBalance(recipient2);
t.is(await hasCollectAmount(umi, asset.publicKey), false);
t.deepEqual(subtractAmounts(balEnd1, balStart1), sol(0.0015 / 2));
t.deepEqual(subtractAmounts(balEnd2, balStart2), sol(0.0015 / 2));

t.assert(await assertNoExcessRent(umi, asset.publicKey), 'Excess rent found');
});

test.serial('it can collect from an asset with external plugins', async (t) => {
const umi = await createUmi();
const account = generateSigner(umi);

// write to example program oracle account
await fixedAccountInit(umi, {
account,
signer: umi.identity,
payer: umi.identity,
args: {
oracleData: {
__kind: 'V1',
create: ExternalValidationResult.Pass,
update: ExternalValidationResult.Rejected,
transfer: ExternalValidationResult.Pass,
burn: ExternalValidationResult.Pass,
},
},
}).sendAndConfirm(umi);

const asset = await createAsset(umi, {
plugins: [
{
type: 'FreezeDelegate',
frozen: false,
},
{
type: 'Attributes',
attributeList: [
{
key: 'Test',
value: 'Test',
},
],
},
{
type: 'Oracle',
resultsOffset: {
type: 'Anchor',
},
lifecycleChecks: {
create: [CheckResult.CAN_REJECT],
transfer: [CheckResult.CAN_REJECT],
},
baseAddress: account.publicKey,
},
],
});
const balStart1 = await umi.rpc.getBalance(recipient1);
const balStart2 = await umi.rpc.getBalance(recipient2);
await collect(umi, {})
.addRemainingAccounts({
isSigner: false,
isWritable: true,
pubkey: asset.publicKey,
})
.sendAndConfirm(umi);
const balEnd1 = await umi.rpc.getBalance(recipient1);
const balEnd2 = await umi.rpc.getBalance(recipient2);
t.is(await hasCollectAmount(umi, asset.publicKey), false);
t.deepEqual(subtractAmounts(balEnd1, balStart1), sol(0.0015 / 2));
t.deepEqual(subtractAmounts(balEnd2, balStart2), sol(0.0015 / 2));

t.assert(await assertNoExcessRent(umi, asset.publicKey), 'Excess rent found');
});

test.serial(
'it can collect from an asset with plugins that was burned',
async (t) => {
const umi = await createUmi();
const asset = await createAsset(umi, {
plugins: [
{
type: 'FreezeDelegate',
frozen: false,
},
{
type: 'Attributes',

attributeList: [
{
key: 'Test',
value: 'Test',
},
],
},
],
});
const balStart1 = await umi.rpc.getBalance(recipient1);
const balStart2 = await umi.rpc.getBalance(recipient2);

await burnV1(umi, {
asset: asset.publicKey,
}).sendAndConfirm(umi);

await collect(umi, {})
.addRemainingAccounts({
isSigner: false,
isWritable: true,
pubkey: asset.publicKey,
})
.sendAndConfirm(umi);
const balEnd1 = await umi.rpc.getBalance(recipient1);
const balEnd2 = await umi.rpc.getBalance(recipient2);
t.is(await hasCollectAmount(umi, asset.publicKey), false);
t.deepEqual(subtractAmounts(balEnd1, balStart1), sol(0.0015 / 2));
t.deepEqual(subtractAmounts(balEnd2, balStart2), sol(0.0015 / 2));

t.assert(
await assertNoExcessRent(umi, asset.publicKey),
'Excess rent found'
);
}
);

test.serial(
'it can collect from an asset with external plugins that was burned',
async (t) => {
const umi = await createUmi();
const account = generateSigner(umi);

// write to example program oracle account
await fixedAccountInit(umi, {
account,
signer: umi.identity,
payer: umi.identity,
args: {
oracleData: {
__kind: 'V1',
create: ExternalValidationResult.Pass,
update: ExternalValidationResult.Rejected,
transfer: ExternalValidationResult.Pass,
burn: ExternalValidationResult.Pass,
},
},
}).sendAndConfirm(umi);

const asset = await createAsset(umi, {
plugins: [
{
type: 'FreezeDelegate',
frozen: false,
},
{
type: 'Attributes',

attributeList: [
{
key: 'Test',
value: 'Test',
},
],
},
{
type: 'Oracle',
resultsOffset: {
type: 'Anchor',
},
lifecycleChecks: {
create: [CheckResult.CAN_REJECT],
transfer: [CheckResult.CAN_REJECT],
},
baseAddress: account.publicKey,
},
],
});
const balStart1 = await umi.rpc.getBalance(recipient1);
const balStart2 = await umi.rpc.getBalance(recipient2);

await burnV1(umi, {
asset: asset.publicKey,
}).sendAndConfirm(umi);

await collect(umi, {})
.addRemainingAccounts({
isSigner: false,
isWritable: true,
pubkey: asset.publicKey,
})
.sendAndConfirm(umi);
const balEnd1 = await umi.rpc.getBalance(recipient1);
const balEnd2 = await umi.rpc.getBalance(recipient2);
t.is(await hasCollectAmount(umi, asset.publicKey), false);
t.deepEqual(subtractAmounts(balEnd1, balStart1), sol(0.0015 / 2));
t.deepEqual(subtractAmounts(balEnd2, balStart2), sol(0.0015 / 2));

t.assert(
await assertNoExcessRent(umi, asset.publicKey),
'Excess rent found'
);
}
);

test.serial('it can collect burned asset', async (t) => {
const umi = await createUmi();
const asset = await createAsset(umi);
Expand All @@ -132,6 +423,8 @@ test.serial('it can collect burned asset', async (t) => {
t.is(await hasCollectAmount(umi, asset.publicKey), false);
t.deepEqual(subtractAmounts(balEnd1, balStart1), sol(0.0015 / 2));
t.deepEqual(subtractAmounts(balEnd2, balStart2), sol(0.0015 / 2));

t.assert(await assertNoExcessRent(umi, asset.publicKey), 'Excess rent found');
});

test.serial(
Expand Down Expand Up @@ -165,6 +458,11 @@ test.serial(
t.is(await hasCollectAmount(umi, asset.publicKey), false);
t.deepEqual(subtractAmounts(balEnd1, balStart1), sol(0.0015 / 2));
t.deepEqual(subtractAmounts(balEnd2, balStart2), sol(0.0015 / 2));

t.assert(
await assertNoExcessRent(umi, asset.publicKey),
'Excess rent found'
);
}
);

Expand Down Expand Up @@ -201,6 +499,8 @@ test.serial('it can collect multiple assets at once', async (t) => {
t.is(await hasCollectAmount(umi, asset3.publicKey), false);
t.deepEqual(subtractAmounts(balEnd1, balStart1), sol((0.0015 / 2) * 3));
t.deepEqual(subtractAmounts(balEnd2, balStart2), sol((0.0015 / 2) * 3));

t.assert(await assertNoExcessRent(umi, asset.publicKey), 'Excess rent found');
});

test('it can transfer after collecting', async (t) => {
Expand All @@ -226,4 +526,6 @@ test('it can transfer after collecting', async (t) => {
owner: newOwner.publicKey,
updateAuthority: { type: 'Address', address: umi.identity.publicKey },
});

t.assert(await assertNoExcessRent(umi, asset.publicKey), 'Excess rent found');
});
Loading

0 comments on commit a8d6807

Please sign in to comment.