@verxioprotocol/core
Version:
Opensource infrastructure powering on-chain loyalty across Solana with Metaplex Core
1 lines • 71.8 kB
JavaScript
"use strict";var z=Object.defineProperty;var W=(e,t,r)=>t in e?z(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r;var B=(e,t,r)=>W(e,typeof t!="symbol"?t+"":t,r);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const E=require("@metaplex-foundation/umi"),u=require("@metaplex-foundation/mpl-core");require("@solana/web3.js");const X=require("@metaplex-foundation/mpl-toolbox"),b={name:"Grind",rewards:["nothing for you!"],xpRequired:0},L={totalBroadcasts:0,broadcasts:[]},S={totalVouchersIssued:0,totalVouchersRedeemed:0,totalValueRedeemed:0,voucherStats:[]},_={xp:0,lastAction:null,actionHistory:[],messageHistory:[],currentTier:b.name,tierUpdatedAt:Date.now(),rewards:b.rewards},h={ATTRIBUTES:"Attributes",APP_DATA:"AppData",PERMANENT_TRANSFER_DELEGATE:"PermanentTransferDelegate",UPDATE_DELEGATE:"UpdateDelegate",FREEZE_DELEGATE:"FreezeDelegate"},p={PROGRAM_TYPE:"programType",TIERS:"tiers",POINTS_PER_ACTION:"pointsPerAction",CREATOR:"creator",TYPE:"type",XP:"xp",METADATA:"metadata",VOUCHER_TYPES:"voucherTypes",MERCHANT_ID:"merchantId"};class j extends Error{constructor(r,i,a){const s=`Expected a string of base ${i}, got [${r}].`;super(s);B(this,"name","InvalidBaseStringError");this.cause=a}}const Z=e=>{const t=e.length,r=BigInt(t);return{description:`base${t}`,fixedSize:null,maxSize:null,serialize(i){if(!i.match(new RegExp(`^[${e}]*$`)))throw new j(i,t);if(i==="")return new Uint8Array;const a=[...i];let s=a.findIndex(y=>y!==e[0]);s=s===-1?a.length:s;const o=Array(s).fill(0);if(s===a.length)return Uint8Array.from(o);const n=a.slice(s);let d=0n,l=1n;for(let y=n.length-1;y>=0;y-=1)d+=l*BigInt(e.indexOf(n[y])),l*=r;const m=[];for(;d>0n;)m.unshift(Number(d%256n)),d/=256n;return Uint8Array.from(o.concat(m))},deserialize(i,a=0){if(i.length===0)return["",0];const s=i.slice(a);let o=s.findIndex(m=>m!==0);o=o===-1?s.length:o;const n=e[0].repeat(o);if(o===s.length)return[n,i.length];let d=s.slice(o).reduce((m,y)=>m*256n+BigInt(y),0n);const l=[];for(;d>0n;)l.unshift(e[Number(d%r)]),d/=r;return[n+l.join(""),i.length]}}},Q=Z("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz");function g(e){return Q.deserialize(e)[0]}function D(e){if(!e)throw new Error("assertValidContext: Context is undefined");if(!e.umi)throw new Error("assertValidContext: UMI is undefined");if(!e.programAuthority)throw new Error("assertValidContext: Program authority is undefined");return!0}const ee={CREATE_LOYALTY_PROGRAM:.002,CREATE_VOUCHER_COLLECTION:.002,LOYALTY_OPERATIONS:.001,VERXIO_INTERACTION:4e-4},te=E.publicKey("3DdcJkvjW7KLtMeko3Zr57jEJWhqRHuPsEBFm1XJYh7W");function w(e,t,r){return X.transferSol(e,{source:t,destination:te,amount:E.sol(ee[r])})}async function O(e,t){try{if(!t||!t.imageUri||!t.creator)throw new Error("Missing required data for metadata generation");const r={name:t.loyaltyProgramName,symbol:"VERXIO",description:`Loyalty Program for ${t.metadata.organizationName}`,image:t.imageUri,properties:{files:[{uri:t.imageUri,type:t.mimeType||"image/png"}],category:"image",creators:[{address:t.creator.toString(),share:100}]},attributes:[{trait_type:"Organization",value:t.metadata.organizationName},{trait_type:"Program Type",value:"Loyalty Program"},{trait_type:"Tiers",value:t.tiers.length.toString()},...t.metadata.brandColor?[{trait_type:"Brand Color",value:t.metadata.brandColor}]:[]],program:{name:t.loyaltyProgramName,metadata:t.metadata,tiers:t.tiers,pointsPerAction:t.pointsPerAction}};return await e.umi.uploader.uploadJson(r)}catch(r){throw console.error("Error generating loyalty program metadata:",r),new Error("Failed to generate loyalty program metadata")}}async function M(e,t){try{if(!t||!t.imageUri||!t.creator)throw new Error("Missing required data for pass metadata generation");const r={name:t.passName,symbol:"VERXIO-PASS",description:`Loyalty Pass for ${t.organizationName}`,image:t.imageUri,properties:{files:[{uri:t.imageUri,type:t.mimeType||"image/png"}],category:"image",creators:[{address:t.creator.toString(),share:100}]},attributes:[{trait_type:"Organization",value:t.organizationName},{trait_type:"Pass Type",value:"Loyalty Pass"},{trait_type:"Status",value:"Active"}]};return await e.umi.uploader.uploadJson(r)}catch(r){throw console.error("Error generating loyalty pass metadata:",r),new Error("Failed to generate loyalty pass metadata")}}async function k(e,t){try{if(!t||!t.imageUri||!t.creator)throw new Error("Missing required data for collection metadata generation");const r={name:t.collectionName,symbol:"VERXIO-VOUCHER",description:t.description,image:t.imageUri,properties:{files:[{uri:t.imageUri,type:t.mimeType||"image/png"}],category:"image",creators:[{address:t.creator.toString(),share:100}]},attributes:[{trait_type:"Merchant",value:t.merchantName},{trait_type:"Collection Type",value:"Voucher Collection"},{trait_type:"Status",value:"Active"}]};return await e.umi.uploader.uploadJson(r)}catch(r){throw console.error("Error generating voucher collection metadata:",r),new Error("Failed to generate voucher collection metadata")}}async function F(e,t){try{if(!t||!t.imageUri||!t.creator)throw new Error("Missing required data for voucher metadata generation");const r={name:t.voucherName,symbol:"VERXIO-VOUCHER",description:t.voucherData.description,image:t.imageUri,properties:{files:[{uri:t.imageUri,type:t.mimeType||"image/png"}],category:"image",creators:[{address:t.creator.toString(),share:100}]},attributes:[{trait_type:"Voucher Type",value:t.voucherData.type},{trait_type:"Value",value:t.voucherData.value.toString()},{trait_type:"Merchant ID",value:t.voucherData.merchantId},{trait_type:"Status",value:"Active"}]};return await e.umi.uploader.uploadJson(r)}catch(r){throw console.error("Error generating voucher metadata:",r),new Error("Failed to generate voucher metadata")}}async function T(e,t,r,i="image/png"){try{if(!t)throw new Error("Image buffer is required");if(!r||typeof r!="string")throw new Error("Valid filename is required");if(!e||!e.umi||!e.umi.uploader)throw new Error("Valid context with uploader is required");const a=E.createGenericFile(t,r,{contentType:i}),[s]=await e.umi.uploader.upload([a]);return s}catch(a){throw console.error("Error uploading image:",a),new Error("Failed to upload image")}}async function re(e,t){D(e),ae(t);const r=t.collectionSigner??E.generateSigner(e.umi),i=t.updateAuthority??E.generateSigner(e.umi);try{let a=t.metadataUri;if(!a){if(!t.imageBuffer||!t.imageFilename)throw new Error("Either metadataUri or imageBuffer with imageFilename must be provided");const d=await T(e,t.imageBuffer,t.imageFilename,t.imageContentType);a=await O(e,{loyaltyProgramName:t.loyaltyProgramName,metadata:t.metadata,tiers:t.tiers,pointsPerAction:t.pointsPerAction,imageUri:d,creator:t.programAuthority,mimeType:t.imageContentType})}const s=w(e.umi,e.umi.identity.publicKey,"CREATE_LOYALTY_PROGRAM"),n=await u.createCollection(e.umi,{collection:r,name:t.loyaltyProgramName,plugins:K(t,i.publicKey),uri:a,updateAuthority:i.publicKey}).add(s).add(u.writeCollectionExternalPluginAdapterDataV1(e.umi,{collection:r.publicKey,authority:i,key:{__kind:h.APP_DATA,fields:[{__kind:"Address",address:i.publicKey}]},data:new TextEncoder().encode(JSON.stringify(L))})).sendAndConfirm(e.umi,{confirm:{commitment:"confirmed"}});return{collection:r,signature:g(n.signature),updateAuthority:i}}catch(a){throw new Error(`Failed to create loyalty program: ${a}`)}}function K(e,t){return[{type:h.ATTRIBUTES,attributeList:[{key:p.PROGRAM_TYPE,value:"loyalty"},{key:p.TIERS,value:JSON.stringify(e.tiers)},{key:p.POINTS_PER_ACTION,value:JSON.stringify(e.pointsPerAction)},{key:p.CREATOR,value:e.programAuthority.toString()},{key:p.METADATA,value:JSON.stringify(e.metadata)}]},{type:h.PERMANENT_TRANSFER_DELEGATE,authority:{address:e.programAuthority,type:"Address"}},{type:h.UPDATE_DELEGATE,authority:{address:t,type:"Address"},additionalDelegates:[]},{type:h.APP_DATA,dataAuthority:{type:"Address",address:t},schema:u.ExternalPluginAdapterSchema.Json}]}function ae(e){if(!e)throw new Error("assertValidCreateLoyaltyProgramConfig: Config is undefined");if(!e.loyaltyProgramName||!e.loyaltyProgramName.trim()||!e.loyaltyProgramName.trim().length)throw new Error("assertValidCreateLoyaltyProgramConfig: Loyalty program name is undefined");if(e.metadataUri){if(!e.metadataUri.trim()||!e.metadataUri.trim().length)throw new Error("assertValidCreateLoyaltyProgramConfig: Metadata URI is empty");if(!e.metadataUri.startsWith("https://")&&!e.metadataUri.startsWith("http://"))throw new Error("assertValidCreateLoyaltyProgramConfig: Metadata URI is not a valid URL")}else{if(!e.imageBuffer)throw new Error("assertValidCreateLoyaltyProgramConfig: Image buffer is required when metadataUri is not provided");if(!e.imageFilename||!e.imageFilename.trim())throw new Error("assertValidCreateLoyaltyProgramConfig: Image filename is required when metadataUri is not provided")}if(!e.programAuthority)throw new Error("assertValidCreateLoyaltyProgramConfig: Program authority is undefined");if(!e.updateAuthority)throw new Error("assertValidCreateLoyaltyProgramConfig: Update authority is undefined");if(!e.tiers||e.tiers.length===0)throw new Error("assertValidCreateLoyaltyProgramConfig: Tiers configuration is missing");if(!e.pointsPerAction||Object.keys(e.pointsPerAction).length===0)throw new Error("assertValidCreateLoyaltyProgramConfig: Points per action configuration is missing");if(!e.metadata)throw new Error("assertValidCreateLoyaltyProgramConfig: Metadata is undefined");if(!e.metadata.organizationName||!e.metadata.organizationName.trim()||!e.metadata.organizationName.trim().length)throw new Error("assertValidCreateLoyaltyProgramConfig: Organization name is undefined")}async function ie(e,t){D(e),se(t);const r=t.collectionSigner??E.generateSigner(e.umi),i=t.updateAuthority??E.generateSigner(e.umi);try{let a=t.metadataUri;if(!a){if(!t.imageBuffer||!t.imageFilename)throw new Error("Either metadataUri or imageBuffer with imageFilename must be provided");const d=await T(e,t.imageBuffer,t.imageFilename,t.imageContentType);a=await k(e,{collectionName:t.voucherCollectionName,merchantName:t.metadata.merchantName,description:t.description||`Voucher collection for ${t.metadata.merchantName}`,imageUri:d,creator:t.programAuthority,mimeType:t.imageContentType})}const s=w(e.umi,e.umi.identity.publicKey,"CREATE_VOUCHER_COLLECTION"),n=await u.createCollection(e.umi,{collection:r,name:t.voucherCollectionName,plugins:G(t,i.publicKey),uri:a,updateAuthority:i.publicKey}).add(s).add(u.writeCollectionExternalPluginAdapterDataV1(e.umi,{collection:r.publicKey,authority:i,key:{__kind:h.APP_DATA,fields:[{__kind:"Address",address:i.publicKey}]},data:new TextEncoder().encode(JSON.stringify(S))})).sendAndConfirm(e.umi,{confirm:{commitment:"confirmed"}});return{collection:r,signature:g(n.signature),updateAuthority:i}}catch(a){throw new Error(`Failed to create voucher collection: ${a}`)}}function G(e,t){return[{type:h.ATTRIBUTES,attributeList:[{key:p.PROGRAM_TYPE,value:"voucher"},{key:p.CREATOR,value:e.programAuthority.toString()},{key:p.METADATA,value:JSON.stringify(e.metadata)},{key:"voucherTypes",value:JSON.stringify(e.metadata.voucherTypes)},{key:"merchantId",value:e.metadata.merchantAddress}]},{type:h.PERMANENT_TRANSFER_DELEGATE,authority:{address:e.programAuthority,type:"Address"}},{type:h.UPDATE_DELEGATE,authority:{address:t,type:"Address"},additionalDelegates:[]},{type:h.APP_DATA,dataAuthority:{type:"Address",address:t},schema:u.ExternalPluginAdapterSchema.Json}]}function se(e){if(!e)throw new Error("assertValidCreateVoucherCollectionConfig: Config is undefined");if(!e.voucherCollectionName||!e.voucherCollectionName.trim()||!e.voucherCollectionName.trim().length)throw new Error("assertValidCreateVoucherCollectionConfig: Voucher collection name is undefined");if(e.metadataUri){if(!e.metadataUri.trim()||!e.metadataUri.trim().length)throw new Error("assertValidCreateVoucherCollectionConfig: Metadata URI is empty");if(!e.metadataUri.startsWith("https://")&&!e.metadataUri.startsWith("http://"))throw new Error("assertValidCreateVoucherCollectionConfig: Metadata URI is not a valid URL")}else{if(!e.imageBuffer)throw new Error("assertValidCreateVoucherCollectionConfig: Image buffer is required when metadataUri is not provided");if(!e.imageFilename||!e.imageFilename.trim())throw new Error("assertValidCreateVoucherCollectionConfig: Image filename is required when metadataUri is not provided")}if(!e.programAuthority)throw new Error("assertValidCreateVoucherCollectionConfig: Program authority is undefined");if(!e.metadata)throw new Error("assertValidCreateVoucherCollectionConfig: Metadata is undefined");if(!e.metadata.merchantName||!e.metadata.merchantName.trim()||!e.metadata.merchantName.trim().length)throw new Error("assertValidCreateVoucherCollectionConfig: Merchant name is undefined");if(!e.metadata.merchantAddress||!e.metadata.merchantAddress.trim()||!e.metadata.merchantAddress.trim().length)throw new Error("assertValidCreateVoucherCollectionConfig: Merchant address is undefined");if(!e.metadata.voucherTypes||!Array.isArray(e.metadata.voucherTypes)||e.metadata.voucherTypes.length===0)throw new Error("assertValidCreateVoucherCollectionConfig: Voucher types are undefined or empty")}async function oe(e,t){ne(t);try{const r=t.assetSigner??E.generateSigner(e.umi);let i=t.voucherMetadataUri;if(!i){if(!t.imageBuffer||!t.imageFilename)throw new Error("Either voucherMetadataUri or imageBuffer with imageFilename must be provided");const d=await T(e,t.imageBuffer,t.imageFilename,t.imageContentType);i=await F(e,{voucherName:t.voucherName,voucherData:t.voucherData,imageUri:d,creator:t.updateAuthority.publicKey,mimeType:t.imageContentType})}const a=w(e.umi,e.umi.identity.publicKey,"LOYALTY_OPERATIONS"),s={type:t.voucherData.type,value:t.voucherData.value,description:t.voucherData.description,expiryDate:t.voucherData.expiryDate,maxUses:t.voucherData.maxUses,currentUses:0,transferable:t.voucherData.transferable??!1,status:"active",issuedAt:Date.now(),merchantId:t.voucherData.merchantId,conditions:t.voucherData.conditions||[],redemptionHistory:[]},n=await u.create(e.umi,{asset:r,name:t.voucherName,uri:i,owner:t.recipient,authority:t.updateAuthority,collection:{publicKey:t.collectionAddress},plugins:[{type:h.APP_DATA,dataAuthority:{type:"Address",address:t.updateAuthority.publicKey},schema:u.ExternalPluginAdapterSchema.Json},{type:h.ATTRIBUTES,attributeList:[{key:p.TYPE,value:"voucher"},{key:"voucherType",value:t.voucherData.type},{key:"merchantId",value:t.voucherData.merchantId},{key:"transferable",value:s.transferable.toString()}]},{type:h.FREEZE_DELEGATE,authority:{type:"Address",address:t.updateAuthority.publicKey},frozen:!s.transferable}]}).add(a).add(u.writeData(e.umi,{key:{type:h.APP_DATA,dataAuthority:{type:"Address",address:t.updateAuthority.publicKey}},authority:t.updateAuthority,data:new TextEncoder().encode(JSON.stringify(s)),asset:E.publicKey(r.publicKey),collection:t.collectionAddress})).sendAndConfirm(e.umi,{confirm:{commitment:"confirmed"}});return{asset:r,signature:g(n.signature),voucherAddress:r.publicKey}}catch(r){throw new Error(`Failed to mint voucher: ${r}`)}}function ne(e){if(!e)throw new Error("assertValidMintVoucherConfig: Config is undefined");if(!e.collectionAddress)throw new Error("assertValidMintVoucherConfig: Collection address is undefined");if(!e.recipient)throw new Error("assertValidMintVoucherConfig: Recipient is undefined");if(!e.voucherName||!e.voucherName.trim()||!e.voucherName.trim().length)throw new Error("assertValidMintVoucherConfig: Voucher name is undefined");if(!e.updateAuthority)throw new Error("assertValidMintVoucherConfig: Update authority is undefined");if(!e.voucherData)throw new Error("assertValidMintVoucherConfig: Voucher data is undefined");if(!e.voucherData.type)throw new Error("assertValidMintVoucherConfig: Voucher type is undefined");if(typeof e.voucherData.value!="number"||e.voucherData.value<0)throw new Error("assertValidMintVoucherConfig: Voucher value must be a non-negative number");if(!e.voucherData.description||!e.voucherData.description.trim())throw new Error("assertValidMintVoucherConfig: Voucher description is undefined");if(typeof e.voucherData.expiryDate!="number"||e.voucherData.expiryDate<=Date.now())throw new Error("assertValidMintVoucherConfig: Voucher expiry date must be in the future");if(typeof e.voucherData.maxUses!="number"||e.voucherData.maxUses<=0)throw new Error("assertValidMintVoucherConfig: Voucher max uses must be a positive number");if(!e.voucherData.merchantId||!e.voucherData.merchantId.trim())throw new Error("assertValidMintVoucherConfig: Merchant ID is undefined");if(e.voucherMetadataUri){if(!e.voucherMetadataUri.trim()||!e.voucherMetadataUri.trim().length)throw new Error("assertValidMintVoucherConfig: Voucher metadata URI is empty");if(!e.voucherMetadataUri.startsWith("https://")&&!e.voucherMetadataUri.startsWith("http://"))throw new Error("assertValidMintVoucherConfig: Voucher metadata URI is not a valid URL")}else{if(!e.imageBuffer)throw new Error("assertValidMintVoucherConfig: Image buffer is required when voucherMetadataUri is not provided");if(!e.imageFilename||!e.imageFilename.trim())throw new Error("assertValidMintVoucherConfig: Image filename is required when voucherMetadataUri is not provided")}}async function R(e,t){var i;const r={errors:[]};try{const s=(i=(await u.fetchAsset(e.umi,t.voucherAddress)).appDatas)==null?void 0:i[0];if(!s||!s.data)return r.errors.push("Voucher data not found"),r;const o=s.data;return r.voucher=o,r}catch(a){return r.errors.push(`Failed to fetch voucher: ${a}`),r}}async function de(e,t){const r={success:!1,validation:{errors:[]},errors:[]};try{const i=await R(e,{voucherAddress:t.voucherAddress});if(r.validation=i,!i.voucher)return r.errors.push("Voucher validation failed"),r;if(i.voucher.merchantId!==t.merchantId)return r.errors.push("Voucher is not valid for merchant "+t.merchantId),r;const a=await u.fetchAsset(e.umi,t.voucherAddress),s=u.collectionAddress(a);console.log("Collection address:",s);const o=ue(i.voucher,t.redemptionAmount);r.redemptionValue=o;const n=le(i.voucher,o,t.redemptionDetails);r.updatedVoucher=n;const d=w(e.umi,e.umi.identity.publicKey,"LOYALTY_OPERATIONS"),m=await u.writeData(e.umi,{key:{type:h.APP_DATA,dataAuthority:{type:"Address",address:t.updateAuthority.publicKey}},authority:t.updateAuthority,data:new TextEncoder().encode(JSON.stringify(n)),asset:t.voucherAddress,collection:s}).add(d).sendAndConfirm(e.umi,{confirm:{commitment:"confirmed"}});return r.success=!0,r.signature=g(m.signature),r}catch(i){return r.errors.push(`Failed to redeem voucher: ${i}`),r}}function ue(e,t){switch(e.type){case"percentage_off":if(!t)throw new Error("Redemption amount required for percentage_off voucher");return t*e.value/100;case"fixed_verxio_credits":return e.value;case"free_item":return e.value;case"buy_one_get_one":return e.value;case"custom_reward":return e.value;default:return 0}}function le(e,t,r){const i={...e,currentUses:e.currentUses+1,usedAt:Date.now()};i.currentUses>=i.maxUses&&(i.status="used");const a={timestamp:Date.now(),redemptionValue:t,transactionId:r==null?void 0:r.transactionId,items:r==null?void 0:r.items,totalAmount:r==null?void 0:r.totalAmount,discountApplied:r==null?void 0:r.discountApplied,creditsUsed:r==null?void 0:r.creditsUsed};return i.redemptionHistory||(i.redemptionHistory=[]),i.redemptionHistory.push(a),i}function ce(e){switch(e.type){case"percentage_off":return`${e.value}% off`;case"fixed_verxio_credits":return`${e.value} Verxio Credits`;case"free_item":return`Free ${e.description}`;case"buy_one_get_one":return"Buy One Get One Free";case"custom_reward":return e.description;default:return e.description}}function me(e){return e.maxUses>1&&e.currentUses<e.maxUses}function ye(e){return Math.max(0,e.maxUses-e.currentUses)}async function he(e,t){var i;const r={success:!1,errors:[]};try{const a=await u.fetchAsset(e.umi,t.voucherAddress),s=u.collectionAddress(a),o=(i=a.appDatas)==null?void 0:i[0];if(!o||!o.data)return r.errors.push("Voucher data not found"),r;const n=o.data;if(n.status==="cancelled")return r.errors.push("Voucher is already cancelled"),r;if(n.status==="used")return r.errors.push("Cannot cancel a fully used voucher"),r;const d={...n,status:"cancelled",usedAt:Date.now()};r.updatedVoucher=d;const l=w(e.umi,e.umi.identity.publicKey,"LOYALTY_OPERATIONS"),y=await u.writeData(e.umi,{key:{type:h.APP_DATA,dataAuthority:{type:"Address",address:t.updateAuthority.publicKey}},authority:t.updateAuthority,data:new TextEncoder().encode(JSON.stringify(d)),asset:t.voucherAddress,collection:s}).add(l).sendAndConfirm(e.umi,{confirm:{commitment:"confirmed"}});return r.success=!0,r.signature=g(y.signature),r}catch(a){return r.errors.push(`Failed to cancel voucher: ${a}`),r}}async function pe(e,t){var i;Ae(t);const r={success:!1,errors:[]};try{const a=await u.fetchAsset(e.umi,t.voucherAddress),s=u.collectionAddress(a),o=(i=a.appDatas)==null?void 0:i[0];if(!o||!o.data)return r.errors.push("Voucher data not found"),r;const n=o.data;if(n.status==="cancelled")return r.errors.push("Cannot extend expiry of a cancelled voucher"),r;if(n.status==="used")return r.errors.push("Cannot extend expiry of a fully used voucher"),r;if(t.newExpiryDate<=Date.now())return r.errors.push("New expiry date must be in the future"),r;if(t.newExpiryDate<=n.expiryDate)return r.errors.push("New expiry date must be later than current expiry date"),r;r.previousExpiryDate=n.expiryDate;const d={...n,expiryDate:t.newExpiryDate,status:n.status==="expired"?"active":n.status};r.updatedVoucher=d;const l=w(e.umi,e.umi.identity.publicKey,"LOYALTY_OPERATIONS"),y=await u.writeData(e.umi,{key:{type:h.APP_DATA,dataAuthority:{type:"Address",address:t.updateAuthority.publicKey}},authority:t.updateAuthority,data:new TextEncoder().encode(JSON.stringify(d)),asset:t.voucherAddress,collection:s}).add(l).sendAndConfirm(e.umi,{confirm:{commitment:"confirmed"}});return r.success=!0,r.signature=g(y.signature),r}catch(a){return r.errors.push(`Failed to extend voucher expiry: ${a}`),r}}function J(e){const t=Date.now(),r=e.expiryDate-t;if(r<=0)return{isExpired:!0,timeRemaining:0,daysRemaining:0,hoursRemaining:0,minutesRemaining:0};const a=Math.floor(r/(24*60*60*1e3)),s=Math.floor(r%(24*60*60*1e3)/(60*60*1e3)),o=Math.floor(r%(60*60*1e3)/(60*1e3));return{isExpired:!1,timeRemaining:r,daysRemaining:a,hoursRemaining:s,minutesRemaining:o}}function we(e,t=7){const{daysRemaining:r}=J(e);return r<=t&&r>0}function Ae(e){if(!e)throw new Error("assertValidExtendVoucherExpiryConfig: Config is undefined");if(!e.voucherAddress)throw new Error("assertValidExtendVoucherExpiryConfig: Voucher address is undefined");if(!e.updateAuthority)throw new Error("assertValidExtendVoucherExpiryConfig: Update authority is undefined");if(!e.newExpiryDate||e.newExpiryDate<=0)throw new Error("assertValidExtendVoucherExpiryConfig: New expiry date must be a positive number")}async function x(e,t){var r;try{const a=(await u.fetchAssetsByOwner(e.umi,t.userAddress)).filter(m=>{const y=m.attributes;if(!y||!y.attributeList)return!1;const c=y.attributeList.find(A=>A.key===p.TYPE);return c&&c.value==="voucher"}),s=[],o={activeVouchers:0,expiredVouchers:0,usedVouchers:0,cancelledVouchers:0,totalValue:0,byType:{},byMerchant:{}};for(const m of a)try{const y=(r=m.appDatas)==null?void 0:r[0];if(!y||!y.data)continue;const c=y.data,A=Date.now(),f=c.expiryDate<=A,C=c.status==="active"&&!f&&c.currentUses<c.maxUses,N=Math.max(0,c.maxUses-c.currentUses),P=Math.max(0,c.expiryDate-A);if(t.collectionAddress&&m.collection!==t.collectionAddress||t.merchantId&&c.merchantId!==t.merchantId||t.status&&c.status!==t.status||t.voucherType&&c.type!==t.voucherType)continue;const q={voucherAddress:m.publicKey,voucherData:c,collectionAddress:m.collection,name:m.name,uri:m.uri,isExpired:f,canRedeem:C,remainingUses:N,timeUntilExpiry:P};switch(s.push(q),c.status){case"active":f?o.expiredVouchers++:o.activeVouchers++;break;case"used":o.usedVouchers++;break;case"cancelled":o.cancelledVouchers++;break;case"expired":o.expiredVouchers++;break}o.totalValue+=c.value,o.byType[c.type]=(o.byType[c.type]||0)+1,o.byMerchant[c.merchantId]=(o.byMerchant[c.merchantId]||0)+1}catch(y){console.warn("Error processing voucher asset:",y);continue}s.sort((m,y)=>m.voucherData.status==="active"&&y.voucherData.status!=="active"?-1:m.voucherData.status!=="active"&&y.voucherData.status==="active"?1:m.voucherData.expiryDate-y.voucherData.expiryDate);const n=t.offset||0,d=t.limit||50;return{vouchers:s.slice(n,n+d),totalCount:s.length,hasMore:n+d<s.length,summary:o}}catch(i){throw new Error(`Failed to get user vouchers: ${i}`)}}async function fe(e,t){const r=await x(e,t),a=(t.expiryWarningDays||7)*24*60*60*1e3;return r.vouchers.filter(s=>s.voucherData.status==="active"&&s.timeUntilExpiry>0&&s.timeUntilExpiry<=a)}async function Ee(e,t){return(await x(e,t)).vouchers.filter(i=>i.canRedeem)}function I(e){if(!e.collectionAddress)throw new Error("Collection not initialized")}async function V(e,t){var a,s;I(e);const i=(s=(a=(await u.fetchCollection(e.umi,e.collectionAddress)).attributes)==null?void 0:a.attributeList.find(o=>o.key===t))==null?void 0:s.value;return i?JSON.parse(i):null}async function v(e,t){return(await V(e,p.TIERS)||[]).reduce((i,a)=>t>=a.xpRequired&&(!i||a.xpRequired>i.xpRequired)?a:i,b)}async function U(e,t,r,i,a){const s=w(e.umi,e.umi.identity.publicKey,"VERXIO_INTERACTION"),o={xp:a.xp,lastAction:a.action,currentTier:a.newTier.name,tierUpdatedAt:a.newTier.name!==a.currentData.currentTier?Date.now():a.currentData.tierUpdatedAt,actionHistory:a.currentData.actionHistory||[],messageHistory:a.messageHistory||a.currentData.messageHistory||[],rewards:a.newTier.rewards||[]},n=new TextEncoder().encode(JSON.stringify(o)),l=await u.writeData(e.umi,{key:{type:h.APP_DATA,dataAuthority:i.dataAuthority},authority:r,data:n,asset:t,collection:e.collectionAddress}).add(s).sendAndConfirm(e.umi,{confirm:{commitment:"confirmed"}});return{points:a.xp,signature:g(l.signature)}}async function Y(e,t,r,i,a){const s=w(e.umi,e.umi.identity.publicKey,"VERXIO_INTERACTION"),o={broadcasts:a.broadcasts,totalBroadcasts:a.totalBroadcasts},n=new TextEncoder().encode(JSON.stringify(o)),l=await u.writeCollectionExternalPluginAdapterDataV1(e.umi,{collection:t,authority:r,key:{__kind:h.APP_DATA,fields:[{__kind:"Address",address:i.dataAuthority.address}]},data:n}).add(s).sendAndConfirm(e.umi,{confirm:{commitment:"confirmed"}});return{signature:g(l.signature)}}async function Ce(e,t){try{Ve(t);const r=t.assetSigner??E.generateSigner(e.umi);let i=t.passMetadataUri;if(!i){if(!t.imageBuffer||!t.imageFilename)throw new Error("Either passMetadataUri or imageBuffer with imageFilename must be provided");const n=await T(e,t.imageBuffer,t.imageFilename,t.imageContentType);i=await M(e,{passName:t.passName,organizationName:t.organizationName,imageUri:n,creator:t.updateAuthority.publicKey,mimeType:t.imageContentType})}const a=w(e.umi,e.umi.identity.publicKey,"LOYALTY_OPERATIONS"),o=await u.create(e.umi,{asset:r,name:t.passName,uri:i,owner:t.recipient,authority:t.updateAuthority,collection:{publicKey:t.collectionAddress},plugins:[{type:h.APP_DATA,dataAuthority:{type:"Address",address:t.updateAuthority.publicKey},schema:u.ExternalPluginAdapterSchema.Json},{type:h.ATTRIBUTES,attributeList:[{key:p.TYPE,value:`${t.passName} loyalty pass`}]}]}).add(a).add(u.writeData(e.umi,{key:{type:h.APP_DATA,dataAuthority:{type:"Address",address:t.updateAuthority.publicKey}},authority:t.updateAuthority,data:new TextEncoder().encode(JSON.stringify(_)),asset:E.publicKey(r.publicKey),collection:t.collectionAddress})).sendAndConfirm(e.umi,{confirm:{commitment:"confirmed"}});return{asset:r,signature:g(o.signature)}}catch(r){throw console.error("Error in issueLoyaltyPass:",r),new Error(`Failed to issue loyalty pass: ${r}`)}}function Ve(e){if(!e)throw console.error("Validation failed: config is undefined"),new Error("assertValidIssueLoyaltyPassConfig: Config is undefined");if(!e.collectionAddress)throw console.error("Validation failed: collectionAddress is undefined",e),new Error("assertValidIssueLoyaltyPassConfig: Collection address is undefined");if(!e.recipient)throw console.error("Validation failed: recipient is undefined",e),new Error("assertValidIssueLoyaltyPassConfig: Recipient is undefined");if(!e.passName||!e.passName.trim()||!e.passName.trim().length)throw console.error("Validation failed: passName is invalid",e),new Error("assertValidIssueLoyaltyPassConfig: Pass name is undefined");if(!e.organizationName||!e.organizationName.trim())throw console.error("Validation failed: organizationName is invalid",e),new Error("assertValidIssueLoyaltyPassConfig: Organization name is undefined");if(e.passMetadataUri){if(!e.passMetadataUri.trim()||!e.passMetadataUri.trim().length)throw console.error("Validation failed: passMetadataUri is empty",e),new Error("assertValidIssueLoyaltyPassConfig: Pass metadata URI is empty");if(!e.passMetadataUri.startsWith("https://")&&!e.passMetadataUri.startsWith("http://"))throw console.error("Validation failed: passMetadataUri is not a valid URL",e),new Error("assertValidIssueLoyaltyPassConfig: Pass metadata URI is not a valid URL")}else{if(!e.imageBuffer)throw console.error("Validation failed: imageBuffer is required",e),new Error("assertValidIssueLoyaltyPassConfig: Image buffer is required when passMetadataUri is not provided");if(!e.imageFilename||!e.imageFilename.trim())throw console.error("Validation failed: imageFilename is required",e),new Error("assertValidIssueLoyaltyPassConfig: Image filename is required when passMetadataUri is not provided")}}async function ge(e,t){var r,i;try{let a;try{a=await u.fetchAsset(e.umi,t.passAddress),console.log("asset",a)}catch{throw new Error("Failed to award points: Pass not found")}const s=(r=a.appDatas)==null?void 0:r[0];if(!s)throw new Error("AppData plugin not found");const o=s.data||{},n=o.xp||0,d=await V(e,p.POINTS_PER_ACTION);if(!d||Object.keys(d).length===0||Object.values(d).every(c=>c===0))throw new Error("Points per action configuration not found");if(!d[t.action]||d[t.action]===0)throw new Error(`Action '${t.action}' is not defined in points per action configuration`);const l=d[t.action]*(t.multiplier||1),m=n+l,y=await v(e,m);try{const c=await U(e,t.passAddress,t.signer,s,{xp:m,action:t.action,points:l,currentData:o,newTier:y});return{points:m,signature:c.signature}}catch(c){throw(i=c.message)!=null&&i.includes("Invalid Authority")?new Error("Failed to award points: Signer is not the pass owner"):c}}catch(a){throw a instanceof Error?a:new Error(`Failed to award points: ${a}`)}}async function Pe(e,t){var r;Te(t);try{const i=await u.fetchAsset(e.umi,t.passAddress);if(!i)throw new Error("Failed to gift points: Pass not found");if(!V(e,p.TYPE))throw new Error("Pass does not belong to a collection");const s=(r=i.appDatas)==null?void 0:r[0];if(!s)throw new Error("AppData plugin not found");const o=s.data||{},d=(o.xp||0)+t.pointsToGift,l=await v(e,d),m=await U(e,t.passAddress,t.signer,s,{xp:d,action:t.action,points:t.pointsToGift,currentData:o,newTier:l});return{points:d,signature:m.signature,newTier:l}}catch(i){throw i instanceof Error?i:new Error(`Failed to gift points: ${i}`)}}function Te(e){if(!e)throw new Error("assertValidGiftLoyaltyPointsConfig: Config is undefined");if(!e.passAddress)throw new Error("assertValidGiftLoyaltyPointsConfig: Pass address is undefined");if(typeof e.pointsToGift!="number"||e.pointsToGift<=0)throw new Error("assertValidGiftLoyaltyPointsConfig: Points to gift must be a positive number");if(!e.signer)throw new Error("assertValidGiftLoyaltyPointsConfig: Signer is undefined");if(!e.action)throw new Error("assertValidGiftLoyaltyPointsConfig: Action is undefined")}async function Ie(e,t){var r,i;ve(t);try{let a;try{a=await u.fetchAsset(e.umi,t.passAddress)}catch{throw new Error("Failed to revoke points: Pass not found")}if(!a)throw new Error("Failed to revoke points: Pass not found");if(!V(e,p.TYPE))throw new Error("Pass does not belong to a collection");const o=(r=a.appDatas)==null?void 0:r[0];if(!o)throw new Error("AppData plugin not found");const n=o.data||{},d=n.xp||0,l=Math.max(0,d-t.pointsToRevoke),m=d-l,y=await v(e,l);try{const c=await U(e,t.passAddress,t.signer,o,{xp:l,action:"revoke",points:-m,currentData:n,newTier:y});return{points:l,signature:c.signature,newTier:y}}catch(c){throw console.error("Error in updatePassData:",c),(i=c.message)!=null&&i.includes("Invalid Authority")?new Error("Failed to revoke points: Signer is not the pass owner"):c}}catch(a){throw a instanceof Error?a:new Error(`Failed to revoke points: ${a}`)}}function ve(e){if(!e)throw new Error("assertValidRevokeLoyaltyPointsConfig: Config is undefined");if(!e.passAddress)throw new Error("assertValidRevokeLoyaltyPointsConfig: Pass address is undefined");if(typeof e.pointsToRevoke!="number"||e.pointsToRevoke<=0)throw new Error("assertValidRevokeLoyaltyPointsConfig: Points to revoke must be a positive number");if(!e.signer)throw new Error("assertValidRevokeLoyaltyPointsConfig: Signer is undefined")}async function De(e,t){D(e),Re(t);try{const r=await V(e,p.TIERS),i=await V(e,p.POINTS_PER_ACTION);if(!r||!i)throw new Error("Failed to update loyalty program: Current configuration not found");let a=r;t.newTiers&&(a=Ue(r,t.newTiers));let s=i;t.newPointsPerAction&&(s=be(i,t.newPointsPerAction));const o=w(e.umi,e.umi.identity.publicKey,"LOYALTY_OPERATIONS"),d=await u.updateCollectionPlugin(e.umi,{collection:t.collectionAddress,plugin:{type:h.ATTRIBUTES,attributeList:[{key:p.PROGRAM_TYPE,value:"loyalty"},{key:p.TIERS,value:JSON.stringify(a)},{key:p.POINTS_PER_ACTION,value:JSON.stringify(s)},{key:p.CREATOR,value:t.programAuthority.toString()}]},authority:t.updateAuthority}).add(o).sendAndConfirm(e.umi,{confirm:{commitment:"confirmed"}});return{signature:g(d.signature)}}catch(r){throw new Error(`Failed to update loyalty program: ${r}`)}}function Ue(e,t){if(!e.find(o=>o.name==="Grind"))throw new Error("Grind tier must exist and cannot be removed");const i=new Map(e.map(o=>[o.name,o])),a=t.map(o=>{const n=i.get(o.name);return n?{...n,xpRequired:o.xpRequired,rewards:o.rewards}:o}),s=a.findIndex(o=>o.name==="Grind");if(s!==0){const o=a.splice(s,1)[0];a.unshift(o)}if(!a.find(o=>o.name==="Grind"))throw new Error("Grind tier must exist");return a}function be(e,t){const r={...e};return Object.entries(t).forEach(([i,a])=>{if(a<0)throw new Error(`Points for action '${i}' cannot be negative`);r[i]=a}),r}function Re(e){if(!e)throw new Error("assertValidUpdateLoyaltyProgramConfig: Config is undefined");if(!e.collectionAddress)throw new Error("assertValidUpdateLoyaltyProgramConfig: Collection address is undefined");if(!e.programAuthority)throw new Error("assertValidUpdateLoyaltyProgramConfig: Program authority is undefined");if(!e.updateAuthority)throw new Error("assertValidUpdateLoyaltyProgramConfig: Update authority is undefined");if(e.newTiers&&!Array.isArray(e.newTiers))throw new Error("assertValidUpdateLoyaltyProgramConfig: New tiers must be an array");if(e.newPointsPerAction&&typeof e.newPointsPerAction!="object")throw new Error("assertValidUpdateLoyaltyProgramConfig: New points per action must be an object")}async function Ne(e,t){var r;Le(t);try{const i=await u.fetchAsset(e.umi,t.passAddress);if(!i)throw new Error("Failed to send message: Pass not found");const a=(r=i.appDatas)==null?void 0:r[0];if(!a)throw new Error("AppData plugin not found");const s=a.data||{},o=s.messageHistory||[],n={id:crypto.randomUUID(),content:t.message,sender:t.sender.toString(),timestamp:Date.now(),read:!1};return{signature:(await U(e,t.passAddress,t.signer,a,{xp:s.xp,action:"message",points:0,currentData:{...s,messageHistory:[...o,n]},newTier:{name:s.currentTier,rewards:s.rewards}})).signature,message:n}}catch(i){throw i instanceof Error?i:new Error(`Failed to send message: ${i}`)}}function Le(e){if(!e)throw new Error("assertValidSendMessageConfig: Config is undefined");if(!e.passAddress)throw new Error("assertValidSendMessageConfig: Pass address is undefined");if(!e.message||!e.message.trim())throw new Error("assertValidSendMessageConfig: Message is undefined or empty");if(!e.sender)throw new Error("assertValidSendMessageConfig: Sender is undefined");if(!e.signer)throw new Error("assertValidSendMessageConfig: Signer is undefined")}async function Se(e,t){var r;_e(t);try{const i=await u.fetchCollection(e.umi,t.collectionAddress);if(!i)throw new Error("Failed to send broadcast: Collection not found");const a=(r=i.appDatas)==null?void 0:r[0];if(console.log("appDataPlugin",a),!a)throw new Error("AppData plugin not found");const s=a.data,o=s.broadcasts,n={id:crypto.randomUUID(),content:t.message,sender:t.sender.toString(),timestamp:Date.now(),read:!1};return{signature:(await Y(e,t.collectionAddress,t.signer,a,{totalBroadcasts:(s.totalBroadcasts||0)+1,broadcasts:[...o,n]})).signature,broadcast:n}}catch(i){throw i instanceof Error?i:new Error(`Failed to send broadcast: ${i}`)}}function _e(e){if(!e)throw new Error("assertValidSendBroadcastConfig: Config is undefined");if(!e.collectionAddress)throw new Error("assertValidSendBroadcastConfig: Collection address is undefined");if(!e.message||!e.message.trim())throw new Error("assertValidSendBroadcastConfig: Message is undefined or empty");if(!e.sender)throw new Error("assertValidSendBroadcastConfig: Sender is undefined");if(!e.signer)throw new Error("assertValidSendBroadcastConfig: Signer is undefined")}async function Oe(e){I(e);try{return await V(e,p.TIERS)||[]}catch(t){throw new Error(`Failed to fetch program tiers: ${t}`)}}async function Me(e){var t,r,i,a,s,o;I(e);try{const n=await u.fetchCollection(e.umi,e.collectionAddress),d=((t=n.attributes)==null?void 0:t.attributeList)||[],l=d.find(P=>P.key===p.TIERS),m=d.find(P=>P.key===p.POINTS_PER_ACTION),y=d.find(P=>P.key===p.METADATA),c=l?JSON.parse(l.value):[],A=m?JSON.parse(m.value):{},f=y?JSON.parse(y.value):{},C=(r=n.appDatas)==null?void 0:r[0],N=C==null?void 0:C.data;return{name:n.name,uri:n.uri,collectionAddress:n.publicKey,updateAuthority:n.updateAuthority,numMinted:n.numMinted,transferAuthority:(a=(i=n.permanentTransferDelegate)==null?void 0:i.authority.address)==null?void 0:a.toString(),creator:(o=(s=n.attributes)==null?void 0:s.attributeList.find(P=>P.key===p.CREATOR))==null?void 0:o.value,tiers:c,pointsPerAction:A,metadata:f,broadcasts:N}}catch(n){throw new Error(`Failed to fetch program details: ${n}`)}}async function ke(e,t){var r,i,a,s;try{const o=await u.fetchAsset(e.umi,t),n=(r=o.appDatas)==null?void 0:r.find(C=>C.type===h.APP_DATA);if(!n||!n.data)return null;const d=o.updateAuthority.address;if(!d)throw new Error("Collection address not found");const l=await u.fetchCollection(e.umi,d),m=(i=l.attributes)==null?void 0:i.attributeList.find(C=>C.key===p.METADATA),y=m?JSON.parse(m.value):{},c=(a=l.attributes)==null?void 0:a.attributeList.find(C=>C.key===p.TIERS),A=c?JSON.parse(c.value):{},f=(s=l.appDatas)==null?void 0:s[0].data;return{...n.data,name:o.name,uri:o.uri,owner:o.owner.toString(),pass:o.publicKey.toString(),metadata:y,rewardTiers:A,broadcasts:f}}catch(o){if(o instanceof Error&&o.message.includes("not found"))return null;throw new Error(`Failed to fetch asset data: ${o}`)}}async function Fe(e){I(e);try{return await V(e,p.POINTS_PER_ACTION)||{}}catch(t){throw new Error(`Failed to fetch points per action: ${t}`)}}async function xe(e,t){try{return await u.fetchAssetsByOwner(e.umi,t)}catch(r){throw new Error(`Failed to fetch wallet loyalty passes: ${r}`)}}async function Be(e,t,r){I(e);try{const i=w(e.umi,e.umi.identity.publicKey,"VERXIO_INTERACTION");await u.transferV1(e.umi,{asset:t,newOwner:r,collection:e.collectionAddress}).add(i).sendAndConfirm(e.umi,{confirm:{commitment:"confirmed"}})}catch(i){throw new Error(`Failed to approve transfer: ${i}`)}}function Ke(e,t){return{umi:e,programAuthority:t}}async function Ge(e,t){D(e),Je(t);const r=t.collectionSigner??E.generateSigner(e.umi),i=t.updateAuthority??E.generateSigner(e.umi);let a=t.metadataUri;if(!a){if(!t.imageBuffer||!t.imageFilename)throw new Error("Either metadataUri or imageBuffer with imageFilename must be provided");const n=await T(e,t.imageBuffer,t.imageFilename,t.imageContentType);a=await O(e,{loyaltyProgramName:t.loyaltyProgramName,metadata:t.metadata,tiers:t.tiers,pointsPerAction:t.pointsPerAction,imageUri:n,creator:t.programAuthority,mimeType:t.imageContentType})}let s=u.createCollection(e.umi,{collection:r,name:t.loyaltyProgramName,plugins:H(t,i.publicKey),uri:a,updateAuthority:i.publicKey});const o=w(e.umi,e.umi.identity.publicKey,"CREATE_LOYALTY_PROGRAM");return s=s.add(o),s=s.add(u.writeCollectionExternalPluginAdapterDataV1(e.umi,{collection:r.publicKey,authority:i,key:{__kind:h.APP_DATA,fields:[{__kind:"Address",address:i.publicKey}]},data:new TextEncoder().encode(JSON.stringify(L))})),{instruction:s,collection:r,updateAuthority:i}}function H(e,t){return[{type:h.ATTRIBUTES,attributeList:[{key:p.PROGRAM_TYPE,value:"loyalty"},{key:p.TIERS,value:JSON.stringify(e.tiers)},{key:p.POINTS_PER_ACTION,value:JSON.stringify(e.pointsPerAction)},{key:p.CREATOR,value:e.programAuthority.toString()},{key:p.METADATA,value:JSON.stringify(e.metadata)}]},{type:h.PERMANENT_TRANSFER_DELEGATE,authority:{address:e.programAuthority,type:"Address"}},{type:h.UPDATE_DELEGATE,authority:{address:t,type:"Address"},additionalDelegates:[]},{type:h.APP_DATA,dataAuthority:{type:"Address",address:t},schema:u.ExternalPluginAdapterSchema.Json}]}function Je(e){if(!e)throw new Error("assertValidCreateLoyaltyProgramInstructionConfig: Config is undefined");if(!e.loyaltyProgramName||!e.loyaltyProgramName.trim()||!e.loyaltyProgramName.trim().length)throw new Error("assertValidCreateLoyaltyProgramInstructionConfig: Loyalty program name is undefined");if(!e.pointsPerAction||Object.keys(e.pointsPerAction).length===0)throw new Error("assertValidCreateLoyaltyProgramInstructionConfig: Points per action configuration is missing");if(e.metadataUri){if(!e.metadataUri.trim()||!e.metadataUri.trim().length)throw new Error("assertValidCreateLoyaltyProgramInstructionConfig: Metadata URI is empty");if(!e.metadataUri.startsWith("https://")&&!e.metadataUri.startsWith("http://"))throw new Error("assertValidCreateLoyaltyProgramInstructionConfig: Metadata URI is not a valid URL")}else{if(!e.imageBuffer)throw new Error("assertValidCreateLoyaltyProgramInstructionConfig: Image buffer is required when metadataUri is not provided");if(!e.imageFilename||!e.imageFilename.trim())throw new Error("assertValidCreateLoyaltyProgramInstructionConfig: Image filename is required when metadataUri is not provided")}if(!e.programAuthority)throw new Error("assertValidCreateLoyaltyProgramInstructionConfig: Program authority is undefined");if(!e.updateAuthority)throw new Error("assertValidCreateLoyaltyProgramInstructionConfig: Update authority is undefined");if(!e.tiers||e.tiers.length===0)throw new Error("assertValidCreateLoyaltyProgramInstructionConfig: Tiers configuration is missing");if(!e.metadata)throw new Error("assertValidCreateLoyaltyProgramInstructionConfig: Metadata is undefined");if(!e.metadata.organizationName||!e.metadata.organizationName.trim()||!e.metadata.organizationName.trim().length)throw new Error("assertValidCreateLoyaltyProgramInstructionConfig: Organization name is undefined");return!0}async function Ye(e,t){D(e),qe(t);const r=await V(e,p.TIERS),i=await V(e,p.POINTS_PER_ACTION);if(!r||!i)throw new Error("Failed to create update instruction: Current configuration not found");let a=r;t.newTiers&&(a=He(r,t.newTiers));let s=i;t.newPointsPerAction&&(s=$e(i,t.newPointsPerAction));let o=u.updateCollectionPlugin(e.umi,{collection:t.collectionAddress,plugin:{type:h.ATTRIBUTES,attributeList:[{key:p.PROGRAM_TYPE,value:"loyalty"},{key:p.TIERS,value:JSON.stringify(a)},{key:p.POINTS_PER_ACTION,value:JSON.stringify(s)},{key:p.CREATOR,value:t.programAuthority.toString()}]},authority:t.updateAuthority});const n=w(e.umi,e.umi.identity.publicKey,"LOYALTY_OPERATIONS");return o=o.add(n),{instruction:o,updatedTiers:a,updatedPointsPerAction:s}}function He(e,t){if(!e.find(o=>o.name==="Grind"))throw new Error("Grind tier must exist and cannot be removed");const i=new Map(e.map(o=>[o.name,o])),a=t.map(o=>{const n=i.get(o.name);return n?{...n,xpRequired:o.xpRequired,rewards:o.rewards}:o}),s=a.findIndex(o=>o.name==="Grind");if(s!==0){const o=a.splice(s,1)[0];a.unshift(o)}if(!a.find(o=>o.name==="Grind"))throw new Error("Grind tier must exist");return a}function $e(e,t){const r={...e};return Object.entries(t).forEach(([i,a])=>{if(a<0)throw new Error(`Points for action '${i}' cannot be negative`);r[i]=a}),r}function qe(e){if(!e)throw new Error("assertValidUpdateLoyaltyProgramInstructionConfig: Config is undefined");if(!e.collectionAddress)throw new Error("assertValidUpdateLoyaltyProgramInstructionConfig: Collection address is undefined");if(!e.programAuthority)throw new Error("assertValidUpdateLoyaltyProgramInstructionConfig: Program authority is undefined");if(!e.updateAuthority)throw new Error("assertValidUpdateLoyaltyProgramInstructionConfig: Update authority is undefined");if(e.newTiers&&!Array.isArray(e.newTiers))throw new Error("assertValidUpdateLoyaltyProgramInstructionConfig: New tiers must be an array");if(e.newPointsPerAction&&typeof e.newPointsPerAction!="object")throw new Error("assertValidUpdateLoyaltyProgramInstructionConfig: New points per action must be an object")}async function ze(e,t){We(t);const r=t.assetSigner??E.generateSigner(e.umi);let i=t.passMetadataUri;if(!i){if(!t.imageBuffer||!t.imageFilename)throw new Error("Either passMetadataUri or imageBuffer with imageFilename must be provided");const o=await T(e,t.imageBuffer,t.imageFilename,t.imageContentType);i=await M(e,{passName:t.passName,organizationName:t.organizationName,imageUri:o,creator:t.updateAuthority.publicKey,mimeType:t.imageContentType})}let a=u.create(e.umi,{asset:r,name:t.passName,uri:i,owner:t.recipient,authority:t.updateAuthority,collection:{publicKey:t.collectionAddress},plugins:[{type:h.APP_DATA,dataAuthority:{type:"Address",address:t.updateAuthority.publicKey},schema:u.ExternalPluginAdapterSchema.Json},{type:h.ATTRIBUTES,attributeList:[{key:p.TYPE,value:`${t.passName} loyalty pass`}]}]});const s=w(e.umi,e.umi.identity.publicKey,"LOYALTY_OPERATIONS");return a=a.add(s),a=a.add(u.writeData(e.umi,{key:{type:h.APP_DATA,dataAuthority:{type:"Address",address:t.updateAuthority.publicKey}},authority:t.updateAuthority,data:new TextEncoder().encode(JSON.stringify(_)),asset:E.publicKey(r.publicKey),collection:t.collectionAddress})),{instruction:a,asset:r}}function We(e){if(!e)throw new Error("assertValidIssueLoyaltyPassInstructionConfig: Config is undefined");if(!e.collectionAddress||!e.collectionAddress.toString().trim())throw new Error("assertValidIssueLoyaltyPassInstructionConfig: Collection address is undefined");if(!e.recipient||!e.recipient.toString().trim())throw new Error("assertValidIssueLoyaltyPassInstructionConfig: Recipient is undefined");if(!e.passName||!e.passName.trim())throw new Error("assertValidIssueLoyaltyPassInstructionConfig: Pass name is undefined");if(!e.organizationName||!e.organizationName.trim())throw new Error("assertValidIssueLoyaltyPassInstructionConfig: Organization name is undefined");if(e.passMetadataUri){if(!e.passMetadataUri.trim())throw new Error("assertValidIssueLoyaltyPassInstructionConfig: Pass metadata URI is empty");if(!e.passMetadataUri.startsWith("https://")&&!e.passMetadataUri.startsWith("http://"))throw new Error("assertValidIssueLoyaltyPassInstructionConfig: Pass metadata URI is not a valid URL")}else{if(!e.imageBuffer)throw new Error("assertValidIssueLoyaltyPassInstructionConfig: Image buffer is required when passMetadataUri is not provided");if(!e.imageFilename||!e.imageFilename.trim())throw new Error("assertValidIssueLoyaltyPassInstructionConfig: Image filename is required when passMetadataUri is not provided")}if(!e.updateAuthority)throw new Error("assertValidIssueLoyaltyPassInstructionConfig: Update authority is undefined")}async function Xe(e,t){var f;let r;try{r=await u.fetchAsset(e.umi,t.passAddress)}catch{throw new Error("Failed to create award points instruction: Pass not found")}const i=(f=r.appDatas)==null?void 0:f[0];if(!i)throw new Error("AppData plugin not found");const a=i.data||{},s=a.xp||0,o=await V(e,p.POINTS_PER_ACTION);if(!o||Object.keys(o).length===0||Object.values(o).every(C=>C===0))throw new Error("Points per action configuration not found");if(!o[t.action]||o[t.action]===0)throw new Error(`Action '${t.action}' is not defined in points per action configuration`);const n=o[t.action]*(t.multiplier||1),d=s+n,l=await v(e,d),m={xp:d,lastAction:t.action,currentTier:l.name,tierUpdatedAt:l.name!==a.currentTier?Date.now():a.tierUpdatedAt,actionHistory:a.actionHistory||[],messageHistory:a.messageHistory||[],rewards:l.rewards||[]},y=new TextEncoder().encode(JSON.stringify(m));let c=u.writeData(e.umi,{key:{type:h.APP_DATA,dataAuthority:i.dataAuthority},authority:t.signer,data:y,asset:t.passAddress,collection:e.collectionAddress});const A=w(e.umi,e.umi.identity.publicKey,"VERXIO_INTERACTION");return c=c.add(A),{instruction:c,newXp:d,pointsAwarded:n,newTier:l}}async function je(e,t){var f;Ze(t);let r;try{r=await u.fetchAsset(e.umi,t.passAddress)}catch{throw new Error("Failed to create revoke points instruction: Pass not found")}if(!r)throw new Error("Failed to create revoke points instruction: Pass not found");if(!V(e,p.TYPE))throw new Error("Pass does not belong to a collection");const a=(f=r.appDatas)==null?void 0:f[0];if(!a)throw new Error("AppData plugin not found");const s=a.data||{},o=s.xp||0,n=Math.max(0,o-t.pointsToRevoke),d=o-n,l=await v(e,n),m={xp:n,lastAction:"revoke",currentTier:l.name,tierUpdatedAt:l.name!==s.currentTier?Date.now():s.tierUpdatedAt,actionHistory:s.actionHistory||[],messageHistory:s.messageHistory||[],rewards:l.rewards||[]},y=new TextEncoder().encod