diff --git a/js/cli/package.json b/js/cli/package.json index bf9aa11c..9736c140 100644 --- a/js/cli/package.json +++ b/js/cli/package.json @@ -1,6 +1,6 @@ { "name": "@raindrops-protocol/raindrops-cli", - "version": "0.5.7", + "version": "0.5.8", "license": "Apache-2.0", "bin": { "boot-up": "./src/boot_up.ts", diff --git a/js/lib/package.json b/js/lib/package.json index ca5e4180..25516dca 100644 --- a/js/lib/package.json +++ b/js/lib/package.json @@ -1,6 +1,6 @@ { "name": "@raindrops-protocol/raindrops", - "version": "0.5.7", + "version": "0.5.8", "module": "./build/main.js", "main": "./build/main.js", "types": "./build/main.d.ts", diff --git a/js/lib/src/contract/avatar/rpc/avatar.ts b/js/lib/src/contract/avatar/rpc/avatar.ts index 11c5fdc8..1f00a424 100644 --- a/js/lib/src/contract/avatar/rpc/avatar.ts +++ b/js/lib/src/contract/avatar/rpc/avatar.ts @@ -848,7 +848,9 @@ export class AvatarClient { ); const ixArgs = { - variantMetadata: args.variantMetadata ? args.variantMetadata : null, + variantMetadata: args.variantMetadata + ? args.variantMetadata.formatForIx() + : null, variantOption: args.variantOption ? args.variantOption.formatForIx() : null, diff --git a/rust/itemv2/src/state/accounts.rs b/rust/itemv2/src/state/accounts.rs index 1142adda..bfa26371 100644 --- a/rust/itemv2/src/state/accounts.rs +++ b/rust/itemv2/src/state/accounts.rs @@ -256,15 +256,21 @@ impl Build { .any(|mint_data| mint_data.mint.eq(&ingredient_mint)) { build_ingredient_data.current_amount += amount; + + // dont allow builders to put in more than the required amount + require!( + build_ingredient_data.current_amount <= build_ingredient_data.required_amount, + ErrorCode::IncorrectIngredient + ); + found = true; break; } } - if found { - Ok(()) - } else { - Err(ErrorCode::IncorrectIngredient.into()) - } + + require!(found, ErrorCode::IncorrectIngredient); + + Ok(()) } pub fn decrement_build_amount(&mut self, ingredient_mint: Pubkey, amount: u64) -> Result<()> { diff --git a/rust/tests/itemv2.ts b/rust/tests/itemv2.ts index b82d64b7..4a938c99 100644 --- a/rust/tests/itemv2.ts +++ b/rust/tests/itemv2.ts @@ -13,7 +13,6 @@ import * as splToken from "@solana/spl-token"; import * as cmp from "@solana/spl-account-compression"; import * as mplAuth from "@metaplex-foundation/mpl-token-auth-rules"; import { assert } from "chai"; -import { encode } from "@msgpack/msgpack"; import fs from "fs"; import path from "path"; @@ -3093,6 +3092,91 @@ describe("itemv2", () => { console.log("releaseFromEscrowTxSig: %s", result.txid); } }); + + it("do not allow builder to add more than required amount for an ingredient", async () => { + const payer = await newPayer(connection); + + const itemProgram = await ItemProgramV2.getProgramWithConfig( + ItemProgramV2, + { + asyncSigning: false, + provider: new anchor.AnchorProvider( + connection, + new anchor.Wallet(payer), + { commitment: "confirmed" } + ), + idl: Idls.ItemV2IDL, + } + ); + + // ingredient 1, nft + const nftItemClass = await createItemClassCollectionMode( + payer, + connection, + 2, + false + ); + + // output nft + const outputItemClass = await createItemClassCollectionMode( + payer, + connection, + 1, + false, + { + buildEnabled: true, + payment: null, + ingredientArgs: [ + { + itemClass: nftItemClass.itemClass, + requiredAmount: new BN(1), + buildEffect: { + degradation: null, + cooldown: null, + }, + isDeterministic: false, + }, + ], + buildPermitRequired: false, + selectableOutputs: [], + } + ); + + // start the build process + const startBuildAccounts: Instructions.ItemV2.StartBuildAccounts = { + itemClass: outputItemClass.itemClass, + builder: itemProgram.client.provider.publicKey, + }; + + const startBuildArgs: Instructions.ItemV2.StartBuildArgs = { + recipeIndex: new anchor.BN(0), + recipeOutputSelection: [], + }; + + const startBuildResult = await itemProgram.startBuild( + startBuildAccounts, + startBuildArgs + ); + console.log("startBuildTxSig: %s", startBuildResult.txid); + + // add ingredient to build using collection verification + await addIngredientCollection( + itemProgram, + outputItemClass.itemClass, + nftItemClass.mints[0], + nftItemClass.itemClass, + new anchor.BN(1) + ); + + // try to add second ingredient and this should fail because the recipe only requires 1 + assertRejects(addIngredientCollection( + itemProgram, + outputItemClass.itemClass, + nftItemClass.mints[1], + nftItemClass.itemClass, + new anchor.BN(1) + )); + }) }); async function newPayer(