Minting NFTs in Solana. Transaction fees - solana

I have already prepared the Candy Machines for minting an NFT collection in the Solana network, and I am testing the Mint process using its Devnet.
Even if you can find a lot of tutorials about how to prepare the candy machines, there are some questions that I am still not able to find the right answer and I think that could be useful for other users.
Does the Mint need to be one by one? If a user would like to buy, for example 50 NFTs, does it require approving 50 transactions and pay 50 times the fees (using Phantom or any other wallet)?
I assume that yes, because every minted NFT is a new contract. Am I right?
I am successfully doing a Mint in the Devnet using my Phantom wallet in order to determine the fees. For a single NFT, the transaction fee reflected in the wallet is 0.012SOL = 2.16$ at this time. It seems really expensive based on what a transaction in Solana should cost. How are these fees calculated? Is this the normal fee price that a user pay for minting 1 NFT?

To answer both your questions:
The mint does not need to be one by one (from a mint site I am assuming is what you mean). You can string multiple transactions together like what this repo has achieved: https://github.com/maxwellfortney/next-candy-machine
Note: this repo is for cmv1 which is no longer supported but can be simply adjusted to work with cmv2 as the transactions themseleves should be similar.
Yes, that is a normal fee for minting. Transactions (transfering tokens or sol) themselves on solana are extremely cheap but storing data is not as cheap. To store data (such as is required by an NFT as they need a URI for the metadata) some "rent" costs are involved, as defined in the solana docs https://docs.solana.com/implemented-proposals/rent. Basically you have to pay for the NFT to store this data and exist which is the minting fees you are witnessing, a tiny fraction of the price you pay is for transferring the NFT to your wallet.

Mints are usually done one by one, but someone could hand code a transaction to do multiple, especially with Candy Machine V1.
The rent collected depends on the amount of bytes stored for each NFT. You can check how much it will cost with solana -um rent <bytes>. You can find more information here

I recently update the candy machine to v2, and it has some interesting features as minting more than one NFT or handle a whitelist of wallets:
https://docs.metaplex.com/candy-machine-v2/getting-started

for your second question, you can maybe think to use an external service that handles the transaction fees.
In this way you'll be able to let you customer get the NFT without paying any fee.
If you are interested in implementing a similar external solution, I guess that this APIs Service is for you: cowsigner.com
You can also solve your first point, because when you create a transaction, you'll be able to add as many instructions as you want to it.
For anything else, just drop a simple comment below :)

Related

How to calculate transaction fee

I want to empty my transactable balance,but alwalys got LackofBalance error.
I've used gas price* gas limit and ransfer_cost + create_account_cost + add_key_cost.full_access_cost by
https://nomicon.io/GenesisConfig/RuntimeFeeConfig/ActionCreationConfig#transfer_cost to calculate fee and max transaction amount.None of them work well.
If your account is linked to the NEAR wallet, you can use Send MAX to transfer as much NEAR balance as possible. After that operation your account will be, in some sense, locked since you need to receive funds from someone to continue operating with it.
An alternative to getting ALL the funds from your account is deleting it and set another account as the target where all funds should go. This can be done via near-cli using near delete tobedestroyed.near receiver.near

How to calculate storage rent?

I send transactions programmatically and I need to know exactly how much the fee is going to be. I managed to figure out how to calculate fees for ordinary transaction ((transfer cost + receipt creation cost) * 2), but now I'm struggling with a case where I need all my funds out of the account without deleting it. As I understand, in this case there must be a storage rent left on the account. However, I can't really figure out how to calculate that rent. There is a value returned from 'EXPERIMENTAL_protocol_config' method that seem to be connected to rent - 'storage_amount_per_byte', which implies that each byte costs 10000000000000000000 yocto, and also I can get 'storage_usage' from 'query' method with request type 'view_account', which is supposedly indicated how many bytes my account uses (which is 182). But whenever I try to send a transaction, I get a 'NotEnoughBalance' error that states that transaction cost is higher than the balance, but just by 669547687500000000 yocto. Whatever I do, I can't understand where this number comes from. No combination of fees from aforementioned 'EXPERIMENTAL_protocol_config' method yields this number.
There seems to be little to no decent documentation on transaction fee calculation, except for some 'fixed' values for most used actions. If you have any info on fee/storage rent calculation - I'll be thankful for it.
Through a random chance, I managed to find out the name that the number '6695476875' is referred to as, 'Reserved for transactions', (in gas, not tokens) as in the official wallet (wallet.near.org). God knows why it is reserved, neither docs.near.org, nomicon.io nor wiki.near.org have any info regarding this 'reservation' and this number is never mentioned in any RPC API method. This number is also never mentioned in 'near-api-js' lib, so I really have no idea if devs are even aware of it.
Anyway, since the title of this problem is 'How to calculate storage rent', the answer is something like this:
You get account info from 'query' method of RPC API (here's the doc) and take the "storage_usage" value (this is the amount of bytes that your account takes up on the blockchain).
You get protocol info from 'EXPERIMENTAL_protocol_config' method of RPC API (here's the doc) and take the "storage_amount_per_byte" value.
You multiply the amount of bytes by the storage_amount_per_byte and add the magic 669547687500000000 number to it.
And the resulting number is the least amount of tokens that you must have at your account at any time.
I don't know why it is a common practice to make lives of developers harder in blockchain industry, but this is a good example of such practice.

Why the transferable to smart contract is deducted?

I uploaded and created a new smart contract. I sent 1000 units to this smart contract.
However when the contract is deployed the transferable is not equal to 1000.
And when I execute any function it also deducts the transferable.
Is there any way to prevent this. I want to deduct user token instead of the smart contract token. In Ethereum, the user token is deducted.
I want to deduct user token instead of the smart contract token. In Ethereum, the user token is deducted.
I think there is a misunderstanding here, you probably understood the deducted tokens as gas. But gas is deducted from the instantiating account (what you referred to as "user token"), same as in Ethereum.
The amount that is deducted from the contract here is state rent ‒ i.e. the contract has to regularly pay for the amount of state and code storage it uses. This is a concept which is currently used by the contracts pallet to reduce state bloat. I won't link to the documentation here though, since a new paradigm will be introduced soon, making it obsolete.

how can i implement recurring payment for payeezy in codeigniter?

I want to integrate recurring payment using Payeezy in codeigniter. I have implement the single time payment using curl and now i want to recurring payment with acknowledgement to update my DB.
I created a WordPress plugin for Payeezy that also handles recurring. You should be able to use the underlying PHP code for CodeIgniter.
https://wordpress.org/plugins/wp-payeezy-pay/
I can explain the process that will get you the least PCI compliance issues, and that's the token-based API.
1. Generate Token in Payment Form
So basically you'll use the Javascript API to generate your authorize token. An authorize token doesn't charge the card. It's for validating the card and returning a token for better PCI compliance. This API source code and explanation is here:
https://github.com/payeezy/payeezy_js
2. Post Form To Your Server for the Curl Call to FirstData
Then, once you have this token, you post it back to your controller file with a standard form post, but remove the name attribute on your credit card number and credit card CVC fields so that these do not post to your server. Note that you'll need to store this data (but not card number and CVC) because on refunds (and subscription cancellations) you'll need to reply back with the last purchase token, cardholder name, card type, card expiration date, amount spent, and currency code. You may wonder why FirstData/PayEezy is asking you to store cardholder name, card type, and card expiration date. Well, there's a perfectly good explanation for that. Your call center may need that detail for troubleshooting an issue over the phone with a customer. Also, you need that for refunds. And, most importantly, if you're doing a recurring subscription payment, your code needs to look at the expiration date ahead of time before charging because the API call will fail if the card is past expiration. Last, because you're not storing the credit card number and credit card validation (CVC) code, you're going to be in stronger PCI compliance.
From there, since you are already familiar with the Curl process for a single-purchase, it's just a minor single field change (transaction_type becomes 'recurring') in the Curl to do the recurring. For anyone not familiar with the Curl process, it's explained here:
https://developer.payeezy.com/payeezy-api/apis/post/transactions-4
Also, for those unfamiliar people, you'll need to read up on how FirstData/PayEezy wants you to send in the Curl request with a special header that includes Content-Type: application/json, apikey, token, Authorization, nonce, and timestamp. You can see more detail about that here:
https://github.com/payeezy/payeezy_direct_API/blob/master/payeezy_php/example/src/Payeezy.php
(What I did to make that code simpler was intercept the Curl calls from that script into a log file so that I could make it much more straightforward in a single function instead of breaking it up into all these little functions. That made it far easier to understand what was going on.)
3. Switching Curl Call for Recurring Payments
So, as you discovered in your Curl call, you saw how to do a one-time purchase by setting the transaction_type to 'purchase'. For doing recurring, you set transaction_type to 'recurring'. You have to do that from the start. So, if I'm selling something for $29.99 monthly, the very first month charge needs to still be set to type 'recurring', as would any subsequent month.
4. Your Responsibilities for Recurring Payments
Now, this is where everyone gets hung up because it's poorly documented unless you check the PayEezy Developer Support Forum. For subscriptions, PayEezy doesn't have a system for setting payment plans with varying durations, nor setting up automatic (set-it-and-forget-it) subscriptions for you. (I think I read that they have something experimental on Apple Pay, but nothing else yet.) So, to achieve this, you have 2 choices:
Use Chargify.com. Unfortunately, though, this increases CPA (Cost Per Acquisition) of your product or service. You'll have to factor that in if you want to use that. This basically is a SaaS service that you send the transaction to and they handle the automatic subscription plan for you against FirstData/PayEezy.
Roll your own cron job solution. To do this, you basically take the Curl code for a single transaction, and change the transaction type from 'purchase' to 'recurring'. (Do that from the start -- don't start with 'purchase' on a recurring charge.) From there, it's up to you with your own cron job to check for product or service expiration terms, and then send the API call back off to FirstData/PayEezy for charging that card again with the 'recurring' transaction_type.
On either of those options, the customer never gets asked to enter in credit card data past the first time unless their card expires or unless you have some problem billing that card (like insufficient funds).
Of course, doing your own cron job route for the recurring payment has implications you'll need to prepare for:
Add some failsafe code so that you prevent the possibility of duplicate transactions, such as a database field.
Add some failsafe code such that if you have cancelled a subscription, you won't charge them again.
Add some failsafe code such that if they cancel their subscription, yet purchase it again as a subscription at a later time, that you do charge them again and don't block it from your other failsafe code.
Add some sort of grace period on your product or service such that even if you "say" that the term expired, you have like a 2 day grace period so that your API has a chance to do a renewal.
It's probably a good idea to email the customer before their renewal period so that they can make certain they have money in their account and have a way to cancel that charge (like call your office or call center, or have a link to click where you provide a way to cancel).
If their card has expired before the renewal, and you detect that in the warning email that comes before renewal, then you'll want to let them know this.
If their card has been declined for any reason at the point of renewal, then you'll want to let them know this and give them a link to go through the cart again to buy it again, or some other way to save that transaction in your code.
How To Do Subscription Cancellations / Stop Recurring Payments
To stop a recurring payment, you treat it just like a refund on a single purchase, but use the transaction ID of the last purchase. This is documented with this Curl example here:
https://developer.payeezy.com/payeezy-api/apis/post/transactions/%7Bid%7D-0
Look under "Refund" and choose Token.

Stripe & transferring funds

I am currently in the process of planning & developing an integrated application using Stripe in addition to some other technologies (a combination of backbone & laravel). As a result I am using Stripejs in combination with the PHP stripe library.
I use stripejs to send Stripe their account info (for savings accounts I send country, routing and account numbers via stripes js lib, I then save off the created token in the response to the backend). I am attempting to transfer money to various recipients following charging accounts (so I have money in my stripe account) but I am a bit confused over exactly what approach to take.
My main questions are as follows.
If I am positive of the identities of the individual’s using the application, is verification required (5 – 10 people max will be using)?
If it is required what is the best approach to verifying the user using the current technique I am using (create a token, save off on the backend)?
From my experience with Stripe, you don't need to 'verify identities' each time you use a token, so long as a customer has been set up for recurring use. So as long as your application is properly secured so that only the 5-10 people can use it, and can only process payments for their own accounts, you are good to go. In other words, you obviously want to do your own user verification to make sure only valid people can use the application, but you don't need to do it as far as Stripe is concerned.
That said, if you are in essence transferring money between people, you might want to go the extra distance and make sure that the user has the correct card number or bank account number each time. In which case I would use something like:
Get user data using tokens stored in DB.
$cu = Stripe_Customer::retrieve("cus_4pn93XXXXXXXXXXX");
$card = $cu->cards->retrieve("card_14g7ZU4rLTyXXXXXXXXXXX");
If Stripe's returned data matches user-submitted data, you know you have the correct user. In particular, if the last 4 digits of the card and the expiry date match the last 4 returned by Stripe and the Stripe returned expiry date, you can be reasonably sure (albeit not certain) that the person actually possesses the card in question.

Resources