Documentation Index
Fetch the complete documentation index at: https://mintlify.com/frol/near-connect-ios/llms.txt
Use this file to discover all available pages before exploring further.
Overview
ThecallFunction() method allows you to call smart contract functions on NEAR. The wallet signs and broadcasts the transaction containing the function call.
Basic Contract Call
Call a contract function with arguments:do {
let result = try await walletManager.callFunction(
contractId: "guest-book.near",
methodName: "add_message",
args: ["text": "Hello from iOS!"],
deposit: "0" // yoctoNEAR
)
print("Transaction hash: \(result.transactionHashes.first ?? "")")
} catch {
print("Contract call failed: \(error.localizedDescription)")
}
Method Parameters
public func callFunction(
contractId: String, // Contract account ID
methodName: String, // Function name to call
args: [String: Any], // Arguments as JSON dictionary
gas: String, // Gas limit in yoctoGas (default: 30 TGas)
deposit: String // Attached NEAR in yoctoNEAR (default: 0)
) async throws -> TransactionResult
Parameters Explained
- contractId: The account ID of the smart contract (e.g.,
"guest-book.near","v2.ref-finance.near") - methodName: The name of the contract function to call
- args: Function arguments as a dictionary (automatically converted to JSON and base64-encoded)
- gas: Maximum gas to attach (default is 30 TGas = 30000000000000 yoctoGas)
- deposit: Amount of NEAR to attach to the call in yoctoNEAR (default is 0)
Gas is specified in yoctoGas (1 TGas = 10¹² yoctoGas). Most function calls use 30-300 TGas.
Complete Example: Guest Book
Here’s the real contract call demo from the example app:import SwiftUI
import NEARConnect
struct MessageSigningDemoView: View {
@EnvironmentObject var walletManager: NEARWalletManager
@State private var contractId = "guest-book.near"
@State private var methodName = "add_message"
@State private var argsText = "{\"text\": \"Hello from iOS!\"}"
@State private var deposit = "0"
@State private var isProcessing = false
@State private var showError = false
@State private var errorMessage = ""
var body: some View {
Form {
Section(header: Text("Contract Call")) {
HStack {
Text("Signer")
.foregroundColor(.secondary)
Spacer()
Text(walletManager.currentAccount?.accountId ?? "")
.font(.caption)
}
TextField("Contract ID", text: $contractId)
.textInputAutocapitalization(.never)
.autocorrectionDisabled()
TextField("Method Name", text: $methodName)
.textInputAutocapitalization(.never)
.autocorrectionDisabled()
VStack(alignment: .leading, spacing: 4) {
Text("Arguments (JSON)")
.font(.caption)
.foregroundColor(.secondary)
TextEditor(text: $argsText)
.font(.system(.body, design: .monospaced))
.frame(height: 80)
}
HStack {
TextField("Deposit", text: $deposit)
.keyboardType(.decimalPad)
Text("NEAR")
.foregroundColor(.secondary)
}
}
Section {
Button(action: callContract) {
HStack {
Spacer()
if isProcessing {
ProgressView()
.padding(.trailing, 8)
}
Text(isProcessing ? "Calling..." : "Call Contract")
Spacer()
}
}
.disabled(isProcessing || contractId.isEmpty || methodName.isEmpty)
}
}
.alert("Error", isPresented: $showError) {
Button("OK", role: .cancel) { }
} message: {
Text(errorMessage)
}
}
private func callContract() {
guard let argsData = argsText.data(using: .utf8),
let args = try? JSONSerialization.jsonObject(with: argsData) as? [String: Any] else {
errorMessage = "Invalid JSON arguments"
showError = true
return
}
let depositYocto = NEARWalletManager.toYoctoNEAR(deposit) ?? "0"
Task {
isProcessing = true
defer { isProcessing = false }
do {
let txResult = try await walletManager.callFunction(
contractId: contractId,
methodName: methodName,
args: args,
deposit: depositYocto
)
let hashes = txResult.transactionHashes.joined(separator: ", ")
print("✅ Transaction hashes: \(hashes)")
} catch {
errorMessage = error.localizedDescription
showError = true
}
}
}
}
Common Contract Patterns
Simple Function Call (No Arguments)
let result = try await walletManager.callFunction(
contractId: "counter.near",
methodName: "increment",
args: [:], // Empty dictionary for no arguments
deposit: "0"
)
Function Call with Multiple Arguments
let result = try await walletManager.callFunction(
contractId: "marketplace.near",
methodName: "make_offer",
args: [
"nft_contract_id": "nft.near",
"token_id": "123",
"price": "5000000000000000000000000" // 5 NEAR in yoctoNEAR
],
deposit: "5000000000000000000000000"
)
Function Call with Attached NEAR
// Buy NFT - attach payment
let result = try await walletManager.callFunction(
contractId: "nft-marketplace.near",
methodName: "buy",
args: ["token_id": "42"],
deposit: "10000000000000000000000000" // 10 NEAR
)
Function Call with Custom Gas
// Complex operation requiring more gas
let result = try await walletManager.callFunction(
contractId: "defi.near",
methodName: "swap",
args: [
"token_in": "usdc.near",
"token_out": "near",
"amount": "1000000" // 1 USDC
],
gas: "100000000000000", // 100 TGas
deposit: "1" // 1 yoctoNEAR for storage
)
Handling Complex Arguments
Nested Objects
let args: [String: Any] = [
"proposal": [
"title": "Increase treasury allocation",
"description": "Proposal to increase allocation to 10%",
"actions": [
["type": "Transfer", "amount": "1000"]
]
]
]
let result = try await walletManager.callFunction(
contractId: "dao.near",
methodName: "add_proposal",
args: args
)
Arrays
let args: [String: Any] = [
"account_ids": ["alice.near", "bob.near", "carol.near"],
"amounts": ["100", "200", "300"]
]
let result = try await walletManager.callFunction(
contractId: "token.near",
methodName: "batch_transfer",
args: args
)
Error Handling
Handle contract-specific errors:do {
let result = try await walletManager.callFunction(
contractId: contractId,
methodName: methodName,
args: args,
deposit: deposit
)
print("✅ Contract call successful")
} catch NEARError.notSignedIn {
print("❌ Please connect a wallet first")
} catch NEARError.operationInProgress {
print("❌ Another operation is in progress")
} catch NEARError.walletError(let message) {
// Parse contract panics and errors
if message.contains("Smart contract panicked") {
print("❌ Contract panic: \(message)")
} else if message.contains("insufficient") {
print("❌ Insufficient balance or allowance")
} else {
print("❌ Contract error: \(message)")
}
} catch {
print("❌ Unexpected error: \(error.localizedDescription)")
}
Contract function calls require gas. If the contract operation runs out of gas, the transaction will fail. Increase the
gas parameter for complex operations.View Functions (Read-Only)
For read-only contract queries that don’t modify state, use RPC directly instead ofcallFunction():
struct ContractViewCall {
static func viewFunction(
contractId: String,
methodName: String,
args: [String: Any],
network: NEARWalletManager.Network = .mainnet
) async throws -> Any {
let rpcURL = network == .mainnet
? "https://rpc.mainnet.near.org"
: "https://rpc.testnet.near.org"
let argsJSON = try JSONSerialization.data(withJSONObject: args)
let argsBase64 = argsJSON.base64EncodedString()
let body: [String: Any] = [
"jsonrpc": "2.0",
"id": "1",
"method": "query",
"params": [
"request_type": "call_function",
"finality": "final",
"account_id": contractId,
"method_name": methodName,
"args_base64": argsBase64
]
]
let data = try JSONSerialization.data(withJSONObject: body)
var request = URLRequest(url: URL(string: rpcURL)!)
request.httpMethod = "POST"
request.httpBody = data
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let (responseData, _) = try await URLSession.shared.data(for: request)
let json = try JSONSerialization.jsonObject(with: responseData)
guard let response = json as? [String: Any],
let result = response["result"] as? [String: Any],
let resultArray = result["result"] as? [Int] else {
throw NEARError.rpcError("Invalid response")
}
// Convert byte array to Data
let resultData = Data(resultArray.map { UInt8($0) })
return try JSONSerialization.jsonObject(with: resultData)
}
}
// Usage
let balance = try await ContractViewCall.viewFunction(
contractId: "token.near",
methodName: "ft_balance_of",
args: ["account_id": "alice.near"]
)
Gas Estimation Guidelines
Gas Guidelines:
- Simple storage operations: 30 TGas (default)
- Token transfers (FT/NFT): 50-100 TGas
- Cross-contract calls: 100-200 TGas
- Complex DeFi operations: 200-300 TGas
// Convert TGas to yoctoGas
func tGasToYocto(_ tGas: Int) -> String {
return "\(tGas)000000000000"
}
let gas30TGas = tGasToYocto(30) // "30000000000000"
let gas100TGas = tGasToYocto(100) // "100000000000000"