Contract Interaction Methods
The @layerg-ua-sdk/aa-sdk
package provides powerful methods for interacting with smart contracts through Universal Accounts. These methods allow for seamless contract calls with proper encoding and transaction management.
Building Contract Requests
buildContractCallRequest
buildContractCallRequest(options: ContractCallOptions): UserOperationRequest
Creates a user operation request for a contract method call.
Parameters:
options: ContractCallOptions
- Options for the contract call:sender: string
- Address of the Universal Account sending the transactioncontractAddress: string
- Address of the target contractabi: Array | string
- Contract ABI or ABI fragment for the methodmethod: string
- Method name to callparams: any[]
- Parameters for the method callvalue?: string
- Optional ETH value to send with the call (in wei)
Returns:
UserOperationRequest
- Ready-to-send user operation request
Example:
import { buildContractCallRequest } from '@layerg-ua-sdk/aa-sdk';
const txRequest = buildContractCallRequest({
sender: '0xUniversalAccountAddress',
contractAddress: '0xContractAddress',
abi: CONTRACT_ABI, // Or specific method ABI fragment
method: 'mint',
params: [1, '0xRecipientAddress'],
value: '10000000000000000' // 0.01 ETH
});
// txRequest can now be sent using a provider
buildMultiCallRequest
buildMultiCallRequest(options: MultiCallOptions): UserOperationRequest
Creates a batched user operation that executes multiple contract calls in a single transaction.
Parameters:
options: MultiCallOptions
- Options for the batch:sender: string
- Address of the Universal Account sending the transactioncalls: ContractCall[]
- Array of contract calls to execute:contractAddress: string
- Target contract addressabi: Array | string
- Contract ABI or method fragmentmethod: string
- Method nameparams: any[]
- Method parametersvalue?: string
- Optional ETH value
Returns:
UserOperationRequest
- Ready-to-send user operation request for batch execution
Example:
import { buildMultiCallRequest } from '@layerg-ua-sdk/aa-sdk';
const multiCallRequest = buildMultiCallRequest({
sender: '0xUniversalAccountAddress',
calls: [
{
contractAddress: '0xToken1Address',
abi: ERC20_ABI,
method: 'approve',
params: ['0xSpenderAddress', '1000000000000000000'] // 1 token
},
{
contractAddress: '0xDexAddress',
abi: DEX_ABI,
method: 'swap',
params: ['0xToken1Address', '0xToken2Address', '1000000000000000000', '0']
}
]
});
// multiCallRequest can now be sent using a provider
buildERC20TransferRequest
buildERC20TransferRequest(options: ERC20TransferOptions): UserOperationRequest
Creates a user operation specifically for ERC-20 token transfers.
Parameters:
options: ERC20TransferOptions
- Options for the transfer:sender: string
- Address of the Universal AccounttokenAddress: string
- Address of the ERC-20 token contractrecipient: string
- Address of the recipientamount: string
- Amount to transfer (in smallest units)
Returns:
UserOperationRequest
- Ready-to-send user operation request
Example:
import { buildERC20TransferRequest } from '@layerg-ua-sdk/aa-sdk';
const tokenTransferRequest = buildERC20TransferRequest({
sender: '0xUniversalAccountAddress',
tokenAddress: '0xUSDCTokenAddress',
recipient: '0xRecipientAddress',
amount: '1000000' // 1 USDC (assuming 6 decimals)
});
// tokenTransferRequest can now be sent using a provider
Contract Execution
executeContractCall
executeContractCall(provider: LayerProvider, options: ContractCallOptions, sendOptions?: SendOptions): Promise<UserOperationResponse>
Builds and executes a contract call in a single function.
Parameters:
provider: LayerProvider
- Initialized Layer provideroptions: ContractCallOptions
- Contract call options (same asbuildContractCallRequest
)sendOptions?: SendOptions
- Optional sending options:sponsor?: boolean
- Whether to sponsor gas (default: false)maxPriorityFeePerGas?: string
- Max priority feemaxFeePerGas?: string
- Max fee
Returns:
Promise<UserOperationResponse>
- Response with transaction hash and wait function
Example:
import { executeContractCall, LayerProvider } from '@layerg-ua-sdk/aa-sdk';
// With provider already initialized
const result = await executeContractCall(
layerProvider,
{
sender: accountAddress,
contractAddress: '0xContractAddress',
abi: CONTRACT_ABI,
method: 'mint',
params: [1, accountAddress]
},
{ sponsor: true }
);
// Wait for transaction confirmation
const receipt = await result.wait();
console.log(`Transaction confirmed in block ${receipt.blockNumber}`);
executeMultiCall
executeMultiCall(provider: LayerProvider, options: MultiCallOptions, sendOptions?: SendOptions): Promise<UserOperationResponse>
Builds and executes a batch of contract calls in a single function.
Parameters:
provider: LayerProvider
- Initialized Layer provideroptions: MultiCallOptions
- Multi-call options (same asbuildMultiCallRequest
)sendOptions?: SendOptions
- Optional sending options
Returns:
Promise<UserOperationResponse>
- Response with transaction hash and wait function
Example:
import { executeMultiCall } from '@layerg-ua-sdk/aa-sdk';
const result = await executeMultiCall(
layerProvider,
{
sender: accountAddress,
calls: [
{
contractAddress: '0xToken1Address',
abi: ERC20_ABI,
method: 'approve',
params: ['0xSpenderAddress', '1000000000000000000']
},
{
contractAddress: '0xDexAddress',
abi: DEX_ABI,
method: 'swap',
params: ['0xToken1Address', '0xToken2Address', '1000000000000000000', '0']
}
]
},
{ sponsor: true }
);
// Transaction hash is immediately available
console.log(`User operation hash: ${result.userOpHash}`);
// Wait for transaction confirmation
const receipt = await result.wait();
console.log(`Multi-call executed in block ${receipt.blockNumber}`);
Event Handling
decodeEvents
decodeEvents(receipt: TransactionReceipt, abi: any, eventName?: string): any[]
Decodes events from a transaction receipt.
Parameters:
receipt: TransactionReceipt
- Transaction receiptabi: any
- Contract ABI containing event definitionseventName?: string
- Optional specific event name to decode
Returns:
any[]
- Array of decoded events
Example:
import { decodeEvents } from '@layerg-ua-sdk/aa-sdk';
// After getting a transaction receipt
const transferEvents = decodeEvents(receipt, ERC20_ABI, 'Transfer');
console.log('Transfer events:', transferEvents);
// All events
const allEvents = decodeEvents(receipt, CONTRACT_ABI);
console.log('All events:', allEvents);
waitForUserOperationReceipt
waitForUserOperationReceipt(userOpHash: string, chainId: number, timeout?: number): Promise<UserOperationReceipt>
Waits for a user operation to be included in a block and returns the receipt.
Parameters:
userOpHash: string
- User operation hash returned from sendUserOperationchainId: number
- Chain ID where the operation was senttimeout?: number
- Optional timeout in milliseconds (default: 60000)
Returns:
Promise<UserOperationReceipt>
- User operation receipt including transaction details
Example:
import { waitForUserOperationReceipt } from '@layerg-ua-sdk/aa-sdk';
// After sending a user operation
const receipt = await waitForUserOperationReceipt(userOpHash, 2484);
console.log(`Operation included in block ${receipt.receipt.blockNumber}`);
console.log(`Transaction hash: ${receipt.receipt.transactionHash}`);
// Decode events from the receipt
const events = decodeEvents(receipt.receipt, CONTRACT_ABI);
Error Handling
Contract interaction methods throw standardized errors when issues occur. Always implement proper error handling:
try {
const result = await executeContractCall(
layerProvider,
{
sender: accountAddress,
contractAddress: contractAddress,
abi: CONTRACT_ABI,
method: 'mint',
params: [tokenId, accountAddress]
}
);
// Process successful result
console.log(`User operation hash: ${result.userOpHash}`);
} catch (error) {
if (error.code === 'CONTRACT_EXECUTION_FAILED') {
console.error('Contract execution failed:', error.message);
// Check if there's additional error data
if (error.data && error.data.reason) {
console.error('Reason:', error.data.reason);
}
} else if (error.code === 'BUNDLER_ERROR') {
console.error('Bundler error:', error.message);
} else {
console.error('Unknown error:', error);
}
}
Gas Estimation
estimateGasForContractCall
estimateGasForContractCall(provider: LayerProvider, options: ContractCallOptions): Promise<GasEstimate>
Estimates gas for a contract call.
Parameters:
provider: LayerProvider
- Initialized Layer provideroptions: ContractCallOptions
- Contract call options
Returns:
Promise<GasEstimate>
- Gas estimate object:gas: string
- Estimated gas limitmaxFeePerGas: string
- Recommended max fee per gasmaxPriorityFeePerGas: string
- Recommended max priority fee per gas
Example:
import { estimateGasForContractCall } from '@layerg-ua-sdk/aa-sdk';
const gasEstimate = await estimateGasForContractCall(
layerProvider,
{
sender: accountAddress,
contractAddress: '0xContractAddress',
abi: CONTRACT_ABI,
method: 'mint',
params: [1, accountAddress]
}
);
console.log(`Estimated gas: ${gasEstimate.gas}`);
console.log(`Max fee per gas: ${gasEstimate.maxFeePerGas}`);
Next Steps
- Learn about Providers for interacting with the blockchain
- See Account APIs for account management functionality
- Check the aa-smc package for smart contract integration details