Skip to main content

Upgrading the Contract

In this tutorial, you'll build off the work you previously did to implement the minting functionality on a skeleton smart contract. You got to the point where NFTs could be minted and the wallet correctly picked up on the fact that you owned an NFT. However, it had no way of displaying the tokens since your contract didn't implement the method that the wallet was trying to call.


Introduction

Today you'll learn about deploying patch fixes to smart contracts and you'll use that knowledge to implement the nft_tokens_for_owner function on the contract you deployed in the previous tutorial.


Upgrading contracts overview

Upgrading contracts, when done right, can be an immensely powerful tool. If done wrong, it can lead to a lot of headaches. It's important to distinguish between the code and state of a smart contract. When a contract is deployed on top of an existing contract, the only thing that changes is the code. The state will remain the same and that's where a lot of developer's issues come to fruition.

The NEAR Runtime will read the serialized state from disk and it will attempt to load it using the current contract code. When your code changes, it might not be able to figure out how to do this. When your code changes, it might not be able to figure out how to do this.

You need to strategically upgrade your contracts and make sure that the runtime will be able to read your current state with the new contract code. For more information about upgrading contracts and some best practices, see the NEAR SDK's upgrading contracts write-up. For more information about upgrading contracts and some best practices, see the NEAR SDK's upgrading contracts write-up.


Modifications to our contract

In order for the wallet to properly display your NFTs, you need to implement the nft_tokens_for_owner method. This will allow anyone to query for a paginated list of NFTs owned by a given account ID. This will allow anyone to query for a paginated list of NFTs owned by a given account ID.

To accomplish this, let's break it down into some smaller subtasks. First, you need to get access to a list of all token IDs owned by a user. This information can be found in the tokens_per_owner data structure. To accomplish this, let's break it down into some smaller subtasks. First, you need to get access to a list of all token IDs owned by a user. This information can be found in the tokens_per_owner data structure. Now that you have a set of token IDs, you need to convert them into JsonToken objects as that's what you'll be returning from the function.

Luckily, you wrote a function nft_token which takes a token ID and returns a JsonToken in the nft_core.rs file. As you can guess, in order to get a list of JsonToken objects, you would need to iterate through the token IDs owned by the user and then convert each token ID into a JsonToken and store that in a list. As you can guess, in order to get a list of JsonToken objects, you would need to iterate through the token IDs owned by the user and then convert each token ID into a JsonToken and store that in a list.

As for the pagination, Rust has some awesome functions for skipping to a starting index and taking the first n elements of an iterator.

Let's move over to the enumeration.rs file and implement that logic:


Redeploying the contract

Now that you've implemented the necessary logic for nft_tokens_for_owner, it's time to build and re-deploy the contract to your account. Using the build script, deploy the contract as you did in the previous tutorial: Using the cargo-near, deploy the contract as you did in the previous tutorial:

cargo near deploy $NFT_CONTRACT_ID without-init-call network-config testnet sign-with-keychain send

Once the contract has been redeployed, let's test and see if the state migrated correctly by running a simple view function:

near contract call-function as-read-only $NFT_CONTRACT_ID nft_metadata json-args {} network-config testnet now

This should return an output similar to the following:

{
spec: 'nft-1.0.0',
name: 'NFT Tutorial Contract',
symbol: 'GOTEAM',
icon: null,
base_uri: null,
reference: null,
reference_hash: null
}

Go team! At this point, you can now test and see if the new function you wrote works correctly. Let's query for the list of tokens that you own: Let's query for the list of tokens that you own:

near contract call-function as-read-only $NFT_CONTRACT_ID nft_tokens_for_owner json-args '{"account_id": "'$NFT_CONTRACT_ID'", "limit": 5}' network-config testnet now
Example response:

[
{
token_id: 'token-1',
owner_id: 'goteam.examples.testnet',
metadata: {
title: 'My Non Fungible Team Token',
description: 'The Team Most Certainly Goes :)',
media: 'https://bafybeiftczwrtyr3k7a2k4vutd3amkwsmaqyhrdzlhvpt33dyjivufqusq.ipfs.dweb.link/goteam-gif.gif',
media_hash: null,
copies: null,
issued_at: null,
expires_at: null,
starts_at: null,
updated_at: null,
extra: null,
reference: null,
reference_hash: null
}
}
]


Viewing NFTs in the wallet

Now that your contract implements the necessary functions that the wallet uses to display NFTs, you should be able to see your tokens on display in the collectibles tab.

filled-nft-in-wallet


Conclusion

In this tutorial, you learned about the basics of upgrading contracts. In this tutorial, you learned about the basics of upgrading contracts. Then, you implemented the necessary modifications to your smart contract and redeployed it. Finally you navigated to the wallet collectibles tab and viewed your NFTs. Finally you navigated to the wallet collectibles tab and viewed your NFTs.

In the next tutorial, you'll implement the remaining functions needed to complete the enumeration standard.

Versioning for this article

At the time of this writing, this example works with the following versions:

  • rustc: 1.77.1
  • near-cli-rs: 0.11.0
  • cargo-near 0.6.1
  • NFT standard: NEP171, version 1.0.0
Was this page helpful?