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

Moving ATA checks to IX #6

Merged
merged 3 commits into from
Nov 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .github/workflows/build-programs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,5 @@ jobs:
name: program-builds
# First wildcard ensures exported paths are consistently under the programs folder.
path: ./program*/.bin/*.so
include-hidden-files: true
if-no-files-found: error
1 change: 1 addition & 0 deletions .github/workflows/build-rust-client.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,5 @@ jobs:
name: rust-client-builds
# First wildcard ensures exported paths are consistently under the clients folder.
path: ./targe*/release/*mpl_hybrid*
include-hidden-files: true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I don't think you need hidden files for this path because its not in .bin or "dot" anything so its not hidden.

if-no-files-found: error
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ dist
.yarn
programs/.bin
clients/js/output.json
mp14o4AQcmE5meFDxCscervMc1E4zyKEyDp3398PcwU.json
MPL4o4wMzndgh8T1NVDxELQCj5UQfYTYEkabX3wNKtb.json
Comment on lines +23 to +24
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you want these in the .gitignore? Seems like specific thing to add when I think normally they could be anywhere.

1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 39 additions & 0 deletions clients/js/src/generated/errors/mplHybrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,45 @@ export class InvalidUpdateAuthorityError extends ProgramError {
codeToErrorMap.set(0x177c, InvalidUpdateAuthorityError);
nameToErrorMap.set('InvalidUpdateAuthority', InvalidUpdateAuthorityError);

/** InvalidTokenAccount: Invalid Token Account */
export class InvalidTokenAccountError extends ProgramError {
override readonly name: string = 'InvalidTokenAccount';

readonly code: number = 0x177d; // 6013

constructor(program: Program, cause?: Error) {
super('Invalid Token Account', program, cause);
}
}
codeToErrorMap.set(0x177d, InvalidTokenAccountError);
nameToErrorMap.set('InvalidTokenAccount', InvalidTokenAccountError);

/** InvalidTokenAccountOwner: Invalid Token Account Owner */
export class InvalidTokenAccountOwnerError extends ProgramError {
override readonly name: string = 'InvalidTokenAccountOwner';

readonly code: number = 0x177e; // 6014

constructor(program: Program, cause?: Error) {
super('Invalid Token Account Owner', program, cause);
}
}
codeToErrorMap.set(0x177e, InvalidTokenAccountOwnerError);
nameToErrorMap.set('InvalidTokenAccountOwner', InvalidTokenAccountOwnerError);

/** InvalidTokenAccountMint: Invalid Token Account Mint */
export class InvalidTokenAccountMintError extends ProgramError {
override readonly name: string = 'InvalidTokenAccountMint';

readonly code: number = 0x177f; // 6015

constructor(program: Program, cause?: Error) {
super('Invalid Token Account Mint', program, cause);
}
}
codeToErrorMap.set(0x177f, InvalidTokenAccountMintError);
nameToErrorMap.set('InvalidTokenAccountMint', InvalidTokenAccountMintError);

/**
* Attempts to resolve a custom program error from the provided error code.
* @category Errors
Expand Down
48 changes: 47 additions & 1 deletion clients/js/test/capture.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ import test from 'ava';
import { generateSigner, publicKey } from '@metaplex-foundation/umi';
import {
createFungible,
fetchDigitalAssetWithAssociatedToken,
mintV1,
TokenStandard,
} from '@metaplex-foundation/mpl-token-metadata';
import {
string,
publicKey as publicKeySerializer,
} from '@metaplex-foundation/umi/serializers';
import { addCollectionPlugin, transfer } from '@metaplex-foundation/mpl-core';
import {
addCollectionPlugin,
fetchAsset,
transfer,
} from '@metaplex-foundation/mpl-core';
import {
captureV1,
EscrowV1,
Expand Down Expand Up @@ -94,6 +99,26 @@ test('it can swap tokens for an asset', async (t) => {
solFeeAmount: 1_000_000n,
});

const userTokenBefore = await fetchDigitalAssetWithAssociatedToken(
umi,
tokenMint.publicKey,
umi.identity.publicKey
);
t.deepEqual(userTokenBefore.token.amount, 1000n);
try {
await fetchDigitalAssetWithAssociatedToken(
umi,
tokenMint.publicKey,
publicKey(escrow)
);
t.fail('Escrow token account should not exist');
} catch (e) {
t.is(e.name, 'AccountNotFoundError');
}

const assetBefore = await fetchAsset(umi, assets[0].publicKey);
t.is(assetBefore.owner, publicKey(escrow));

await captureV1(umi, {
owner: umi.identity,
escrow,
Expand All @@ -102,6 +127,27 @@ test('it can swap tokens for an asset', async (t) => {
feeProjectAccount: escrowData.feeLocation,
token: tokenMint.publicKey,
}).sendAndConfirm(umi);

const escrowTokenAfter = await fetchDigitalAssetWithAssociatedToken(
umi,
tokenMint.publicKey,
publicKey(escrow)
);
t.deepEqual(escrowTokenAfter.token.amount, 5n);
const userTokenAfter = await fetchDigitalAssetWithAssociatedToken(
umi,
tokenMint.publicKey,
umi.identity.publicKey
);
t.deepEqual(userTokenAfter.token.amount, 994n);
const feeTokenAfter = await fetchDigitalAssetWithAssociatedToken(
umi,
tokenMint.publicKey,
escrowData.feeLocation
);
t.deepEqual(feeTokenAfter.token.amount, 1n);
const assetAfter = await fetchAsset(umi, assets[0].publicKey);
t.is(assetAfter.owner, umi.identity.publicKey);
});

test('it can swap tokens for an asset as UpdateDelegate', async (t) => {
Expand Down
71 changes: 70 additions & 1 deletion clients/js/test/release.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ import test from 'ava';
import { generateSigner, publicKey } from '@metaplex-foundation/umi';
import {
createFungible,
fetchDigitalAssetWithAssociatedToken,
mintV1,
TokenStandard,
} from '@metaplex-foundation/mpl-token-metadata';
import {
string,
publicKey as publicKeySerializer,
} from '@metaplex-foundation/umi/serializers';
import { addCollectionPlugin } from '@metaplex-foundation/mpl-core';
import { addCollectionPlugin, fetchAsset } from '@metaplex-foundation/mpl-core';
import {
EscrowV1,
fetchEscrowV1,
Expand Down Expand Up @@ -83,6 +84,25 @@ test('it can swap an asset for tokens', async (t) => {
solFeeAmount: 1_000_000n,
});

const escrowTokenBefore = await fetchDigitalAssetWithAssociatedToken(
umi,
tokenMint.publicKey,
publicKey(escrow)
);
t.deepEqual(escrowTokenBefore.token.amount, 1000n);
try {
await fetchDigitalAssetWithAssociatedToken(
umi,
tokenMint.publicKey,
umi.identity.publicKey
);
t.fail('User token account should not exist');
} catch (e) {
t.is(e.name, 'AccountNotFoundError');
}

t.is(assets[0].owner, umi.identity.publicKey);

await releaseV1(umi, {
owner: umi.identity,
escrow,
Expand All @@ -91,6 +111,21 @@ test('it can swap an asset for tokens', async (t) => {
feeProjectAccount: escrowData.feeLocation,
token: tokenMint.publicKey,
}).sendAndConfirm(umi);

const escrowTokenAfter = await fetchDigitalAssetWithAssociatedToken(
umi,
tokenMint.publicKey,
publicKey(escrow)
);
t.deepEqual(escrowTokenAfter.token.amount, 995n);
const userTokenAfter = await fetchDigitalAssetWithAssociatedToken(
umi,
tokenMint.publicKey,
umi.identity.publicKey
);
t.deepEqual(userTokenAfter.token.amount, 5n);
const assetAfter = await fetchAsset(umi, assets[0].publicKey);
t.is(assetAfter.owner, publicKey(escrow));
});

test('it can swap an asset for tokens as UpdateDelegate', async (t) => {
Expand Down Expand Up @@ -167,6 +202,25 @@ test('it can swap an asset for tokens as UpdateDelegate', async (t) => {
solFeeAmount: 1_000_000n,
});

const escrowTokenBefore = await fetchDigitalAssetWithAssociatedToken(
umi,
tokenMint.publicKey,
publicKey(escrow)
);
t.deepEqual(escrowTokenBefore.token.amount, 1000n);
try {
await fetchDigitalAssetWithAssociatedToken(
umi,
tokenMint.publicKey,
umi.identity.publicKey
);
t.fail('User token account should not exist');
} catch (e) {
t.is(e.name, 'AccountNotFoundError');
}

t.is(assets[0].owner, umi.identity.publicKey);

await releaseV1(umi, {
owner: umi.identity,
authority: escrow,
Expand All @@ -176,4 +230,19 @@ test('it can swap an asset for tokens as UpdateDelegate', async (t) => {
feeProjectAccount: escrowData.feeLocation,
token: tokenMint.publicKey,
}).sendAndConfirm(umi);

const escrowTokenAfter = await fetchDigitalAssetWithAssociatedToken(
umi,
tokenMint.publicKey,
publicKey(escrow)
);
t.deepEqual(escrowTokenAfter.token.amount, 995n);
const userTokenAfter = await fetchDigitalAssetWithAssociatedToken(
umi,
tokenMint.publicKey,
umi.identity.publicKey
);
t.deepEqual(userTokenAfter.token.amount, 5n);
const assetAfter = await fetchAsset(umi, assets[0].publicKey);
t.is(assetAfter.owner, publicKey(escrow));
});
9 changes: 9 additions & 0 deletions clients/rust/src/generated/errors/mpl_hybrid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,15 @@ pub enum MplHybridError {
/// 6012 (0x177C) - Invalid Update Authority
#[error("Invalid Update Authority")]
InvalidUpdateAuthority,
/// 6013 (0x177D) - Invalid Token Account
#[error("Invalid Token Account")]
InvalidTokenAccount,
/// 6014 (0x177E) - Invalid Token Account Owner
#[error("Invalid Token Account Owner")]
InvalidTokenAccountOwner,
/// 6015 (0x177F) - Invalid Token Account Mint
#[error("Invalid Token Account Mint")]
InvalidTokenAccountMint,
}

impl solana_program::program_error::PrintProgramError for MplHybridError {
Expand Down
15 changes: 15 additions & 0 deletions idls/mpl_hybrid.json
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,21 @@
"code": 6012,
"name": "InvalidUpdateAuthority",
"msg": "Invalid Update Authority"
},
{
"code": 6013,
"name": "InvalidTokenAccount",
"msg": "Invalid Token Account"
},
{
"code": 6014,
"name": "InvalidTokenAccountOwner",
"msg": "Invalid Token Account Owner"
},
{
"code": 6015,
"name": "InvalidTokenAccountMint",
"msg": "Invalid Token Account Mint"
}
],
"metadata": {
Expand Down
19 changes: 11 additions & 8 deletions programs/mpl-hybrid/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,34 +1,37 @@
[package]
name = "mpl-hybrid-program"
version = "0.0.1"
description = "The MPL Hybrid program"
edition = "2021"
name = "mpl-hybrid-program"
version = "0.0.1"

[lib]
crate-type = ["cdylib", "lib"]
name = "mpl_hybrid"

[features]
cpi = ["no-entrypoint"]
default = []
no-entrypoint = []
no-idl = []
no-log-ix-name = []
cpi = ["no-entrypoint"]
default = []
# idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]

[dependencies]
anchor-lang = { version = "~0.29", features = ["init-if-needed"] }
anchor-spl = { version = "~0.29" }
arrayref = "0.3.6"
getrandom = { version = "0.2.9", features = ["custom"] }
mpl-core = "0.7.1"
mpl-utils = "0.3.5"
solana-program = "=1.17.22"
winnow = "=0.4.1"
toml_datetime = "=0.6.5"
spl-associated-token-account = { version = "2.3.0", features = [
"no-entrypoint",
] }
spl-token = { version = "3.2.0", features = ["no-entrypoint"] }
spl-token-2022 = { version = "~1.0", features = ["no-entrypoint"] }
spl-token-metadata-interface = { version = "0.2.0" }
mpl-core = "0.7.1"
mpl-utils = "0.3.5"
toml_datetime = "=0.6.5"
winnow = "=0.4.1"

[dev-dependencies]
proptest = { version = "1.0" }
Loading
Loading