Smart Contract Interactions
Last updated
Last updated
The Send Contract Transaction action enables you to interact with a smart contract by sending a transaction to a specified contract address. It utilizes a JSON stringified representation of the contract's ABI (Application Binary Interface), focusing specifically on the function you intend to call. Although you can provide the complete ABI, it is recommended to include only the specific function being called for better optimization.
Contract Address: The address of the smart contract.
ABI: A JSON stringified representation of the ABI (Application Binary Interface). It is recommended to include only the relevant function for optimization. You can get it from a blockchain scan for example: https://amoy.polygonscan.com/address/0x35214dc712C4F1571ec7F6cf957c3050ca8e863D#code
You can pass only a single definition of the function that will be used during contract interaction or the whole ABI element
Function Name: The name of the function being called in the ABI
Input Data: A JSON stringified representation of the input data required for the function call. Example format:
Chain ID: The target chain ID (in decimals) specifies the blockchain network where the transaction will be sent. https://chainlist.org/
Check Account: First, the function checks if your account is available. If you're not connected to an account, it will stop and show an error message saying the account is missing.
Prepare the Contract: It checks the technical setup of the contract to ensure the function you're calling exists. If it doesn’t, you’ll get an error saying the function isn’t found. It also checks that the inputs you’ve given (like addresses or values) match what the function expects.
Set Status to Pending: Once everything looks good, the transaction status is set to "pending." This means that the transaction is about to start.
Switch to the Correct Network: The function makes sure you're on the correct blockchain network (like Ethereum or Binance Smart Chain) to send the transaction. This happens automatically.
Estimate Fees: It calculates how much gas (or transaction fee) is needed for the action you're about to do on the blockchain. This ensures you don’t run out of gas during the transaction.
Send the Transaction: The transaction is sent to the blockchain. If you’re sending tokens, it makes sure the amount and recipient are correct. It also takes the current network fee into account to avoid overpaying for gas. Once it’s sent, you’ll get a transaction hash—a unique code that tracks the transaction.
Wait for Confirmation: The function waits for the transaction to be confirmed by the blockchain. It checks every few seconds to see if the transaction has gone through. If it takes too long (more than 2 minutes), it stops and tells you the confirmation timed out.
Final Status:
If the transaction goes through successfully, it updates the status to "success."
If something goes wrong (like the transaction fails or is rejected), the status changes to "error" and it tells you what went wrong.
Error Handling: If something goes wrong at any point—whether it’s a connection issue, an error with the contract, or a transaction failure—the function will stop, log the problem, and show you an error message so you know what happened.
Once the transaction is successfully sent and confirmed, the action updates the last transaction hash, which can be retrieved using the Get Last Transaction Hash expression. Additionally, the On Transaction Sent condition is triggered, indicating that the transaction has been successfully processed and confirmed.
The Set Transaction Status action allows you to manually update the internal status of the transaction. This can be useful for debugging or custom logic where you need to set a specific status based on the flow of your application.
Status: A string representing the new status of the transaction (e.g., "pending", "success", "error"
).
The Get Transaction Status expression retrieves the current status of the last transaction processed. It returns the status as a string, allowing you to check if a transaction is pending, successful, or has encountered an error. This expression is useful for displaying the status or making decisions based on the transaction outcome.
The Read Contract Data action allows you to interact with a smart contract by calling a function and reading data from it. This action uses a JSON stringified representation of the contract's Application Binary Interface (ABI) and focuses on the function you want to read from. While you can provide the entire ABI, it is recommended to only include the specific function being called to optimize the request by reducing unnecessary data.
Contract Address: The address of the smart contract.
ABI: A JSON stringified representation of the ABI (Application Binary Interface)
Function Name: The name of the function being called in the ABI
Input Data: A JSON stringified representation of the input data required for the function call. Example format:
RPC URL: The URL of the Remote Procedure Call (RPC) endpoint for interacting with the blockchain. https://chainlist.org/
Understanding the Contract: The function starts by looking at the provided ABI (the blueprint of the contract). It uses the function name you provided to find the specific part of the contract you're trying to interact with. If the function doesn’t exist, you’ll get an error saying the function wasn’t found.
Check Your Inputs: The data you’re sending (like addresses or amounts) is checked to make sure it matches what the contract function expects. If the number of inputs doesn’t match, the function will stop and show an error, helping you avoid sending wrong data.
Connect to the Blockchain: The function connects to the blockchain using a Web3 provider. This is like connecting to the internet but for blockchain. It uses the URL you provide to talk to the right blockchain network.
Set Up the Contract: Once connected, the function gets ready to interact with the contract by setting it up with the provided contract address and the ABI (contract blueprint). This allows the function to communicate directly with the deployed smart contract.
Fetch Data from the Contract: The contract’s function is called using the inputs you provided (e.g., addresses, token amounts). It fetches the data you want from the blockchain, like checking balances or getting transaction details.
Prepare the Data: Once the data is retrieved from the contract, it’s formatted and stored in a special variable for later use. This makes it easier to read and use later in your project.
Success Notification: After the data is successfully retrieved and stored, the function triggers an event to let you know the contract data has been received. This is like a notification saying the task is complete.
Error Handling: If anything goes wrong—whether it’s an issue with the function, inputs, or blockchain interaction—the error is logged and you’ll get a message explaining what went wrong. This helps you understand and fix the issue quickly.
Once the data is successfully read, the action updates the last read contract data, which can be retrieved using the Get Last Read Contract Data expression. Additionally, the On Contract Data Received condition is triggered, indicating that the data has been successfully retrieved from the contract.
The Read Multiple Contract Data action allows for reading data from multiple functions of a smart contract in a single request. This is particularly useful when you need to fetch various pieces of data from a contract without making multiple separate requests, thus improving efficiency
Contract Address: The address of the smart contract to interact with.
ABI: A JSON stringified representation of the contract's ABI (Application Binary Interface). The ABI defines the functions and events of the contract.
Function Names: A JSON stringified array containing the names of the functions to call. Each function should be present in the provided ABI.
Inputs Data: A JSON stringified array where each element corresponds to the input data for each function being called. The input data should match the number and order of arguments expected by each function.
RPC URL: The RPC endpoint for interacting with the blockchain. https://chainlist.org/
Reading the Contract's Blueprint (ABI): The ABI is like the instructions manual for a smart contract. This function reads the ABI to understand what the contract can do. If there’s a problem with this step, like if the ABI isn’t formatted properly, it will stop and let you know.
Understanding What Functions and Inputs Are Needed: The function names (what the contract is supposed to do) and the input data (the details the contract needs to perform those functions) are checked. It makes sure everything matches correctly. For example, if you’re trying to use a function that doesn’t exist or provide the wrong details, it will stop and show an error.
Connecting to the Blockchain: The function connects to the blockchain using the URL you’ve provided. This step is important because it allows the function to communicate with the smart contract and ask it to do something.
Setting Up Communication with the Contract: Once connected, the function sets up a way to talk to the smart contract by using the ABI and contract address. This is like opening a channel to send requests to the contract.
Calling Multiple Functions: The function then goes through each of the functions you’ve listed, checks that it exists in the contract, and makes sure the inputs are correct. If everything matches, it will call the contract to perform that action. If something doesn’t match, it will stop and inform you.
Running Everything at Once: Since multiple functions can be called, the function handles them all at the same time in the background. This means it can get all the results as quickly as possible without waiting for each one individually.
Saving the Results: Once the contract has completed all its tasks, the results are organized and saved for future use. You’ll be able to see the results in a format that’s easy to understand.
Notifying You When It’s Done: After everything is completed successfully, the function sends a signal (OnMultipleReadContractDataReceived) to let you know the process is finished and the data is ready.
Handling Problems: If something goes wrong at any step—whether it’s a missing function, wrong input, or an issue connecting to the blockchain—the function logs the problem and alerts you with an error message, so you can fix it easily.
Once the data is successfully read, the action updates the last multiple-read contract data, which can be retrieved using the Get Multiple Last Read Contract Data expression. Additionally, the On Multiple Contract Data Received condition is triggered, indicating that the data has been successfully retrieved from the contract.
The Send Crypto action enables the user to send a specified amount of cryptocurrency (native token or ERC-20 tokens) to a given recipient's address. The function automatically switches to the target chain if necessary and uses either the native chain token (e.g., ETH, MATIC) or tokens from a specified contract address.
Token Address (optional): The contract address of the token being transferred (leave empty (e.g. "") for native currency)
Amount: The amount of cryptocurrency or token to be sent. Provided in proper stringified unit. For unit conversion look: https://etherscan.io/unitconverter
Receiver: The address of the recipient who will receive the funds
Chain ID: The target blockchain network (in decimals) on which the transaction will be executed. https://chainlist.org/
Native Token Transfer: If no token address is provided, the function will treat this as a native cryptocurrency transfer. It estimates the gas required, gets the current gas price, and sends the specified amount to the receiver's address.
Token Transfer: If a token address is provided, the function will transfer an ERC-20 token by interacting with the transfer
method from the ERC-20 ABI. It estimates the gas for the transaction, retrieves the gas price, and performs the transfer.
Transaction Status Tracking: The transaction status is set to pending
when the transaction starts. It waits for the transaction confirmation, using a timeout of 120 seconds. During this period, the function periodically checks if the transaction has been confirmed by retrieving its receipt. If confirmed, the status is updated to success
; if not, it is set to error
.
Error Handling: If the transaction fails, or if the confirmation timeout is reached, an error is thrown.
Once the transaction is successfully sent, the action triggers the On Transaction Sent condition, and the transaction hash can be retrieved using the Get Last Transaction Hash expression.
The first thing we do in the On start layout event is call the Request user score action from the metapro plugin (1) to determine the user's current points balance. After retrieving it, we assign the value fetched from the metapro plugin's Get Current Score expression (2) to the global variable currentScore
. Based on this, we are able to assign the value to the text object Shop_CurrentScore_Text
.
Each of the following spaceship (except the default one) is a representation of an ERC-1155 token, which a player can own upon purchase (minting), provided they have sufficient funds. On the On start layout event, we call a defined function in Construct 3 called getUserTokenBalance
(1). The given function contains a call to the Read contract data action (2) from the metapro plugin, which accepts the following parameters:
Contract Address
"0x35214dc712C4F1571ec7F6cf957c3050ca8e863D"
ABI
[ { "inputs": [ { "internalType": "address[]", "name": "accounts", "type": "address[]" }, { "internalType": "uint256[]", "name": "ids", "type": "uint256[]" } ], "name": "balanceOfBatch", "outputs": [ { "internalType": "uint256[]", "name": "", "type": "uint256[]" } ], "stateMutability": "view", "type": "function" } ]
Function Name
balanceOfBatch
Input Data
"[['"& userAccount &"', '"& userAccount &"', '"& userAccount &"'], [1,2,3]]"
NOTE: The global variable userAccount
is fetched from the metapro plugin's Get Account expression, which represents the user's account retrieved from the Web 3 provider at the start of the application.
RPC URL
"https://rpc-amoy.polygon.technology/"
The contract address "0x35214dc712C4F1571ec7F6cf957c3050ca8e863D"
contains a function called balanceOfBatch
. This function takes two inputs:
An array of account addresses (in this case, three instances of the userAccount
, which represents the player's wallet address).
An array of token IDs ([1, 2, 3]
), which correspond to the different spaceships or NFTs the player can own.
The purpose of calling this function is to fetch the balances of these tokens (IDs 1, 2, and 3) for the player's account. The contract will return an array of balances for each of the requested token IDs, where:
A positive value means the player owns the corresponding token.
A value of 0
means the player does not own that token.
For example, the input data would look like this: [['userAccount', 'userAccount', 'userAccount'], [1, 2, 3]]
, which asks for the balances of token IDs 1, 2, and 3 for the player's account (userAccount
).
By calling this function, we want to determine which spaceships the player owns and how many of each, allowing us to update the shop interface based on their ownership status.
When the contract data is successfully read, the On Contract Data Received event (3) is triggered, where we retrieve the saved data from the Get Last Read Contract Data expression into a JSON under the key userNfts
. This is done to further process the data and determine the status of the buttons under each spaceship in the shop—the function updateShipData
(4) is responsible for this.
updateShipData
script:
This code is responsible for managing and updating the availability and status of different spaceships in a game shop based on the player's ownership and selection.
Spaceship List: The game has several spaceships (like Cerbal_2, Cerbal_3, etc.), each represented by an ID. There is also a default ship (Cerbal_1).
Player's Ownership: The game checks which spaceships the player owns by looking at their NFT balances, which are retrieved from the previously read contract data and saved in a local JSON. If the player owns a specific spaceship, the balance for that ship will be greater than 0.
The userNfts
data is stored in a JSON format like this:
In this example, we are checking tokens [1, 2, 3], and each result represents the balance for the corresponding spaceship at the same index. So, token 1 has a balance of 1 (owned), token 2 has a balance of 0 (not owned), and token 3 has a balance of 1 (owned).
Ship Button Updates: For each spaceship, the code updates the corresponding button in the shop:
If the player selected a spaceship (comparing it to the selectedShip
global variable), the button displays "SELECTED."
If the player owns a spaceship but hasn’t selected it, the button displays "SELECT."
If the player doesn’t own the spaceship, the button displays the spaceship's price in points (PT).
In short, this logic ensures the shop displays the correct options (price, select, or selected) for each spaceship based on the player's ownership and current selection.
On the On start layout, we call the getTokenMaxMints
function (1) to determine how many of each specific NFT the player has already minted and what the maximum minting limit per player is. The given function contains the Read Multiple Contract Data action (2) from the metapro plugin, which will check the above data for each spaceship. To achieve this, we will use the following parameters:
Contract Address
"0x35214dc712C4F1571ec7F6cf957c3050ca8e863D"
ABI
[ { "inputs":[ { "internalType":"uint256", "name":"_tokenId", "type":"uint256" } ], "name":"tokenMaxMints", "outputs":[ { "internalType":"uint256", "name":"", "type":"uint256" } ], "stateMutability":"view", "type":"function" }, { "inputs":[ { "internalType":"address", "name":"_wallet", "type":"address" }, { "internalType":"uint256", "name":"_tokenId", "type":"uint256" } ], "name":"walletMintsOf", "outputs":[ { "internalType":"uint256", "name":"", "type":"uint256" } ], "stateMutability":"view", "type":"function" } ]
Function Names
"['tokenMaxMints','walletMintsOf','tokenMaxMints','walletMintsOf','tokenMaxMints','walletMintsOf']"
Input Data
"[[1],['"&userAccount&"', 1], [2],['"&userAccount&"', 2], [3],['"&userAccount&"', 3]]"
NOTE: The global variable userAccount
is fetched from the metapro plugin's Get Account expression, which represents the user's account retrieved from the Web 3 provider at the start of the application.
RPC URL
"https://rpc-amoy.polygon.technology/"
We are interacting with a smart contract at the address:
Contract Address: "0x35214dc712C4F1571ec7F6cf957c3050ca8e863D"
We are using two functions—tokenMaxMints
and walletMintsOf
—to retrieve specific data for each spaceship (NFT) the player interacts with. The purpose of this call is twofold:
tokenMaxMints
: This function checks the maximum number of times each specific NFT (spaceship) can be minted by a player. For example, we want to know the maximum minting limit for token IDs 1, 2, and 3 (which correspond to different spaceships).
walletMintsOf
: This function checks how many times the player has already minted a specific NFT. We will check this for the current player’s wallet (userAccount
) and for each spaceship (NFT token IDs 1, 2, and 3).
The input data is structured as follows:
The first parameter for tokenMaxMints
is the token ID (1, 2, or 3).
The parameters for walletMintsOf
include the player's wallet address (userAccount
) and the token ID (1, 2, or 3).
For example:
tokenMaxMints(1)
retrieves the maximum number of times the player can mint the first spaceship.
walletMintsOf(userAccount, 1)
retrieves how many times the player has already minted the first spaceship.
This same process is repeated for token IDs 2 and 3.
So, we are calling multiple functions to:
Retrieve the maximum number of mints allowed per player for tokens 1, 2, and 3.
Retrieve the number of times the current player (userAccount
) has already minted tokens 1, 2, and 3.
By combining these results, we can determine both the minting limit and the player's current minting status for each spaceship.
When the data is successfully received, the On Multiple Contract Data Received event (3) will be triggered, indicating that we can retrieve the data using the Get Multiple Last Read Contract Data expression. This data will be used to set the labels under each spaceship as follows: MINTS ${number_of_user_mints} of ${number_of_token_max_mints}. Script:
This code updates the display in a game shop to show how many times a player can mint (create) a specific spaceship (NFT) and how many they have already minted. Here's how it works:
Text Objects: The game has text objects that show two things:
The maximum number of mints allowed for each spaceship (ShopMaxMintsText
).
The number of mints the player has already done for each spaceship (ShopCurrentMintsText
).
Mapping Spaceships: The code uses a predefined list (called functionMapping
) to match each spaceship with its minting information (maximum mints and current mints). Each spaceship in the game is identified by a tag like C3
, C2
, or C4
, which helps the code find the correct spaceship to update.
Pulling Mint Data: The data about minting is stored in a JSON format, which looks like this:
The first number (e.g., 5, 10, 1) shows how many times the player can mint that spaceship.
The second number (e.g., 0, 0, 0) shows how many times the player has already minted that spaceship.
Updating the Shop: The code checks if the data is correct and avoids errors. Then, based on the tag (like C3
, C2
, or C4
), it updates the text for each spaceship in the shop to show the current mint status, such as:
"Mints 5" (how many times you can mint this spaceship).
"of 0" (how many times a player already minted it).
In summary, this code ensures the shop accurately shows how many times the player can mint each spaceship and how many they’ve already minted.
In order to purchase a spaceship in the Stellar Ride shop, we first need to mint the NFT that corresponds to the selected spaceship. Our application allows this action if the player does not already own the given NFT and has a sufficient number of points in their account (current balance). When these conditions are met, on the On touch event, we call the defined function mintShip
(1) to initiate the process of interacting with the smart contract and the subsequent logic involved in purchasing the spaceship.
The mintShip
function accepts parameters specifying the token ID of the spaceship being minted and the local name we have assigned to that specific spaceship. The first thing we do is set the global variable processedShipName
to the value of shipName
, indicating that a minting process is underway and specifying which spaceship is being processed in the transaction. Next, we set the properties of a modal on the UI to inform the player that the transaction is in progress. Finally, we call the actual Send contract transaction action (2) from the metapro plugin, which is responsible for minting the selected NFT on the blockchain for the player. To achieve this, we will use the following parameters:
Contract Address
"0x35214dc712C4F1571ec7F6cf957c3050ca8e863D"
ABI
[ { "inputs": [ { "internalType": "address", "name": "_to", "type": "address" }, { "internalType": "uint256", "name": "_tokenId", "type": "uint256" }, { "internalType": "uint256", "name": "_amount", "type": "uint256" }, { "internalType": "bytes", "name": "data", "type": "bytes" } ], "name": "mint", "outputs": [], "stateMutability": "nonpayable", "type": "function" } ]
Function Name
"mint"
Input Data
"['"& userAccount & "', "& tokenID &", "& amount &", '0x']"
NOTE: The global variable userAccount
is fetched from the metapro plugin's Get Account expression, which represents the user's account retrieved from the Web 3 provider at the start of the application.
Chain ID
80002
We are interacting with a smart contract at the address:
Contract Address: "0x35214dc712C4F1571ec7F6cf957c3050ca8e863D"
The contract has a mint
function that allows us to mint (create) a new NFT for the player. Here's how the process works:
Function Name: The function we are calling is named mint
.
Input Parameters:
_to
: The player's wallet address, represented by the userAccount
variable. This is the address to which the minted NFT will be assigned.
_tokenId
: The ID of the spaceship (NFT) being minted, passed as the tokenID
variable from function parameter.
_amount
: The number of NFTs to mint, passed as the amount
variable from function parameter (usually 1).
data
: An additional data parameter, passed as '0x'
, which is commonly used as a placeholder in minting operations.
Chain ID: The transaction will be executed on the blockchain with Chain ID 80002, which represents the testnet version of Polygon (Amoy).
Action: We are sending a transaction using the mint
function of the contract. This transaction will mint the specified spaceship NFT for the player, transferring it to their wallet address (userAccount
).
The goal of this transaction is to mint a new spaceship (NFT) for the player if they meet the required conditions (sufficient balance, not already owning the spaceship).
Once the transaction is successfully executed on the blockchain, the spaceship (NFT) will be transferred to the player's account and we will receive a transaction hash from Get Last Transaction Hash expression.
When the transaction is confirmed (appears on the blockchain), the On Transaction Sent event is triggered. Our application checks if the global variable processedShipName
has a value assigned, which indicates that we are currently minting a spaceship. If this condition is met, we run a script that calls the function onShipHasMinted
(3). This function is passed information from the Construct instance variables of the spaceship. The spaceship data includes:
The price of the spaceship (shipData.Price
).
The local name of the spaceship (e.g., Cerbal_2
).
The spaceship data is retrieved from the Construct instance by using the processedShipName
to reference the specific spaceship currently being processed.
The function onShipHasMinted
, triggered after a successful blockchain transaction, begins by updating the player's current score through the Update user score action from the metapro plugin. It then updates the text displayed on the UI using the Get Current Score expression. The global variable selectedShip
is set to the newly minted local name of the spaceship, indicating that the player has selected this spaceship as active for the game. Next, we reset the transaction-related variables, such as processedShipName
, modal properties used on the UI, and using the Set transaction status action from the metapro plugin, we change the transaction status back to "initial"
. Additionally, we refresh the player's data by calling getUserTokenBalance and getTokenMaxMint.
During the minting process (when the variable processedShipName
is different from an empty string), every second we listen for potential errors. To do this, we check the Get Transaction Status expression from the metapro plugin to see if it is equal to "error"
. If at any point the transaction throws an error (indicating that the minting process has failed), we inform the player by updating the modal properties on the UI and reset the transaction-related variables, just as we would in the case of a successful transaction.