@across-protocol/app-sdk v0.0.3
Getting Started
The @across-protocol/app-sdk
provides useful abstractions on top of Across' Smart Contracts and Quotes API.
To learn more visit our docs.
Installation
To get started, install the app sdk and its peer dependency viem.
pnpm i @across-protocol/app-sdk viem
Quick Start
1. Set up the AcrossClient
Firstly, you need to set up the AcrossClient
and configure the chains you want to support.
import { createAcrossClient } from "@across-protocol/app-sdk";
import { mainnet, optimism, arbitrum } from "viem/chains";
const client = createAcrossClient({
integratorId: "0xdead", // 2-byte hex string
chains: [mainnet, optimism, arbitrum],
});
2. Retrieve a quote
Now, you can retrieve a quote for a given route.
// USDC from Optimism -> Arbitrum
const route = {
originChainId: optimism.chainId
destinationChainId: arbitrum.chainId,
inputToken: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
outputToken: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
};
const quote = await client.getQuote({
route,
inputAmount: parseUnit("1000", 6) // USDC decimals
})
Note that we provide additional utilities for retrieving available routes, chain details, and token infos. See here.
3. Execute a quote
After retrieving a quote, you are ready to execute it.
import { useWalletClient } from "wagmi";
const wallet = useWalletClient();
await client.executeQuote({
walletClient: wallet,
deposit: quote.deposit, // returned by `getQuote`
onProgress: (progress) => {
// handle progress
},
});
The method will execute a quote by:
- Approving the SpokePool contract if necessary
- Depositing the input token on the origin chain
- Waiting for the deposit to be filled on the destination chain
You can use the onProgress
callback to act on different stages of the execution.
Have a look at our example app for a more detailed usage of this method.
Cross-chain message handling
Across enables users to seamlessly interact with your dApp or chain using assets from other chains.
1. Craft a cross-chain message
To implement this feature, you first need to specify a crossChainMessage
.
The example below shows a cross-chain message for staking USDC into a contract deployed
on Optimism by:
- Approve USDC to be pulled into staking
- Stake approved amount into contract
// Example staking contract on Optimism
const stakingContractAddress = "0x733Debf51574c70CfCdb7918F032E16F686bd9f8";
// USDC on Optimism
const usdcAddress = "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85";
// Example user address
const userAddress = "0x924a9f036260DdD5808007E1AA95f08eD08aA569a";
const inputAmount = parseUnits("200", 6);
const crossChainMessage = {
// This address will receive the amount of bridged tokens on the destination chain if
// one of the cross-chain actions fail. Leftover tokens are here as well if all actions
// succeed.
fallbackRecipient: userAddress,
// List of actions that should be executed on the destination chain
actions: [
{
// Address of target contract on destination chain, i.e. USDC on Optimism
target: usdcAddress,
// Encoded function data, i.e. calldata for approving USDC to be pulled in by
// staking contract
callData: generateApproveCallData(
stakingContractAddress,
inputAmount
),
// Native msg.value, can be 0 in the context of USDC
value: 0n,
// Update call data callback - we need to provide a callback function to
// re-generate calldata because it depends on the `outputAmount`, i.e.
// `inputAmount` - `relayer fee`. This is the amount the user has available after a
// relayer filled the deposit on the destination chain.
updateCallData: (outputAmount) => generateApproveCallData(
stakingContractAddress,
outputAmount
)
},
{
// Address of target contract on destination chain, i.e. staking contract
// on Optimism
target: stakingContractAddress,
// Encoded function data, i.e. calldata for staking USDC on behalf of user
callData: generateStakeCallData(
userAddress,
inputAmount
)
// Native msg.value, can be 0 in the context of USDC
value: 0n,
// Same reasoning as above in the approve step.
updateCallData: (outputAmount) => generateStakeCallData(
stakingContractAddress,
outputAmount
)
}
]
}
function generateApproveCallData(spender: Address, amount: uint256) {
const approveCallData = encodeFunctionData({
abi: [parseAbiItem("function approve(address spender, uint256 value)")],
args: [spender, amount],
});
return approveCallData;
}
function generateStakeCallData(userAddress: Address, amount: uint256) {
return encodeFunctionData({
abi: [parseAbiItem("function stake(address stakerAddress, uint256 amount")],
args: [userAddress, amount],
});
}
2. Retrieve a quote
After specifying a cross-chain message, you simply can fetch a quote the same way as a normal bridge
const route = {
originChainId: arbitrum.chainId
destinationChainId: optimism.chainId,
inputToken: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
outputToken: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
};
const quote = await client.getQuote({
route,
inputAmount,
crossChainMessage // crated above
});
3. Execute a quote
If the quote is available, you can execute like so
import { useWalletClient } from "wagmi";
const wallet = useWalletClient();
await client.executeQuote({
walletClient: wallet,
deposit: quote.deposit, // returned by `getQuote`
onProgress: (progress) => {
// handle progress
},
});
Deposit details
TODO
Error handling and debugging
TODO
Route, chain and token details
TODO
@across-protocol/app-sdk
Reference
For the full detailed reference see here.