Skip to main content

Interact with Your Rollup

This guide demonstrates how developers can interact with rollups from their code. We'll cover connecting to the Elder testnet, preparing transactions, and sending them to the rollup.

Connect to Elder Testnet

The first step is to establish a connection to the Elder testnet. This involves signing a message with your Ethereum wallet to derive your Elder address and public key.

import { eth_getElderAccountInfoFromSignature } from 'elderjs'; 
import type { Signer } from 'ethers';

type ConnectParams = {
roll_id: number;
chain_id: bigint;
eth_rpc: string;
message?: string;
};

const ELDER_testnet = process.env.ELDER_testnet;
const ELDER_REST_URL = process.env.ELDER_REST;
const ELDER_RPC_URL = process.env.ELDER_RPC;

let elder_address = '';
let elder_public_key = '';

async function connect(signer: Signer, params: ConnectParams) {
const message = params.message || `Connect to Elder ${ELDER_testnet}`;

const signature = await signer.signMessage(message);

const { recoveredPublicKey, elderAddr } = await eth_getElderAccountInfoFromSignature(
message,
signature
);

elder_address = elderAddr;
elder_public_key = recoveredPublicKey;

return {
roll_id: params.roll_id,
chain_id: params.chain_id,
eth_rpc: params.eth_rpc,
eth_address: (await signer.getAddress()) as `0x${string}`,
elder_address: elderAddr,
elder_public_key: recoveredPublicKey,
signer,
};
}

Understanding the Connection Process

When connecting to the Elder testnet, the function:

  1. Signs a message using your Ethereum wallet
  2. Derives your Elder address and public key from the signature
  3. Returns connection details including both Ethereum and Elder addresses

The elder_address and elder_public_key are crucial as they'll be used when building raw Elder transactions.

Prepare Ethereum Transaction Object

Before sending a transaction to the rollup, you need to prepare an Ethereum transaction object. This can be a PreparedTransactionRequest, PopulatedTransactionRequest, ContractTransaction, or any TransactionLike object.

// Example of preparing a transaction from a contract function
const tx = await didRegistry.connect(signer).getFunction("function_name").populateTransaction(
...args
);

You can prepare transactions for any contract interaction, token transfer, or other operations supported by the rollup.

Send Elder Transaction

Once you have prepared your transaction, you can send it to the Elder network using the following code:

import { ElderConfig, eth_broadcastTx, eth_getElderMsgAndFeeTxRaw } from 'elderjs';
import { TransactionLike } from 'ethers';

type BigNumberish = string | number | bigint;

const config = {
rest: ELDER_REST_URL,
rpc: ELDER_RPC_URL,
chainName: ELDER_testnet,
rollID: Number(ELDER_ROLL_ID),
rollChainID: Number(ROLLUP_CHAIN_ID),
eth_rpc: ROLLUP_ETH_RPC,
};

async function sendTransaction(
tx: TransactionLike<string>,
opts?: { gasLimit?: BigNumberish; value?: BigNumberish }
) {
opts = {
gasLimit: opts?.gasLimit || 10_000_000,
value: opts?.value || parseEther('0'),
};

if (
typeof elder_address === 'undefined' ||
typeof elder_public_key === 'undefined' ||
typeof config === 'undefined'
)
throw new Error('network not connected');

let { tx_hash, rawTx } = await eth_getElderMsgAndFeeTxRaw(
tx,
elder_address,
elder_public_key,
opts.gasLimit!,
opts.value!,
config
);
let broadcastResult = await eth_broadcastTx(rawTx, config.rpc);

return { tx_hash, result: broadcastResult };
}

Using the sendTransaction Function

To send your prepared transaction to the rollup:

// Import parseEther if needed
import { parseEther } from 'ethers';

// Send the transaction with optional parameters
const { result, tx_hash } = await sendTransaction(tx, {
value: parseEther(amount), // Amount of ETH to send with the transaction
gasLimit: 1000000, // Gas limit for the transaction
});

console.log(`Transaction sent with hash: ${tx_hash}`);
console.log('Transaction result:', result);

Complete Example

Here's how you might use these functions together in a complete workflow:

import { Wallet } from 'ethers';
import { eth_getElderAccountInfoFromSignature, eth_broadcastTx, eth_getElderMsgAndFeeTxRaw } from 'elderjs';

// Initialize your wallet with a private key
const wallet = new Wallet('your-private-key');

// Connect to Elder network
const connection = await connect(wallet, {
roll_id: 1,
chain_id: 1n,
eth_rpc: 'https://your-eth-rpc-url',
});

// Prepare a transaction (example with a contract)
const contract = new Contract(contractAddress, contractABI, wallet);
const tx = await contract.getFunction("transfer").populateTransaction(
recipientAddress,
parseEther("0.1")
);

// Send the transaction
const { result, tx_hash } = await sendTransaction(tx, {
gasLimit: 1000000,
});

console.log(`Transaction sent with hash: ${tx_hash}`);

Environment Variables

Make sure to set up the following environment variables for your application:

ELDER_testnet=your-testnet-name
ELDER_REST=https://your-elder-rest-url
ELDER_RPC=https://your-elder-rpc-url
ELDER_ROLL_ID=your-roll-id
ROLLUP_CHAIN_ID=your-rollup-chain-id
ROLLUP_ETH_RPC=https://your-rollup-eth-rpc

These variables are essential for configuring the connection to the Elder network and your specific rollup.

Use with Viem

If you're using Viem instead of Ethers, you can convert your Viem wallet client to an Ethers signer:

import { BrowserProvider } from 'ethers'; 
import type { Account, Chain, Client, Transport } from 'viem';

// Helper function to convert viem wallet client to ethers signer
async function clientToSigner(client: Client<Transport, Chain, Account | undefined>) {
const { account, chain, transport } = client;
const network = {
chainId: chain.id,
name: chain.name,
ensAddress: chain.contracts?.ensRegistry?.address,
};
const provider = new BrowserProvider(transport, network);
const signer = await provider.getSigner(account?.address);
return signer;
}

async function connectViem(
client: Client<Transport, Chain, Account | undefined>,
chain: Chain<undefined, { rollId?: number }>
) {
if (typeof chain.custom?.rollId === 'number')
// connect is the ethers connect function from previous examples
return await connect(await clientToSigner(client), {
chain_id: BigInt(chain.id),
eth_rpc: chain.rpcUrls.default.http[0],
roll_id: chain.custom.rollId,
});
return null;
}

This approach allows you to use your existing Viem setup while still leveraging the Elder.js functions that expect an Ethers signer.

Next Steps

Now that you understand how to interact with your rollup, you can:

  • Develop smart contracts for your rollup
  • Create dApps that leverage the rollup's capabilities
  • Integrate with existing Ethereum applications

For more advanced usage and detailed API documentation, refer to the Elder.js documentation.