Skip to content

Commit

Permalink
Merge branch 'fix/charity' of http://github.com/ai16z/eliza into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
lalalune committed Dec 14, 2024
2 parents 1cfe4ce + 7ce827c commit aa2cf4b
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 31 deletions.
8 changes: 8 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,14 @@ COINBASE_GENERATED_WALLET_ID= # Not your address but the wallet ID from genera
COINBASE_GENERATED_WALLET_HEX_SEED= # Not your address but the wallet hex seed from generating a wallet through the plugin and calling export
COINBASE_NOTIFICATION_URI= # For webhook plugin the uri you want to send the webhook to for dummy ones use https://webhook.site

# Coinbase Charity Configuration
IS_CHARITABLE=false # Set to true to enable charity donations
CHARITY_ADDRESS_BASE=0x1234567890123456789012345678901234567890
CHARITY_ADDRESS_SOL=pWvDXKu6CpbKKvKQkZvDA66hgsTB6X2AgFxksYogHLV
CHARITY_ADDRESS_ETH=0x750EF1D7a0b4Ab1c97B7A623D7917CcEb5ea779C
CHARITY_ADDRESS_ARB=0x1234567890123456789012345678901234567890
CHARITY_ADDRESS_POL=0x1234567890123456789012345678901234567890

# Conflux Configuration
CONFLUX_CORE_PRIVATE_KEY=
CONFLUX_CORE_SPACE_RPC_URL=
Expand Down
23 changes: 23 additions & 0 deletions packages/client-whatsapp/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "@ai16z/client-whatsapp",
"version": "0.0.1",
"description": "WhatsApp client for Eliza",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"clean": "rimraf dist",
"test": "jest",
"lint": "eslint src --ext .ts"
},
"dependencies": {
"@ai16z/eliza": "workspace:*"
},
"devDependencies": {
"@types/node": "^20.0.0",
"typescript": "^5.0.0",
"rimraf": "^5.0.0",
"jest": "^29.0.0",
"@types/jest": "^29.0.0"
}
}
Empty file.
21 changes: 21 additions & 0 deletions packages/client-whatsapp/src/environment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { IAgentRuntime } from "@ai16z/eliza";

export async function validateWhatsAppConfig(
runtime: IAgentRuntime
): Promise<void> {
const requiredSettings = [
"WHATSAPP_API_TOKEN",
"WHATSAPP_PHONE_NUMBER_ID",
"WHATSAPP_APP_ID",
"WHATSAPP_APP_SECRET",
"WHATSAPP_WEBHOOK_VERIFY_TOKEN"
];

for (const setting of requiredSettings) {
if (!runtime.getSetting(setting)) {
throw new Error(
`Missing required WhatsApp configuration: ${setting}`
);
}
}
}
28 changes: 28 additions & 0 deletions packages/client-whatsapp/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { elizaLogger } from "@ai16z/eliza";
import { Client, IAgentRuntime } from "@ai16z/eliza";
import { WhatsAppClient } from "./whatsappClient";
import { validateWhatsAppConfig } from "../../../eliza/packages/client-whatsapp/src/environment";

export const WhatsAppClientInterface: Client = {
start: async (runtime: IAgentRuntime) => {
await validateWhatsAppConfig(runtime);

const client = new WhatsAppClient(
runtime,
runtime.getSetting("WHATSAPP_API_TOKEN"),
runtime.getSetting("WHATSAPP_PHONE_NUMBER_ID")
);

await client.start();

elizaLogger.success(
`✅ WhatsApp client successfully started for character ${runtime.character.name}`
);
return client;
},
stop: async (runtime: IAgentRuntime) => {
elizaLogger.warn("WhatsApp client stopping...");
},
};

export default WhatsAppClientInterface;
113 changes: 82 additions & 31 deletions packages/plugin-coinbase/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { Coinbase, Trade, Transfer, Wallet, WalletData, Webhook } from "@coinbase/coinbase-sdk";
import { elizaLogger, IAgentRuntime } from "@ai16z/eliza";
import {
Coinbase,
Trade,
Transfer,
Wallet,
WalletData,
Webhook,
} from "@coinbase/coinbase-sdk";
import { elizaLogger, IAgentRuntime, settings } from "@ai16z/eliza";
import fs from "fs";
import path from "path";
import { EthereumTransaction } from "@coinbase/coinbase-sdk/dist/client";
Expand Down Expand Up @@ -56,7 +63,10 @@ export async function initializeWallet(
// save it to gitignored file
wallet.saveSeed(seedFilePath);
}
elizaLogger.log("Wallet created and stored new wallet:", walletAddress);
elizaLogger.log(
"Wallet created and stored new wallet:",
walletAddress
);
} catch (error) {
elizaLogger.error("Error updating character secrets:", error);
throw error;
Expand Down Expand Up @@ -92,7 +102,13 @@ export async function initializeWallet(
* @param {string} sourceAsset - The source asset to trade.
* @param {string} targetAsset - The target asset to trade.
*/
export async function executeTradeAndCharityTransfer(runtime: IAgentRuntime, network: string, amount: number, sourceAsset: string, targetAsset: string) {
export async function executeTradeAndCharityTransfer(
runtime: IAgentRuntime,
network: string,
amount: number,
sourceAsset: string,
targetAsset: string
) {
const wallet = await initializeWallet(runtime, network);

elizaLogger.log("Wallet initialized:", {
Expand All @@ -112,18 +128,25 @@ export async function executeTradeAndCharityTransfer(runtime: IAgentRuntime, net

let transfer: Transfer;
if (charityAddress && charityAmount > 0) {
transfer = await executeTransfer(wallet, charityAmount, assetIdLowercase, charityAddress);
transfer = await executeTransfer(
wallet,
charityAmount,
assetIdLowercase,
charityAddress
);
elizaLogger.log("Charity Transfer successful:", {
address: charityAddress,
transactionUrl: transfer.getTransactionLink(),
});
await appendTransactionsToCsv([{
address: charityAddress,
amount: charityAmount,
status: "Success",
errorCode: null,
transactionUrl: transfer.getTransactionLink(),
}]);
await appendTransactionsToCsv([
{
address: charityAddress,
amount: charityAmount,
status: "Success",
errorCode: null,
transactionUrl: transfer.getTransactionLink(),
},
]);
}

const trade: Trade = await wallet.createTrade(tradeParams);
Expand Down Expand Up @@ -219,7 +242,7 @@ export async function appendWebhooksToCsv(webhooks: Webhook[]) {
});
await csvWriter.writeRecords([]); // Create an empty file with headers
elizaLogger.log("New CSV file created with headers.");
}
}
const csvWriter = createArrayCsvWriter({
path: webhookCsvFilePath,
header: [
Expand Down Expand Up @@ -387,16 +410,30 @@ export async function getWalletDetails(
* @param {string} sourceAsset - The source asset to transfer.
* @param {string} targetAddress - The target address to transfer to.
*/
export async function executeTransferAndCharityTransfer(wallet: Wallet, amount: number, sourceAsset: string, targetAddress: string, network: string) {
export async function executeTransferAndCharityTransfer(
wallet: Wallet,
amount: number,
sourceAsset: string,
targetAddress: string,
network: string
) {
const charityAddress = getCharityAddress(network);
const charityAmount = charityAddress ? amount * 0.01 : 0;
const transferAmount = charityAddress ? amount - charityAmount : amount;
const assetIdLowercase = sourceAsset.toLowerCase();

let charityTransfer: Transfer;
if (charityAddress && charityAmount > 0) {
charityTransfer = await executeTransfer(wallet, charityAmount, assetIdLowercase, charityAddress);
elizaLogger.log("Charity Transfer successful:", charityTransfer.toString());
charityTransfer = await executeTransfer(
wallet,
charityAmount,
assetIdLowercase,
charityAddress
);
elizaLogger.log(
"Charity Transfer successful:",
charityTransfer.toString()
);
}

const transferDetails = {
Expand Down Expand Up @@ -430,7 +467,7 @@ export async function executeTransferAndCharityTransfer(wallet: Wallet, amount:
transfer,
charityTransfer,
responseText,
}
};
}

/**
Expand All @@ -440,7 +477,12 @@ export async function executeTransferAndCharityTransfer(wallet: Wallet, amount:
* @param {string} sourceAsset - The source asset to transfer.
* @param {string} targetAddress - The target address to transfer to.
*/
export async function executeTransfer(wallet: Wallet, amount: number, sourceAsset: string, targetAddress: string) {
export async function executeTransfer(
wallet: Wallet,
amount: number,
sourceAsset: string,
targetAddress: string
) {
const assetIdLowercase = sourceAsset.toLowerCase();
const transferDetails = {
amount,
Expand All @@ -454,8 +496,8 @@ export async function executeTransfer(wallet: Wallet, amount: number, sourceAsse
transfer = await wallet.createTransfer(transferDetails);
elizaLogger.log("Transfer initiated:", transfer.toString());
await transfer.wait({
intervalSeconds: 1,
timeoutSeconds: 20,
intervalSeconds: 1,
timeoutSeconds: 20,
});
} catch (error) {
elizaLogger.error("Error executing transfer:", error);
Expand All @@ -465,20 +507,29 @@ export async function executeTransfer(wallet: Wallet, amount: number, sourceAsse

/**
* Gets the charity address based on the network.
* For now we are giving to the following charity, but will make this configurable in the future
* https://www.givedirectly.org/crypto/?_gl=1*va5e6k*_gcl_au*MTM1NDUzNTk5Mi4xNzMzMDczNjA3*_ga*OTIwMDMwNTMwLjE3MzMwNzM2MDg.*_ga_GV8XF9FJ16*MTczMzA3MzYwNy4xLjEuMTczMzA3MzYyMi40NS4wLjA.
* @param {string} network - The network to use.
* @param {boolean} isCharitable - Whether charity donations are enabled
* @throws {Error} If charity address for the network is not configured when charity is enabled
*/
export function getCharityAddress(network: string): string | null {
let charityAddress = null;
if (network === "base") {
charityAddress = "0x750EF1D7a0b4Ab1c97B7A623D7917CcEb5ea779C";
} else if (network === "sol") {
charityAddress = "pWvDXKu6CpbKKvKQkZvDA66hgsTB6X2AgFxksYogHLV";
} else if (network === "eth") {
charityAddress = "0x750EF1D7a0b4Ab1c97B7A623D7917CcEb5ea779C";
} else {
export function getCharityAddress(
network: string,
isCharitable: boolean = false
): string | null {
// Check both environment variable and passed parameter
const isCharityEnabled =
process.env.IS_CHARITABLE === "true" && isCharitable;

if (!isCharityEnabled) {
return null;
}
const networkKey = `CHARITY_ADDRESS_${network.toUpperCase()}`;
const charityAddress = settings[networkKey];

if (!charityAddress) {
throw new Error(
`Charity address not configured for network ${network}. Please set ${networkKey} in your environment variables.`
);
}

return charityAddress;
}
22 changes: 22 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit aa2cf4b

Please sign in to comment.