NFT transfer with price - nearprotocol

I am using near-contract-standards for NFT.
In the example, it has nft_mint which takes token owner id and token id to mint the token.
#[payable]
pub fn nft_mint(
&mut self,
token_id: TokenId,
token_owner_id: ValidAccountId,
token_metadata: TokenMetadata,
) -> Token {
self.tokens.mint(token_id, token_owner_id, Some(token_metadata))
}
}
Then token owner id can do the nft transfer as predecessor to another account.
https://github.com/near-examples/NFT/blob/master/nft/src/lib.rs
contract.nft_mint(token_id.clone(), accounts(0), sample_token_metadata());
testing_env!(context
.storage_usage(env::storage_usage())
.attached_deposit(1)
.predecessor_account_id(accounts(0))
.build());
contract.nft_transfer(accounts(1), token_id.clone(), None, None);
I want to do nft tranfer with a buy price for nft, where predecessor is the user who want to buy the nft, instead of token owner, and then transfer the money to token owner.
How can I do that? Will I use internal_transfer or I will set the price in nft_mint function, and mint the token directly to buyer account id?

If I understand the question correctly you'd like to combine nft_mint with some sort of payable action that will pay the original creator of some "NFT token type"?
You can check the NFT Market repo here: https://github.com/near-apps/nft-market
This repository uses a separate market account and contract to allow NFT Owners to put NFTs up for sale. A little more than what you are looking for I think.
There is also a variant that uses "lazy minting" to only mint the NFTs when a user buys them from the market contract: https://github.com/near-apps/gnr8/
Again, it's a little more than what I think you want because the payment and buying is happening in a separate contract and the NFT transfer and minting is happening in the NFT contract, which is called from the market contract.
If you're looking for something to add your own payable NFT method to, you could start with this:
https://github.com/near-apps/nft-series/
Which allows you to define an NFT type and you could charge users to mint 1/N of that type by making the nft_mint_type method payable and NOT require the owner of the type to be the minter.
FYI these approaches are non-standard, but work.
Feel free to reach out directly on Discord if you need any help with the examples above.

Related

Do smart contract needs a SFT to call esdt_local_mint

My smart contract owns the SFT HAT-a1a1a1-01.
The SFT HAT-a1a1a1-02 also exists but isn't owned by the SC.
When I add local quantity to the SFT with the 02 nonce through a function, my transaction fails with this error:
new NFT data on sender
Do I need to own the SFT HAT-a1a1a1-02 to mint it?
I got an answer in another group:
Yes, you need to own at least 1 to AddQuantity, since otherwise, you wouldn't have the attributes. When you send an NFT/SFT, if your balance after is 0, the metadata is erased from your account.

How can i know the balance of the account where the contract is deployed from a method?

I´m trying to write a function that returns the balance of the account where the contract is deployed.
Something with the following form:
pub fn get_balance(&self) -> Balance {
env::account_balance()
}
The above code returns the balance of the account that is calling the method, the signer. Is there a way to make it returns the balance of the contract account?
I got the answer. near_sdk:env::account_balance() already do what i was looking for. It retrieves the balance of the contract account.
I was lacking a way to check it properly. To do it, i used near state [account_name] on the cli to verify if the balance returned was the master or subaccount (where the contract was deployed) balance.
So the answer would be:
pub fn get_balance(&self) -> Balance {
env::account_balance()
}
noting that to have the transferible balance, it would have to take into account the min balance used for storage.

Calling a payable method using near-api-js when the current access key has low allowance

I have a NEAR application in which most of the methods do not transfer any tokens. Users go through the standard login flow with NEAR wallet, have their 0.25N allowance for gas, and then interact with the application.
I now have a new end-point that I want to be callable from the front-end, which expects the user to pay an amount significantly exceeding 0.25N:
#[payable]
pub fn buy_stuff() {
When I use the standard near-api-js way to call it:
window.contract.buy_stuff({}, undefined, price).then(m => window.location.href='/');
it fails, because it tries to spend the price from the allowance of the aceess key logged in, which it doesn't have -- it naturally only has 0.25N it has for gas.
The specific error is "Access Key {account_id}:{public_key} does not have enough balance 247864837491516400000000 for transaction costing 5004231023352653388973496"
What I want instead is to get the user redirected to the wallet, and authorize this particular transaction using their full access key in the wallet. Is there a way to do that with near-api-js?
It looks like the issue is that the contract API doesn't consider a wallet redirect. One reason might be the initialization of the contract API.
In order for a contract API to be able to redirect to a wallet, the initialization should be done with the ConnectedWalletAccount. It can be done using the following code:
const nearConnection = await nearAPI.connect(...);
const walletConnection = new nearAPI.WalletConnection(
nearConnection,
ContractName
);
const contract = new nearAPI.Contract(
walletConnection.account(),
ContractName,
{
viewMethods: [...],
changeMethods: [...],
}
);

Near protocol equivalent of buring NEAR tokens by sending to address(0)

I want to delete the current contract and burn its NEAR balance when a condition is triggered.
Here's the Solidity version:
selfdestruct(address(0));
I found Promise::delete_account in the Rust SDK but it has a beneficiary_address field. Ideally the funds should be gone forever and not transferred to an owned address.
Promise::new(env::current_account_id()).delete_account(beneficiary_address);
address(0) is address 0x0, a black hole address used to burn Ether.
Currently there is no API to burn NEAR tokens directly. One workaround is to set the beneficiary account id to system. system is an account that can never be created and is used internally for refunds. When the beneficiary account does not exist, the tokens transferred through account deletion are automatically burnt.
I think that is like this:
#[payable]
pub fn burn() {
Promise::new("system".to_string()).transfer(env::attached_deposit());
}
First importing:
use near_sdk::{Promise};

Transferring user token balance to contract in cross contract call

Contract A
#[payable]
pub fn add_liquidity(&mut self, tokens: u128, avrit_id: AccountId) -> u128 {
let amount = env::attached_deposit();
Promise::new(avrit_id).function_call(
b"transfer".to_vec(),
json!({"new_owner_id":"avrit.testnet", "amount": U128(tokens)}).to_string().as_bytes().to_vec(),
38600000000000000000000,
env::prepaid_gas() - GAS_FOR_SWAP,
);
amount
}
Promise function call is done by contract A instead of the person who calls the add_liquidity.
How to call the Promise where predecessor is user who calls add_liquidity instead of contract A address? Explorer
You're right. It's not possible to make a Promise function call where the predecessor is some other account than the current one.
This is an important security feature of contract development on NEAR. Because if you could have spoofed the predecessor account ID, then you'd be able to pretend to be this account and do actions on behalf of this account.
Instead when a contract makes a cross-contract call, the predecessor becomes this contract instead of the transaction signer. The receiving contract will be able to see which account called it directly.

Resources