From b46fd6496846867ce45530ad8ff574abe488113b Mon Sep 17 00:00:00 2001 From: fabri Date: Tue, 11 Mar 2025 15:03:02 -0300 Subject: [PATCH 1/7] update node --- README.md | 1 + examples/gated-group/index.ts | 10 ++++---- examples/gm/index.ts | 4 ++-- examples/gpt/index.ts | 4 ++-- integrations/grok/index.ts | 4 ++-- integrations/grok/package.json | 2 +- package.json | 2 +- yarn.lock | 44 ++-------------------------------- 8 files changed, 16 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 314b6af..2cd95b8 100644 --- a/README.md +++ b/README.md @@ -97,5 +97,6 @@ Interact with the XMTP network using [xmtp.chat](https://xmtp.chat), the officia Examples integrating XMTP with external libraries from the ecosystem - [grok](/integrations/grok/): Integrate XMTP to the Grok API +- [gaia](/integrations/gaia/): Integrate XMTP to the Gaia API > See all the available [integrations](/integrations/). diff --git a/examples/gated-group/index.ts b/examples/gated-group/index.ts index 47f06eb..eeab0f8 100644 --- a/examples/gated-group/index.ts +++ b/examples/gated-group/index.ts @@ -1,4 +1,4 @@ -import { Client, type XmtpEnv } from "@xmtp/node-sdk"; +import { Client, type Group, type XmtpEnv } from "@xmtp/node-sdk"; import { Alchemy, Network } from "alchemy-sdk"; import { createSigner, getEncryptionKeyFromHex } from "@/helpers"; @@ -56,8 +56,8 @@ async function main() { `Received message: ${message.content as string} by ${message.senderInboxId}`, ); - const conversation = client.conversations.getConversationById( - message.conversationId, + const conversation = client.conversations.getDmByInboxId( + message.senderInboxId, ); if (!conversation) { @@ -98,7 +98,7 @@ async function main() { await conversation.send("Please provide a group id"); return; } - const group = client.conversations.getConversationById(groupId); + const group = await client.conversations.getConversationById(groupId); if (!group) { await conversation.send("Please provide a valid group id"); return; @@ -113,7 +113,7 @@ async function main() { console.log("User can't be added to the group"); return; } else { - await group.addMembers([walletAddress]); + await (group as Group).addMembers([walletAddress]); await conversation.send( `User added to the group\n- Group ID: ${groupId}\n- Wallet Address: ${walletAddress}`, ); diff --git a/examples/gm/index.ts b/examples/gm/index.ts index e5e85fa..9761595 100644 --- a/examples/gm/index.ts +++ b/examples/gm/index.ts @@ -52,8 +52,8 @@ async function main() { ); /* Get the conversation by id */ - const conversation = client.conversations.getConversationById( - message.conversationId, + const conversation = client.conversations.getDmByInboxId( + message.senderInboxId, ); if (!conversation) { diff --git a/examples/gpt/index.ts b/examples/gpt/index.ts index 44c400e..2942d1e 100644 --- a/examples/gpt/index.ts +++ b/examples/gpt/index.ts @@ -68,8 +68,8 @@ async function main() { ); /* Get the conversation from the local db */ - const conversation = client.conversations.getConversationById( - message.conversationId, + const conversation = client.conversations.getDmByInboxId( + message.senderInboxId, ); /* If the conversation is not found, skip the message */ diff --git a/integrations/grok/index.ts b/integrations/grok/index.ts index cbac903..8d27f6a 100644 --- a/integrations/grok/index.ts +++ b/integrations/grok/index.ts @@ -63,8 +63,8 @@ async function main() { ); /* Get the conversation from the local db */ - const conversation = client.conversations.getConversationById( - message.conversationId, + const conversation = client.conversations.getDmByInboxId( + message.senderInboxId, ); /* If the conversation is not found, skip the message */ diff --git a/integrations/grok/package.json b/integrations/grok/package.json index f1de7e0..ce50dbb 100644 --- a/integrations/grok/package.json +++ b/integrations/grok/package.json @@ -8,7 +8,7 @@ "gen:keys": "tsx ../../scripts/generateKeys.ts" }, "dependencies": { - "@xmtp/node-sdk": "0.0.42", + "@xmtp/node-sdk": "0.0.47", "tsx": "^4.19.2", "uint8arrays": "^5.1.0", "viem": "^2.22.17" diff --git a/package.json b/package.json index 95d9ef0..43381ad 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "typecheck": "tsc" }, "dependencies": { - "@xmtp/node-sdk": "0.0.45", + "@xmtp/node-sdk": "0.0.47", "alchemy-sdk": "^3.0.0", "openai": "latest", "tsx": "^4.19.2", diff --git a/yarn.lock b/yarn.lock index 19e3357..2084470 100644 --- a/yarn.lock +++ b/yarn.lock @@ -823,7 +823,7 @@ __metadata: version: 0.0.0-use.local resolution: "@integrations/gpt@workspace:integrations/grok" dependencies: - "@xmtp/node-sdk": "npm:0.0.42" + "@xmtp/node-sdk": "npm:0.0.47" tsx: "npm:^4.19.2" uint8arrays: "npm:^5.1.0" viem: "npm:^2.22.17" @@ -1285,20 +1285,6 @@ __metadata: languageName: node linkType: hard -"@xmtp/node-bindings@npm:^0.0.37": - version: 0.0.37 - resolution: "@xmtp/node-bindings@npm:0.0.37" - checksum: 10/06d12ee27f306a2ad767b75eedf3ceb0457cab3f574a545f44e487cbb39d07a3866c81277954a4937dc1f048a75c10b34b5ffa5de4fc43eaf9b1310a1c4dce8a - languageName: node - linkType: hard - -"@xmtp/node-bindings@npm:^0.0.38": - version: 0.0.38 - resolution: "@xmtp/node-bindings@npm:0.0.38" - checksum: 10/a9452a913cdda5cd050b91ed34358b8975524d1c5e6434db51b1d60f13a29069b531ee566811ab4ed339713ad0e041e83f24fc916684c968c322ba63f21319f3 - languageName: node - linkType: hard - "@xmtp/node-bindings@npm:^0.0.41": version: 0.0.41 resolution: "@xmtp/node-bindings@npm:0.0.41" @@ -1306,32 +1292,6 @@ __metadata: languageName: node linkType: hard -"@xmtp/node-sdk@npm:0.0.42": - version: 0.0.42 - resolution: "@xmtp/node-sdk@npm:0.0.42" - dependencies: - "@xmtp/content-type-group-updated": "npm:^2.0.0" - "@xmtp/content-type-primitives": "npm:^2.0.0" - "@xmtp/content-type-text": "npm:^2.0.0" - "@xmtp/node-bindings": "npm:^0.0.37" - "@xmtp/proto": "npm:^3.72.3" - checksum: 10/6163ede6d9cd7bc36b3a237d9a63a8be0041a11a1eefc6f56fefbf7cb8b8cc02c817c4696996a29a4f296d7545fd3172d8ebf8f85e1aeb23dcff917719dfcd10 - languageName: node - linkType: hard - -"@xmtp/node-sdk@npm:0.0.45": - version: 0.0.45 - resolution: "@xmtp/node-sdk@npm:0.0.45" - dependencies: - "@xmtp/content-type-group-updated": "npm:^2.0.0" - "@xmtp/content-type-primitives": "npm:^2.0.0" - "@xmtp/content-type-text": "npm:^2.0.0" - "@xmtp/node-bindings": "npm:^0.0.38" - "@xmtp/proto": "npm:^3.72.3" - checksum: 10/70eb659105a585e651f9c9a538b98014476212a1023308b88012317a5c64e58b4a2d920891c131e763d449823cb8d1e126a4041ff73a803b5593702f43c08e8c - languageName: node - linkType: hard - "@xmtp/node-sdk@npm:0.0.47": version: 0.0.47 resolution: "@xmtp/node-sdk@npm:0.0.47" @@ -3882,7 +3842,7 @@ __metadata: "@ianvs/prettier-plugin-sort-imports": "npm:^4.4.1" "@types/eslint__js": "npm:^8.42.3" "@types/node": "npm:^22.13.0" - "@xmtp/node-sdk": "npm:0.0.45" + "@xmtp/node-sdk": "npm:0.0.47" alchemy-sdk: "npm:^3.0.0" eslint: "npm:^9.19.0" eslint-config-prettier: "npm:^10.0.1" From 3078648ce90c3e5732d81907dc6a6968ba9398a4 Mon Sep 17 00:00:00 2001 From: fabri Date: Wed, 12 Mar 2025 13:19:27 -0300 Subject: [PATCH 2/7] update to rc --- examples/gated-group/README.md | 2 +- examples/gated-group/index.ts | 6 ++++-- examples/gm/README.md | 4 +++- examples/gm/index.ts | 4 +++- examples/gpt/README.md | 2 +- examples/gpt/index.ts | 4 +++- helpers/index.ts | 21 +++++++++++++-------- integrations/gaia/README.md | 18 +++++++++++++----- integrations/gaia/index.ts | 4 +++- integrations/gaia/package.json | 2 +- integrations/grok/README.md | 5 ++++- integrations/grok/index.ts | 5 ++++- integrations/grok/package.json | 2 +- package.json | 2 +- tsconfig.json | 2 +- yarn.lock | 24 ++++++++++++------------ 16 files changed, 68 insertions(+), 39 deletions(-) diff --git a/examples/gated-group/README.md b/examples/gated-group/README.md index a2e4633..3932b17 100644 --- a/examples/gated-group/README.md +++ b/examples/gated-group/README.md @@ -33,7 +33,7 @@ Start your XMTP client and begin listening to messages. The bot responds to the if (message.content === "/create") { console.log("Creating group"); const group = await client.conversations.newGroup([]); - await group.addMembersByInboxId([message.senderInboxId]); + await group.addMembers([message.senderInboxId]); await group.addSuperAdmin(message.senderInboxId); await conversation.send( diff --git a/examples/gated-group/index.ts b/examples/gated-group/index.ts index eeab0f8..c1ac9b1 100644 --- a/examples/gated-group/index.ts +++ b/examples/gated-group/index.ts @@ -36,8 +36,10 @@ async function main() { console.log("Syncing conversations..."); await client.conversations.sync(); + const identifier = await signer.getIdentifier(); + const address = identifier.identifier; console.log( - `Agent initialized on ${client.accountAddress}\nSend a message on http://xmtp.chat/dm/${client.accountAddress}`, + `Agent initialized on ${address}\nSend a message on http://xmtp.chat/dm/${address}`, ); console.log("Waiting for messages..."); @@ -74,7 +76,7 @@ async function main() { const group = await client.conversations.newGroup([]); console.log("Group created", group.id); // First add the sender to the group - await group.addMembersByInboxId([message.senderInboxId]); + await group.addMembers([message.senderInboxId]); // Then make the sender a super admin await group.addSuperAdmin(message.senderInboxId); console.log( diff --git a/examples/gm/README.md b/examples/gm/README.md index d447a4b..dfba002 100644 --- a/examples/gm/README.md +++ b/examples/gm/README.md @@ -36,8 +36,10 @@ async function main() { /* Sync the conversations from the network to update the local db */ await client.conversations.sync(); + const identifier = await signer.getIdentifier(); + const address = identifier.identifier; console.log( - `Agent initialized on ${client.accountAddress}\nSend a message on http://xmtp.chat/dm/${client.accountAddress}?env=${env}`, + `Agent initialized on ${address}\nSend a message on http://xmtp.chat/dm/${address}`, ); console.log("Waiting for messages..."); diff --git a/examples/gm/index.ts b/examples/gm/index.ts index 9761595..c11e361 100644 --- a/examples/gm/index.ts +++ b/examples/gm/index.ts @@ -30,8 +30,10 @@ async function main() { /* Sync the conversations from the network to update the local db */ await client.conversations.sync(); + const identifier = await signer.getIdentifier(); + const address = identifier.identifier; console.log( - `Agent initialized on ${client.accountAddress}\nSend a message on http://xmtp.chat/dm/${client.accountAddress}?env=${env}`, + `Agent initialized on ${address}\nSend a message on http://xmtp.chat/dm/${address}`, ); console.log("Waiting for messages..."); diff --git a/examples/gpt/README.md b/examples/gpt/README.md index 81c2b1d..0fb92e4 100644 --- a/examples/gpt/README.md +++ b/examples/gpt/README.md @@ -60,7 +60,7 @@ async function main() { await client.conversations.sync(); console.log( - `Agent initialized on ${client.accountAddress}\nSend a message on http://xmtp.chat/dm/${client.accountAddress}`, + `Agent initialized on ${address}\nSend a message on http://xmtp.chat/dm/${address}`, ); console.log("Waiting for messages..."); diff --git a/examples/gpt/index.ts b/examples/gpt/index.ts index 2942d1e..4fd0a71 100644 --- a/examples/gpt/index.ts +++ b/examples/gpt/index.ts @@ -46,8 +46,10 @@ async function main() { /* Sync the conversations from the network to update the local db */ await client.conversations.sync(); + const identifier = await signer.getIdentifier(); + const address = identifier.identifier; console.log( - `Agent initialized on ${client.accountAddress}\nSend a message on http://xmtp.chat/dm/${client.accountAddress}?env=${env}`, + `Agent initialized on ${address}\nSend a message on http://xmtp.chat/dm/${address}`, ); console.log("Waiting for messages..."); diff --git a/helpers/index.ts b/helpers/index.ts index 6680c42..5a2efc3 100644 --- a/helpers/index.ts +++ b/helpers/index.ts @@ -1,20 +1,22 @@ import { getRandomValues } from "node:crypto"; -import type { Signer } from "@xmtp/node-sdk"; +import { IdentifierKind } from "@xmtp/node-bindings"; +import { type Signer } from "@xmtp/node-sdk"; import { fromString, toString } from "uint8arrays"; import { createWalletClient, http, toBytes } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { sepolia } from "viem/chains"; interface User { - key: string; + key: `0x${string}`; account: ReturnType; wallet: ReturnType; } -export const createUser = (key: string): User => { - const account = privateKeyToAccount(key as `0x${string}`); +export const createUser = (key: `0x${string}`): User => { + const accountKey = key; + const account = privateKeyToAccount(accountKey); return { - key, + key: accountKey, account, wallet: createWalletClient({ account, @@ -24,11 +26,14 @@ export const createUser = (key: string): User => { }; }; -export const createSigner = (key: string): Signer => { +export const createSigner = (key: `0x${string}`): Signer => { const user = createUser(key); return { - walletType: "EOA", - getAddress: () => user.account.address, + type: "EOA", + getIdentifier: () => ({ + identifierKind: IdentifierKind.Ethereum, + identifier: user.account.address.toLowerCase(), + }), signMessage: async (message: string) => { const signature = await user.wallet.signMessage({ message, diff --git a/integrations/gaia/README.md b/integrations/gaia/README.md index b3bdbca..e517590 100644 --- a/integrations/gaia/README.md +++ b/integrations/gaia/README.md @@ -32,7 +32,13 @@ import { Client, type XmtpEnv } from "@xmtp/node-sdk"; import OpenAI from "openai"; import { createSigner, getEncryptionKeyFromHex } from "@/helpers"; -const { WALLET_KEY, ENCRYPTION_KEY, GAIA_NODE_URL, GAIA_API_KEY, GAIA_MODEL_NAME } = process.env; +const { + WALLET_KEY, + ENCRYPTION_KEY, + GAIA_NODE_URL, + GAIA_API_KEY, + GAIA_MODEL_NAME, +} = process.env; if (!WALLET_KEY) { throw new Error("WALLET_KEY must be set"); @@ -59,9 +65,9 @@ if (!GAIA_MODEL_NAME) { const signer = createSigner(WALLET_KEY); const encryptionKey = getEncryptionKeyFromHex(ENCRYPTION_KEY); -const openai = new OpenAI({ - baseURL: GAIA_NODE_URL, - apiKey: GAIA_API_KEY +const openai = new OpenAI({ + baseURL: GAIA_NODE_URL, + apiKey: GAIA_API_KEY, }); /* Set the environment to dev or production */ @@ -77,8 +83,10 @@ async function main() { /* Sync the conversations from the network to update the local db */ await client.conversations.sync(); + const identifier = await signer.getIdentifier(); + const address = identifier.identifier; console.log( - `Agent initialized on ${client.accountAddress}\nSend a message on http://xmtp.chat/dm/${client.accountAddress}`, + `Agent initialized on ${address}\nSend a message on http://xmtp.chat/dm/${address}`, ); console.log("Waiting for messages..."); diff --git a/integrations/gaia/index.ts b/integrations/gaia/index.ts index d4d96f0..ef7cd1a 100644 --- a/integrations/gaia/index.ts +++ b/integrations/gaia/index.ts @@ -65,8 +65,10 @@ async function main() { /* Sync the conversations from the network to update the local db */ await client.conversations.sync(); + const identifier = await signer.getIdentifier(); + const address = identifier.identifier; console.log( - `Agent initialized on ${client.accountAddress}\nSend a message on http://xmtp.chat/dm/${client.accountAddress}`, + `Agent initialized on ${address}\nSend a message on http://xmtp.chat/dm/${address}`, ); console.log("Waiting for messages..."); diff --git a/integrations/gaia/package.json b/integrations/gaia/package.json index db0dc9e..9a824eb 100644 --- a/integrations/gaia/package.json +++ b/integrations/gaia/package.json @@ -8,7 +8,7 @@ "gen:keys": "tsx ../../scripts/generateKeys.ts" }, "dependencies": { - "@xmtp/node-sdk": "0.0.47", + "@xmtp/node-sdk": "1.0.0-rc1", "tsx": "^4.19.2", "uint8arrays": "^5.1.0", "viem": "^2.22.17" diff --git a/integrations/grok/README.md b/integrations/grok/README.md index 87c8797..2ceb6fe 100644 --- a/integrations/grok/README.md +++ b/integrations/grok/README.md @@ -68,9 +68,12 @@ async function main() { /* Sync the conversations from the network to update the local db */ await client.conversations.sync(); + const identifier = await signer.getIdentifier(); + const address = identifier.identifier; console.log( - `Agent initialized on ${client.accountAddress}\nSend a message on http://xmtp.chat/dm/${client.accountAddress}?env=${env}`, + `Agent initialized on ${address}\nSend a message on http://xmtp.chat/dm/${address}`, ); + console.log("Waiting for messages..."); /* Stream all messages from the network */ const stream = client.conversations.streamAllMessages(); diff --git a/integrations/grok/index.ts b/integrations/grok/index.ts index 8d27f6a..4484fc2 100644 --- a/integrations/grok/index.ts +++ b/integrations/grok/index.ts @@ -42,9 +42,12 @@ async function main() { /* Sync the conversations from the network to update the local db */ await client.conversations.sync(); + const identifier = await signer.getIdentifier(); + const address = identifier.identifier; console.log( - `Agent initialized on ${client.accountAddress}\nSend a message on http://xmtp.chat/dm/${client.accountAddress}?env=${env}`, + `Agent initialized on ${address}\nSend a message on http://xmtp.chat/dm/${address}`, ); + console.log("Waiting for messages..."); /* Stream all messages from the network */ const stream = client.conversations.streamAllMessages(); diff --git a/integrations/grok/package.json b/integrations/grok/package.json index ce50dbb..40601c4 100644 --- a/integrations/grok/package.json +++ b/integrations/grok/package.json @@ -8,7 +8,7 @@ "gen:keys": "tsx ../../scripts/generateKeys.ts" }, "dependencies": { - "@xmtp/node-sdk": "0.0.47", + "@xmtp/node-sdk": "1.0.0-rc1", "tsx": "^4.19.2", "uint8arrays": "^5.1.0", "viem": "^2.22.17" diff --git a/package.json b/package.json index 43381ad..af6960d 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "typecheck": "tsc" }, "dependencies": { - "@xmtp/node-sdk": "0.0.47", + "@xmtp/node-sdk": "1.0.0-rc1", "alchemy-sdk": "^3.0.0", "openai": "latest", "tsx": "^4.19.2", diff --git a/tsconfig.json b/tsconfig.json index c46e6b9..869d58b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,7 +6,7 @@ "declaration": true, "declarationMap": true, "forceConsistentCasingInFileNames": true, - "isolatedModules": true, + "isolatedModules": false, "lib": ["ESNext"], "module": "ESNext", "moduleResolution": "Bundler", diff --git a/yarn.lock b/yarn.lock index 2084470..02d7d98 100644 --- a/yarn.lock +++ b/yarn.lock @@ -812,7 +812,7 @@ __metadata: version: 0.0.0-use.local resolution: "@integrations/gaia@workspace:integrations/gaia" dependencies: - "@xmtp/node-sdk": "npm:0.0.47" + "@xmtp/node-sdk": "npm:1.0.0-rc1" tsx: "npm:^4.19.2" uint8arrays: "npm:^5.1.0" viem: "npm:^2.22.17" @@ -823,7 +823,7 @@ __metadata: version: 0.0.0-use.local resolution: "@integrations/gpt@workspace:integrations/grok" dependencies: - "@xmtp/node-sdk": "npm:0.0.47" + "@xmtp/node-sdk": "npm:1.0.0-rc1" tsx: "npm:^4.19.2" uint8arrays: "npm:^5.1.0" viem: "npm:^2.22.17" @@ -1285,23 +1285,23 @@ __metadata: languageName: node linkType: hard -"@xmtp/node-bindings@npm:^0.0.41": - version: 0.0.41 - resolution: "@xmtp/node-bindings@npm:0.0.41" - checksum: 10/809347d36de2b4f205fe46cc3869b1eab7595107fd14b0535457732745d14851121d1e7b0f22a0845deb32e48dfca29a7ad36a12bf9fc5c46b445a308a589c10 +"@xmtp/node-bindings@npm:^1.0.0-rc2": + version: 1.0.0-rc2 + resolution: "@xmtp/node-bindings@npm:1.0.0-rc2" + checksum: 10/2cd22b55accdc90f463d983eba43e3b78335e974036622808c42488b99589b9c94a8c7dfce6e76f32d6e5da5fc65cb2888a09f2dc7210a85ed058109f26a50bf languageName: node linkType: hard -"@xmtp/node-sdk@npm:0.0.47": - version: 0.0.47 - resolution: "@xmtp/node-sdk@npm:0.0.47" +"@xmtp/node-sdk@npm:1.0.0-rc1": + version: 1.0.0-rc1 + resolution: "@xmtp/node-sdk@npm:1.0.0-rc1" dependencies: "@xmtp/content-type-group-updated": "npm:^2.0.0" "@xmtp/content-type-primitives": "npm:^2.0.0" "@xmtp/content-type-text": "npm:^2.0.0" - "@xmtp/node-bindings": "npm:^0.0.41" + "@xmtp/node-bindings": "npm:^1.0.0-rc2" "@xmtp/proto": "npm:^3.72.3" - checksum: 10/bf3b5e59cc5be0b9ec02acd2d7cf59bcae5f478971b5ffc772e6153c8d59515032c95436faf2c741e1de334d9572dc1991098395d9813ec5364f0eb09666a815 + checksum: 10/0f79fd211e56a627250015104c90605ca4b4cf39716877761311bc067c9dcf61b31e687a88880809a6a89d8fdb2729a271b309a961001660a53fec88ae2afbce languageName: node linkType: hard @@ -3842,7 +3842,7 @@ __metadata: "@ianvs/prettier-plugin-sort-imports": "npm:^4.4.1" "@types/eslint__js": "npm:^8.42.3" "@types/node": "npm:^22.13.0" - "@xmtp/node-sdk": "npm:0.0.47" + "@xmtp/node-sdk": "npm:1.0.0-rc1" alchemy-sdk: "npm:^3.0.0" eslint: "npm:^9.19.0" eslint-config-prettier: "npm:^10.0.1" From 9a2467dfa8218a629a626eb6eefd528b94eac96a Mon Sep 17 00:00:00 2001 From: fabri Date: Wed, 12 Mar 2025 13:26:24 -0300 Subject: [PATCH 3/7] added readme update --- README.md | 20 ++++++++++++++++++++ examples/gated-group/index.ts | 1 + 2 files changed, 21 insertions(+) diff --git a/README.md b/README.md index 2cd95b8..3a54c3b 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,26 @@ await client.conversations.sync(); await client.conversations.messages(); ``` +### Conversations can be of type `Group` or `Dm` + +The new `Group` and `Dm` classes extend the `Conversation` class and provide specific functionality based on the conversation type. + +```tsx +const conversations: (Group | Dm)[] = await client.conversations.list(); + +for (const conversation of conversations) { + // narrow the type to Group to access the group name + if (conversation instanceof Group) { + console.log(group.name); + } + + // narrow the type to Dm to access the peer inboxId + if (conversation instanceof Dm) { + console.log(conversation.peerInboxId); + } +} +``` + ### Working with addresses Conversations in XMTP can be `DMs` or `Groups`. The underlying technicalities are the same, but DMs are essentially groups locked between two users that can be reused - basically a fixed group of 2. This is how MLS works. diff --git a/examples/gated-group/index.ts b/examples/gated-group/index.ts index c1ac9b1..8e5aec9 100644 --- a/examples/gated-group/index.ts +++ b/examples/gated-group/index.ts @@ -38,6 +38,7 @@ async function main() { const identifier = await signer.getIdentifier(); const address = identifier.identifier; + console.log( `Agent initialized on ${address}\nSend a message on http://xmtp.chat/dm/${address}`, ); From 16457af99de5db14ab5699bab908868a4777a2f9 Mon Sep 17 00:00:00 2001 From: fabri Date: Wed, 12 Mar 2025 13:37:11 -0300 Subject: [PATCH 4/7] helper for address --- README.md | 29 ----------------------------- examples/gated-group/README.md | 3 --- examples/gm/index.ts | 10 ++++++++-- examples/gpt/README.md | 3 --- helpers/index.ts | 21 ++++++++++++++++++++- integrations/gaia/README.md | 3 --- integrations/grok/README.md | 3 --- scripts/generateKeys.ts | 3 +++ 8 files changed, 31 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 3a54c3b..3e2f72d 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,6 @@ You can generate random keys with the following command: yarn gen:keys ``` -> [!WARNING] -> Running the `gen:keys` script will overwrite the existing `.env` file. - ### Fetching messages There are to ways to fetch messages from a conversation, one is by starting a stream @@ -72,32 +69,6 @@ for (const conversation of conversations) { } ``` -### Working with addresses - -Conversations in XMTP can be `DMs` or `Groups`. The underlying technicalities are the same, but DMs are essentially groups locked between two users that can be reused - basically a fixed group of 2. This is how MLS works. - -Each member of a conversation has the following properties: - -```tsx -inboxId: string; // unique identifier from the XMTP network -accountAddresses: Array; // ethereum network addresses -installationIds: Array; // How many active devices the user has -permissionLevel: PermissionLevel; // In the context of a group, if it's admin or not -consentState: ConsentState; // If it's blocked or allowed via consent -``` - -To fetch an ethereum address in a DM, you can use a script like the following: - -```tsx -const address = - (await group.members?.find( - (member: any) => member.inboxId === dm.dmPeerInboxId, - )?.accountAddresses[0]) || ""; -``` - -> [!WARNING] -> XMTP is working on integrating passkeys as a pillar of identity. Expect a breaking change soon as XMTP prepares for the first v3 stable release. - ## Web inbox Interact with the XMTP network using [xmtp.chat](https://xmtp.chat), the official web inbox for developers. diff --git a/examples/gated-group/README.md b/examples/gated-group/README.md index 3932b17..987a898 100644 --- a/examples/gated-group/README.md +++ b/examples/gated-group/README.md @@ -20,9 +20,6 @@ You can generate random keys with the following command: yarn gen:keys ``` -> [!WARNING] -> Running the `gen:keys` script will overwrite the existing `.env` file. - ## Start the XMTP agent Start your XMTP client and begin listening to messages. The bot responds to the following commands: diff --git a/examples/gm/index.ts b/examples/gm/index.ts index c11e361..365e4bf 100644 --- a/examples/gm/index.ts +++ b/examples/gm/index.ts @@ -1,5 +1,9 @@ import { Client, type XmtpEnv } from "@xmtp/node-sdk"; -import { createSigner, getEncryptionKeyFromHex } from "@/helpers"; +import { + createSigner, + getAddressOfMember, + getEncryptionKeyFromHex, +} from "@/helpers"; /* Get the wallet key associated to the public key of * the agent and the encryption key for the local db @@ -62,8 +66,10 @@ async function main() { console.log("Unable to find conversation, skipping"); continue; } + const members = await conversation.members(); - console.log(`Sending "gm" response...`); + const address = getAddressOfMember(members, message.senderInboxId); + console.log(`Sending "gm" response to ${address}...`); /* Send a message to the conversation */ await conversation.send("gm"); diff --git a/examples/gpt/README.md b/examples/gpt/README.md index 0fb92e4..c6387a5 100644 --- a/examples/gpt/README.md +++ b/examples/gpt/README.md @@ -18,9 +18,6 @@ You can generate random keys with the following command: yarn gen:keys ``` -> [!WARNING] -> Running the `gen:keys` script will overwrite the existing `.env` file. - ## Usage ```tsx diff --git a/helpers/index.ts b/helpers/index.ts index 5a2efc3..6174df1 100644 --- a/helpers/index.ts +++ b/helpers/index.ts @@ -1,5 +1,5 @@ import { getRandomValues } from "node:crypto"; -import { IdentifierKind } from "@xmtp/node-bindings"; +import { IdentifierKind, type GroupMember } from "@xmtp/node-bindings"; import { type Signer } from "@xmtp/node-sdk"; import { fromString, toString } from "uint8arrays"; import { createWalletClient, http, toBytes } from "viem"; @@ -44,6 +44,25 @@ export const createSigner = (key: `0x${string}`): Signer => { }; }; +/** + * Get the address of a member + * @param members - The members of the group + * @param inboxId - The inboxId of the member + * @returns The address of the member + */ +export function getAddressOfMember(members: GroupMember[], inboxId: string) { + for (const member of members) { + for (const identifier of member.accountIdentifiers) { + if ( + identifier.identifierKind === IdentifierKind.Ethereum && + member.inboxId === inboxId + ) { + return identifier.identifier; + } + } + } +} + /** * Generate a random encryption key * @returns The encryption key diff --git a/integrations/gaia/README.md b/integrations/gaia/README.md index e517590..197de58 100644 --- a/integrations/gaia/README.md +++ b/integrations/gaia/README.md @@ -22,9 +22,6 @@ You can generate random keys with the following command: yarn gen:keys ``` -> [!WARNING] -> Running the `gen:keys` script will overwrite the existing `.env` file. - ## Usage ```tsx diff --git a/integrations/grok/README.md b/integrations/grok/README.md index 2ceb6fe..f9cac76 100644 --- a/integrations/grok/README.md +++ b/integrations/grok/README.md @@ -18,9 +18,6 @@ You can generate random keys with the following command: yarn gen:keys ``` -> [!WARNING] -> Running the `gen:keys` script will overwrite the existing `.env` file. - ## Usage ```tsx diff --git a/scripts/generateKeys.ts b/scripts/generateKeys.ts index d49280a..8a40ded 100644 --- a/scripts/generateKeys.ts +++ b/scripts/generateKeys.ts @@ -15,6 +15,9 @@ await writeFile( `WALLET_KEY=${walletKey} ENCRYPTION_KEY=${encryptionKeyHex} `, + { + flag: "a", + }, ); console.log(`Keys written to ${filePath}`); From 84cb592823a5bee8e96c37b6e7ef07c0ef3131d8 Mon Sep 17 00:00:00 2001 From: fabri Date: Wed, 12 Mar 2025 13:38:02 -0300 Subject: [PATCH 5/7] helper for address --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/README.md b/README.md index 3e2f72d..3e462fb 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,32 @@ for (const conversation of conversations) { } ``` +## Working with addresses + +Because XMTP is interoperable, you may interact with inboxes that are not on your app. In these scenarios, you will need to find the appropriate inbox ID or address. + +```tsx +// get an inbox ID from an address +const inboxId = await getInboxIdForIdentifier({ + identifier: "0x1234567890abcdef1234567890abcdef12345678", + identifierKind: IdentifierKind.Ethereum, +}); + +// find the addresses associated with an inbox ID +const inboxState = await client.inboxStateFromInboxIds([inboxId]); + +interface InboxState { + inboxId: string; + recoveryIdentifier: Identifier; + installations: Installation[]; + identifiers: Identifier[]; +} + +const addresses = inboxState.identifiers + .filter((i) => i.identifierKind === IdentifierKind.Ethereum) + .map((i) => i.identifier); +``` + ## Web inbox Interact with the XMTP network using [xmtp.chat](https://xmtp.chat), the official web inbox for developers. From ee77c8433a70b449ce41d5d300934705fe3621fb Mon Sep 17 00:00:00 2001 From: fabri Date: Thu, 13 Mar 2025 14:51:34 -0300 Subject: [PATCH 6/7] update keys --- README.md | 5 ++++- scripts/generateKeys.ts | 36 ++++++++++++++++++++++++++---------- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 3e462fb..9366f85 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,12 @@ ENCRYPTION_KEY= # encryption key for the local database You can generate random keys with the following command: ```bash -yarn gen:keys +yarn gen:keys ``` +> [!TIP] +> Running the `gen:keys` or `gen:keys ` command will write to the existing `.env` file. + ### Fetching messages There are to ways to fetch messages from a conversation, one is by starting a stream diff --git a/scripts/generateKeys.ts b/scripts/generateKeys.ts index 8a40ded..0a88fa0 100644 --- a/scripts/generateKeys.ts +++ b/scripts/generateKeys.ts @@ -1,23 +1,39 @@ import { writeFile } from "node:fs/promises"; import { join } from "node:path"; -import { generatePrivateKey } from "viem/accounts"; +import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; import { generateEncryptionKeyHex } from "@/helpers"; console.log("Generating keys..."); +const person = process.argv[2]; const walletKey = generatePrivateKey(); +const account = privateKeyToAccount(walletKey); const encryptionKeyHex = generateEncryptionKeyHex(); +const publicKey = account.address; const filePath = join(process.cwd(), ".env"); -await writeFile( - filePath, - `WALLET_KEY=${walletKey} +// Format the environment variables based on whether a person name was provided +let envContent; +if (person) { + envContent = `# ${person.toLowerCase()} +WALLET_KEY_${person.toUpperCase()}=${walletKey} +ENCRYPTION_KEY_${person.toUpperCase()}=${encryptionKeyHex} +# public key is ${publicKey} +`; +} else { + envContent = `# generic keys +WALLET_KEY=${walletKey} ENCRYPTION_KEY=${encryptionKeyHex} -`, - { - flag: "a", - }, -); +# public key is ${publicKey} +`; +} -console.log(`Keys written to ${filePath}`); +await writeFile(filePath, envContent, { flag: "a" }); + +// Log appropriate message based on whether a person name was provided +if (person) { + console.log(`Keys for ${person} written to ${filePath}`); +} else { + console.log(`Generic keys written to ${filePath}`); +} From 0e671fdf04795acedbf2194945e7c21875239a97 Mon Sep 17 00:00:00 2001 From: fabri Date: Thu, 13 Mar 2025 15:05:24 -0300 Subject: [PATCH 7/7] fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9366f85..247eba6 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ yarn gen:keys ``` > [!TIP] -> Running the `gen:keys` or `gen:keys ` command will write to the existing `.env` file. +> Running the `gen:keys` or `gen:keys ` command will append keys to your existing `.env` file. ### Fetching messages