Skip to content

Commit

Permalink
chroe: optimize and fix test issues of plugin-bnb (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
pythonberg1997 authored Jan 16, 2025
1 parent c856d60 commit 0413be4
Show file tree
Hide file tree
Showing 11 changed files with 281 additions and 138 deletions.
2 changes: 1 addition & 1 deletion packages/plugin-bnb/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ Request testnet tokens from the faucet. You could request any of the supported t
- **Token**(Optional)
- **Recipient Address**

The recipient address must maintain a minimum balance of 0.002 BNB on BSC Mainnet to qualify.
The faucet is rate-limited. One claim is allowed per IP address within a 24-hour period. And the recipient address must maintain a minimum balance of 0.002 BNB on BSC Mainnet to qualify.

**Example usage:**

Expand Down
85 changes: 48 additions & 37 deletions packages/plugin-bnb/src/actions/bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ import {
} from "@elizaos/core";
import { parseEther, getContract, Address, parseUnits } from "viem";

import { initWalletProvider, WalletProvider } from "../providers/wallet";
import {
bnbWalletProvider,
initWalletProvider,
WalletProvider,
} from "../providers/wallet";
import { bridgeTemplate } from "../templates";
import {
ERC20Abi,
Expand Down Expand Up @@ -97,13 +101,28 @@ export class BridgeAction {

// check ERC20 allowance
if (!nativeTokenBridge) {
await this.checkTokenAllowance(
const diff = await this.walletProvider.checkERC20Allowance(
params.fromChain,
params.fromToken!,
fromAddress,
this.L1_BRIDGE_ADDRESS,
amount
);
if (diff > 0n) {
elizaLogger.log(
`Increasing ERC20 allowance for L1 bridge. ${diff} more needed`
);
const txHash =
await this.walletProvider.increaseERC20Allowance(
params.fromChain,
params.fromToken!,
this.L1_BRIDGE_ADDRESS,
diff
);
await publicClient.waitForTransactionReceipt({
hash: txHash,
});
}
}

if (selfBridge && nativeTokenBridge) {
Expand Down Expand Up @@ -189,13 +208,28 @@ export class BridgeAction {

// check ERC20 allowance
if (!nativeTokenBridge) {
await this.checkTokenAllowance(
const diff = await this.walletProvider.checkERC20Allowance(
params.fromChain,
params.fromToken!,
fromAddress,
this.L2_BRIDGE_ADDRESS,
amount
);
if (diff > 0n) {
elizaLogger.log(
`Increasing ERC20 allowance for L2 bridge. ${diff} more needed`
);
const txHash =
await this.walletProvider.increaseERC20Allowance(
params.fromChain,
params.fromToken!,
this.L2_BRIDGE_ADDRESS,
diff
);
await publicClient.waitForTransactionReceipt({
hash: txHash,
});
}
}

if (selfBridge && nativeTokenBridge) {
Expand Down Expand Up @@ -268,6 +302,15 @@ export class BridgeAction {
throw new Error("Unsupported bridge direction");
}

if (!resp.txHash || resp.txHash == "0x") {
throw new Error("Get transaction hash failed");
}

// wait for the transaction to be confirmed
await publicClient.waitForTransactionReceipt({
hash: resp.txHash,
});

return resp;
} catch (error) {
throw error;
Expand All @@ -286,44 +329,11 @@ export class BridgeAction {
if (params.fromChain == "bsc" && params.toChain == "opBNB") {
if (params.fromToken && !params.toToken) {
throw new Error(
"token address on opBNB is required for bridge ERC20 from BSC to opBNB"
"token address on opBNB is required when bridging ERC20 from BSC to opBNB"
);
}
}
}

async checkTokenAllowance(
chain: SupportedChain,
token: Address,
owner: Address,
spender: Address,
amount: bigint
) {
const publicClient = this.walletProvider.getPublicClient(chain);
const allowance = await publicClient.readContract({
address: token,
abi: ERC20Abi,
functionName: "allowance",
args: [owner, spender],
});

if (allowance < amount) {
elizaLogger.log("Increasing allowance for ERC20 bridge");
const walletClient = this.walletProvider.getWalletClient(chain);
const { request } = await publicClient.simulateContract({
account: walletClient.account,
address: token,
abi: ERC20Abi,
functionName: "increaseAllowance",
args: [spender, amount - allowance],
});

const hash = await walletClient.writeContract(request);
await publicClient.waitForTransactionReceipt({
hash,
});
}
}
}

// NOTE: The bridge action only supports bridge funds between BSC and opBNB for now. We may adding stargate support later.
Expand All @@ -345,6 +355,7 @@ export const bridgeAction = {
} else {
state = await runtime.updateRecentMessageState(state);
}
state.walletInfo = await bnbWalletProvider.get(runtime, message, state);

// Compose bridge context
const bridgeContext = composeContext({
Expand Down
28 changes: 14 additions & 14 deletions packages/plugin-bnb/src/actions/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ import {
type State,
} from "@elizaos/core";
import solc from "solc";
import { Abi, Address, formatEther, formatUnits, parseUnits } from "viem";
import { initWalletProvider, WalletProvider } from "../providers/wallet";
import { Abi, Address, formatEther, parseUnits } from "viem";
import {
bnbWalletProvider,
initWalletProvider,
WalletProvider,
} from "../providers/wallet";
import { ercContractTemplate } from "../templates";
import {
IDeployERC1155Params,
Expand Down Expand Up @@ -174,16 +178,6 @@ export class DeployAction {

this.walletProvider.switchChain(chain);

// check wallet balance
const publicClient = this.walletProvider.getPublicClient(chain);
const balance = await publicClient.getBalance({
address: this.walletProvider.getAddress(),
});
elizaLogger.debug(`Wallet balance: ${formatEther(balance)} BNB`);
if (balance === 0n) {
elizaLogger.error("Wallet has no BNB for gas fees");
}

const chainConfig = this.walletProvider.getChainConfigs(chain);
const walletClient = this.walletProvider.getWalletClient(chain);
const hash = await walletClient.deployContract({
Expand All @@ -195,6 +189,7 @@ export class DeployAction {
});

elizaLogger.debug("Waiting for deployment transaction...", hash);
const publicClient = this.walletProvider.getPublicClient(chain);
const receipt = await publicClient.waitForTransactionReceipt({
hash,
});
Expand Down Expand Up @@ -223,6 +218,7 @@ export const deployAction = {
} else {
state = await runtime.updateRecentMessageState(state);
}
state.walletInfo = await bnbWalletProvider.get(runtime, message, state);

// Compose context
const context = composeContext({
Expand Down Expand Up @@ -302,15 +298,19 @@ export const deployAction = {
action: "DEPLOY_TOKEN",
},
},
],
[
{
user: "{{user2}}",
user: "{{user1}}",
content: {
text: "Deploy an ERC721 NFT contract with name 'MyNFT', symbol 'MNFT', baseURI 'https://my-nft-base-uri.com'",
action: "DEPLOY_TOKEN",
},
},
],
[
{
user: "{{user3}}",
user: "{{user1}}",
content: {
text: "Deploy an ERC1155 contract with name 'My1155', baseURI 'https://my-1155-base-uri.com'",
action: "DEPLOY_TOKEN",
Expand Down
7 changes: 6 additions & 1 deletion packages/plugin-bnb/src/actions/faucet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ import WebSocket, { ClientOptions } from "ws";

import { faucetTemplate } from "../templates";
import { FaucetResponse, type FaucetParams } from "../types";
import { initWalletProvider, WalletProvider } from "../providers/wallet";
import {
bnbWalletProvider,
initWalletProvider,
WalletProvider,
} from "../providers/wallet";

export { faucetTemplate };

Expand Down Expand Up @@ -135,6 +139,7 @@ export const faucetAction = {
} else {
state = await runtime.updateRecentMessageState(state);
}
state.walletInfo = await bnbWalletProvider.get(runtime, message, state);

// Compose faucet context
const faucetContext = composeContext({
Expand Down
81 changes: 58 additions & 23 deletions packages/plugin-bnb/src/actions/getBalance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,21 @@ import {
type Memory,
type State,
} from "@elizaos/core";
import {
getTokens,
getToken,
getTokenBalance,
getTokenBalances,
ChainId,
} from "@lifi/sdk";
import { getToken, getTokens, getTokenBalances, ChainId } from "@lifi/sdk";

import { initWalletProvider, WalletProvider } from "../providers/wallet";
import {
bnbWalletProvider,
initWalletProvider,
WalletProvider,
} from "../providers/wallet";
import { getBalanceTemplate } from "../templates";
import type { Balance, GetBalanceParams, GetBalanceResponse } from "../types";
import { Address, formatEther, formatUnits } from "viem";
import type {
Balance,
GetBalanceParams,
GetBalanceResponse,
SupportedChain,
} from "../types";
import { Address, erc20Abi, formatEther, formatUnits } from "viem";

export { getBalanceTemplate };

Expand Down Expand Up @@ -48,17 +51,30 @@ export class GetBalanceAction {

// If no specific token is requested, get all token balances
if (!token) {
this.walletProvider.configureLiFiSdk(chain);
const balances = await this.getTokenBalances(chainId, address!);
resp.balances = balances;
} else {
// If specific token is requested and it's not the native token
if (token !== nativeSymbol) {
const balance = await this.getERC20TokenBalance(
chainId,
address!,
token!
);
resp.balances = [{ token: token!, balance }];
if (token.toLowerCase() !== nativeSymbol.toLowerCase()) {
let balance: string;
if (token.startsWith("0x")) {
balance = await this.getERC20TokenBalance(
chain,
address!,
token as `0x${string}`
);
} else {
this.walletProvider.configureLiFiSdk(chain);
const tokenInfo = await getToken(chainId, token);
balance = await this.getERC20TokenBalance(
chain,
address!,
tokenInfo.address as `0x${string}`
);
}

resp.balances = [{ token, balance }];
} else {
// If native token is requested
const nativeBalanceWei = await this.walletProvider
Expand All @@ -80,13 +96,26 @@ export class GetBalanceAction {
}

async getERC20TokenBalance(
chainId: ChainId,
chain: SupportedChain,
address: Address,
tokenSymbol: string
tokenAddress: Address
): Promise<string> {
const token = await getToken(chainId, tokenSymbol);
const tokenBalance = await getTokenBalance(address, token);
return formatUnits(tokenBalance?.amount ?? 0n, token.decimals);
const publicClient = this.walletProvider.getPublicClient(chain);

const balance = await publicClient.readContract({
address: tokenAddress,
abi: erc20Abi,
functionName: "balanceOf",
args: [address],
});

const decimals = await publicClient.readContract({
address: tokenAddress,
abi: erc20Abi,
functionName: "decimals",
});

return formatUnits(balance, decimals);
}

async getTokenBalances(
Expand Down Expand Up @@ -115,7 +144,12 @@ export class GetBalanceAction {
}

if (params.chain != "bsc") {
throw new Error("Only BSC mainnet is supported");
// if token contract address is not provided, only BSC mainnet is supported
if (!(params.token && params.token.startsWith("0x"))) {
throw new Error(
"If token contract address is not provided, only BSC mainnet is supported"
);
}
}
}
}
Expand All @@ -138,6 +172,7 @@ export const getBalanceAction = {
} else {
state = await runtime.updateRecentMessageState(state);
}
state.walletInfo = await bnbWalletProvider.get(runtime, message, state);

// Compose swap context
const getBalanceContext = composeContext({
Expand Down
Loading

0 comments on commit 0413be4

Please sign in to comment.