Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ELIZAAI-21-create-readme-for-generating-access-token #20

Open
wants to merge 11 commits into
base: develop
Choose a base branch
from
Open
62 changes: 62 additions & 0 deletions docs/docs/Linkedin Client/generating-access-token.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# How to Generate an Access Token Manually Using the LinkedIn Developer Portal

The LinkedIn access token is essential for enabling API calls on behalf of a user. It allows your application to interact with LinkedIn's API to perform actions such as posting updates, accessing user profiles, and managing LinkedIn pages. The following instructions will guide you through the process of generating this token.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth to mention that this will result in getting an access token for interacting with User Account which will allow posting only as a Person not as a Company.


## Step 1: Create a New Application

1. Navigate to the [LinkedIn Developer Portal](https://developer.linkedin.com/).
2. Click the **Create app** button.
3. Fill in the **App name** field.
4. Specify a **LinkedIn Page** (either select an existing page or create a new one).
5. Upload a **logo** from your local device.
6. Agree to the terms and conditions by selecting **I have read and agree to these terms**.
7. Complete the process by clicking the **Create app** button.

## Step 2: Configure Your Linkedin Application

1. Navigate to the **Products** tab in your application.
2. Under **OAuth Permissions**, select the following scopes:
- **Sign In with LinkedIn using OpenID Connect**
- **Share on LinkedIn**

## Step 3: Generate an Access Token

1. Open the **Auth** tab in your application.
2. Click on the **OAuth 2.0 tools** link (you can also navigate via **Docs and tools > OAuth Token Tools** in the navigation bar).
3. Press **Create token** to start the process.
4. Ensure the **OAuth flow** is set to **Member authorization code (3-legged)**.
5. Under **Select scopes**, check the boxes for:
- `openid`
- `profile`
- `w_member_social`
6. Click the **Request access token** button.
7. Log in using your LinkedIn credentials and click **Sign In**.
8. Grant your application the requested permissions by selecting **Allow**.
9. After successful authorization, your **access token** will be displayed and is ready for use.

### Resolving Common Issues

If you encounter the error:

> "We can’t verify the authenticity of your request because the state parameter was modified."

This may indicate that your browser is blocking the request. To resolve:

- Disable all browser extensions temporarily.
- Try generating the token in another browser (e.g., Google Chrome).

```
Important! Be aware that some browsers, such as Brave, have built-in protections that might block token generation.
```

## Important Notes

- The access token is valid for **2 months**. After expiration, you must repeat the steps above to generate a new token.
- If the token does not have all the required permissions, regenerate it and ensure the correct scopes are selected.
- Generating the access token automatically updates the **Authorized redirect URLs for your app** field in your application.

### What Is a Redirect URL?

A **redirect URL** is the URI where users are sent after authorization. It must match one of the redirect URLs defined in your application configuration.

For more detailed information, visit Microsoft's official documentation on the [Authorization Code Flow (3-legged OAuth)](https://learn.microsoft.com/en-us/linkedin/shared/authentication/authorization-code-flow?tabs=HTTPS1).
30 changes: 30 additions & 0 deletions packages/plugin-cosmos/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,36 @@ Yes

4. Action executed.

### Token IBC Transfer

This plugin supports a token transfer action, which allows users to transfer tokens between addresses on Cosmos-compatible blockchains between different chains.

#### Example Prompts

Below are examples of how the ibc transfer action can be initiated and confirmed:

**Example**

1. User input:

```
Make an IBC transfer 0.0001 OSMO to neutron1nk3uuw6zt5t5aqw5fvujkd54sa4uws9xg2nk82 from osmosistestnet to neutrontestnet
```

2. Plugin response:

```
Before making the IBC transfer, I would like to confirm the details. You would like to transfer 0.0001 OSMO from osmosistestnet to neutrontestnet, specifically to the address neutron1nk3uuw6zt5t5aqw5fvujkd54sa4uws9xg2nk82, is that correct?
```

3. User confirmation:

```
Yes
```

4. Action executed.

---

## Contribution
Expand Down
2 changes: 2 additions & 0 deletions packages/plugin-cosmos/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
"@cosmjs/cosmwasm-stargate": "^0.32.4",
"@cosmjs/proto-signing": "^0.32.4",
"@cosmjs/stargate": "^0.32.4",
"@skip-go/client": "^0.16.3",
"axios": "^1.7.9",
"bignumber.js": "9.1.2",
"chain-registry": "^1.69.68",
"tsup": "8.3.5",
Expand Down
226 changes: 226 additions & 0 deletions packages/plugin-cosmos/src/actions/ibc-transfer/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
import {
composeContext,
generateObjectDeprecated,
HandlerCallback,
IAgentRuntime,
Memory,
ModelClass,
State,
} from "@elizaos/core";
import { initWalletChainsData } from "../../providers/wallet/utils";
import {
cosmosIBCTransferTemplate,
cosmosTransferTemplate,
} from "../../templates";
import type {
ICosmosPluginOptions,
ICosmosWalletChains,
} from "../../shared/interfaces";
import { IBCTransferActionParams } from "./types";
import { IBCTransferAction } from "./services/ibc-transfer-action-service";
import { bridgeDenomProvider } from "./services/bridge-denom-provider";

export const createIBCTransferAction = (
pluginOptions: ICosmosPluginOptions
) => ({
name: "COSMOS_IBC_TRANSFER",
description: "Transfer tokens between addresses on cosmos chains",
handler: async (
_runtime: IAgentRuntime,
_message: Memory,
state: State,
_options: { [key: string]: unknown },
_callback?: HandlerCallback
) => {
const cosmosIBCTransferContext = composeContext({
state: state,
template: cosmosIBCTransferTemplate,
templatingEngine: "handlebars",
});

const cosmosIBCTransferContent = await generateObjectDeprecated({
runtime: _runtime,
context: cosmosIBCTransferContext,
modelClass: ModelClass.SMALL,
});

const paramOptions: IBCTransferActionParams = {
chainName: cosmosIBCTransferContent.chainName,
symbol: cosmosIBCTransferContent.symbol,
amount: cosmosIBCTransferContent.amount,
toAddress: cosmosIBCTransferContent.toAddress,
targetChainName: cosmosIBCTransferContent.targetChainName,
};

try {
const walletProvider: ICosmosWalletChains =
await initWalletChainsData(_runtime);

const action = new IBCTransferAction(walletProvider);

const customAssets = (pluginOptions?.customChainData ?? []).map(
(chainData) => chainData.assets
);

const transferResp = await action.execute(
paramOptions,
bridgeDenomProvider,
customAssets
);

if (_callback) {
await _callback({
text: `Successfully transferred ${paramOptions.amount} tokens from ${paramOptions.chainName} to ${paramOptions.toAddress} on ${paramOptions.targetChainName}\nTransaction Hash: ${transferResp.txHash}`,
content: {
success: true,
hash: transferResp.txHash,
amount: paramOptions.amount,
recipient: transferResp.to,
fromChain: paramOptions.chainName,
toChain: paramOptions.targetChainName,
},
});

const newMemory: Memory = {
userId: _message.agentId,
agentId: _message.agentId,
roomId: _message.roomId,
content: {
text: `Transaction ${paramOptions.amount} ${paramOptions.symbol} to address ${paramOptions.toAddress} from chain ${paramOptions.chainName} to ${paramOptions.targetChainName} was successfully transferred. Tx hash: ${transferResp.txHash}`,
},
};

await _runtime.messageManager.createMemory(newMemory);
}
return true;
} catch (error) {
console.error("Error during ibc token transfer:", error);

if (_callback) {
await _callback({
text: `Error ibc transferring tokens: ${error.message}`,
content: { error: error.message },
});
}

const newMemory: Memory = {
userId: _message.agentId,
agentId: _message.agentId,
roomId: _message.roomId,
content: {
text: `Transaction ${paramOptions.amount} ${paramOptions.symbol} to address ${paramOptions.toAddress} on chain ${paramOptions.chainName} to ${paramOptions.targetChainName} was unsuccessful.`,
},
};

await _runtime.messageManager.createMemory(newMemory);

return false;
}
},
template: cosmosTransferTemplate,
validate: async (runtime: IAgentRuntime) => {
const mnemonic = runtime.getSetting("COSMOS_RECOVERY_PHRASE");
const availableChains = runtime.getSetting("COSMOS_AVAILABLE_CHAINS");
const availableChainsArray = availableChains?.split(",");

return !(mnemonic && availableChains && availableChainsArray.length);
},
examples: [
[
{
user: "{{user1}}",
content: {
text: "Make an IBC transfer {{0.0001 ATOM}} to {{osmosis1pcnw46km8m5amvf7jlk2ks5std75k73aralhcf}} from {{cosmoshub}} to {{osmosis}}",
action: "COSMOS_IBC_TRANSFER",
},
},
{
user: "{{user2}}",
content: {
text: "Do you confirm the IBC transfer action?",
action: "COSMOS_IBC_TRANSFER",
},
},
{
user: "{{user1}}",
content: {
text: "Yes",
action: "COSMOS_IBC_TRANSFER",
},
},
{
user: "{{user2}}",
content: {
text: "",
action: "COSMOS_IBC_TRANSFER",
},
},
],
[
{
user: "{{user1}}",
content: {
text: "Send {{50 OSMO}} to {{juno13248w8dtnn07sxc3gq4l3ts4rvfyat6f4qkdd6}} from {{osmosis}} to {{juno}}",
action: "COSMOS_IBC_TRANSFER",
},
},
{
user: "{{user2}}",
content: {
text: "Do you confirm the IBC transfer action?",
action: "COSMOS_IBC_TRANSFER",
},
},
{
user: "{{user1}}",
content: {
text: "Yes",
action: "COSMOS_IBC_TRANSFER",
},
},
{
user: "{{user2}}",
content: {
text: "",
action: "COSMOS_IBC_TRANSFER",
},
},
],
[
{
user: "{{user1}}",
content: {
text: "Transfer {{0.005 JUNO}} from {{juno}} to {{cosmos1n0xv7z2pkl4eppnm7g2rqhe2q8q6v69h7w93fc}} on {{cosmoshub}}",
action: "COSMOS_IBC_TRANSFER",
},
},
{
user: "{{user2}}",
content: {
text: "Do you confirm the IBC transfer action?",
action: "COSMOS_IBC_TRANSFER",
},
},
{
user: "{{user1}}",
content: {
text: "Yes",
action: "COSMOS_IBC_TRANSFER",
},
},
{
user: "{{user2}}",
content: {
text: "",
action: "COSMOS_IBC_TRANSFER",
},
},
],
],
similes: [
"COSMOS_BRIDGE_TOKEN",
"COSMOS_IBC_SEND_TOKEN",
"COSMOS_TOKEN_IBC_TRANSFER",
"COSMOS_MOVE_IBC_TOKENS",
],
});
9 changes: 9 additions & 0 deletions packages/plugin-cosmos/src/actions/ibc-transfer/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { z } from "zod";

export const IBCTransferParamsSchema = z.object({
chainName: z.string(),
symbol: z.string(),
amount: z.string(),
toAddress: z.string(),
targetChainName: z.string(),
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { IDenomProvider } from "../../../shared/interfaces";
import { SkipApiAssetsFromSourceFetcher } from "../../../shared/services/skip-api/assets-from-source-fetcher/skip-api-assets-from-source-fetcher";

export const bridgeDenomProvider: IDenomProvider = async (
sourceAssetDenom: string,
sourceAssetChainId: string,
destChainId: string
) => {
const skipApiAssetsFromSourceFetcher =
SkipApiAssetsFromSourceFetcher.getInstance();
const bridgeData = await skipApiAssetsFromSourceFetcher.fetch(
sourceAssetDenom,
sourceAssetChainId
);

const ibcAssetData = bridgeData.dest_assets[destChainId]?.assets?.find(
({ origin_denom }) => origin_denom === sourceAssetDenom
);

if (!ibcAssetData.denom) {
throw new Error("No IBC asset data");
}

return {
denom: ibcAssetData.denom,
};
};
Loading
Loading