Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
6abd911
installed required near packages
EdsonAlcala Mar 13, 2025
6cd5cf5
added near wallet provider
EdsonAlcala Mar 13, 2025
a155a6b
added near action provider
EdsonAlcala Mar 13, 2025
53db579
fixed types in action provider
EdsonAlcala Mar 13, 2025
fdbb4e7
added missing package
EdsonAlcala Mar 13, 2025
1eaf03e
added near chatbot example
EdsonAlcala Mar 13, 2025
e419423
added to ignore the near keystore
EdsonAlcala Mar 13, 2025
a66468d
added near example to the workspace
EdsonAlcala Mar 13, 2025
cd894c8
fixed module and relative path to main base config
EdsonAlcala Mar 13, 2025
25526d7
updated changelog
EdsonAlcala Mar 13, 2025
c9b0ed6
fixed dependencies in the near example chatbot
EdsonAlcala Mar 13, 2025
11692e8
updated example
EdsonAlcala Mar 13, 2025
ec68e4a
fix lint
EdsonAlcala Mar 13, 2025
a354da8
fix lint
EdsonAlcala Mar 13, 2025
c6f037d
fixed linting
EdsonAlcala Mar 13, 2025
fc5016f
fix eslint errors
EdsonAlcala Mar 13, 2025
898b541
added more comments
EdsonAlcala Mar 14, 2025
def3181
more linting
EdsonAlcala Mar 14, 2025
3be1cc4
more linting issues
EdsonAlcala Mar 14, 2025
c99325c
fixed more lint issues
EdsonAlcala Mar 14, 2025
f8d1f0c
fixed more errors
EdsonAlcala Mar 17, 2025
73b3937
fixed lint
EdsonAlcala Mar 17, 2025
461b648
updated agentkit reference
EdsonAlcala Mar 21, 2025
70ec53b
updated near example reference
EdsonAlcala Mar 31, 2025
dbe48ac
updated pnpms package lock
EdsonAlcala Mar 31, 2025
781a9ba
updated near example reference
EdsonAlcala Apr 11, 2025
94aab46
fix lock yaml file
EdsonAlcala Apr 11, 2025
9e1ccd3
inlined descriptions
EdsonAlcala Apr 11, 2025
8d8cbed
updated promised issue
EdsonAlcala Apr 11, 2025
ad67767
added action readme
EdsonAlcala Apr 15, 2025
dc99b91
Merge branch 'main' into feat/near-chain-signatures-support
EdsonAlcala Apr 15, 2025
057286a
added changeset
EdsonAlcala Apr 15, 2025
fc59bcd
Merge branch 'main' into feat/near-chain-signatures-support
EdsonAlcala Apr 15, 2025
defffe2
fixed pnpm lock file
EdsonAlcala Apr 15, 2025
71a6671
applied format to codebase
EdsonAlcala Apr 16, 2025
d647165
fix missing package
EdsonAlcala Apr 16, 2025
ce6001e
fixed near action provider test
EdsonAlcala Apr 16, 2025
ad931c1
fixed lint warnings
EdsonAlcala Apr 16, 2025
9ad9f5b
fixed format warnings
EdsonAlcala Apr 16, 2025
c04cccb
fixed
EdsonAlcala Apr 18, 2025
0f2c16e
reinstalled js-sha3 to fix merge
EdsonAlcala Apr 18, 2025
d941f7a
fixed format and linting
EdsonAlcala Apr 18, 2025
4302eb8
Merge branch 'main' into feat/near-chain-signatures-support
EdsonAlcala May 1, 2025
071e22f
Merge branch 'main' into feat/near-chain-signatures-support
EdsonAlcala May 2, 2025
3eeb842
Merge branch 'main' into feat/near-chain-signatures-support
EdsonAlcala May 13, 2025
3c52838
Merge branch 'main' into feat/near-chain-signatures-support
EdsonAlcala May 15, 2025
22d89fa
Merge branch 'main' into feat/near-chain-signatures-support
EdsonAlcala May 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,6 @@ docs/
# pnpm
typescript/.pnpm-store
typescript/.pnp.*

# Near keytore
.near-credentials
5 changes: 5 additions & 0 deletions typescript/.changeset/mean-cooks-tan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@coinbase/agentkit": minor
---

Added NEAR action provider to interact with NEAR chain signatures
17 changes: 14 additions & 3 deletions typescript/agentkit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,29 @@
"@coinbase/cdp-sdk": "^1.3.0",
"@coinbase/coinbase-sdk": "^0.20.0",
"@jup-ag/api": "^6.0.39",
"@near-js/accounts": "^1.3.1",
"@near-js/crypto": "^1.4.2",
"@near-js/keystores": "^0.2.1",
"@near-js/providers": "^1.0.1",
"@near-js/signers": "^0.2.1",
"@near-js/transactions": "^1.3.1",
"@near-js/types": "^0.3.1",
"@near-js/utils": "^1.0.1",
"@privy-io/public-api": "^2.18.5",
"@privy-io/server-auth": "^1.18.4",
"@solana/spl-token": "^0.4.12",
"@solana/web3.js": "^1.98.0",
"@zerodev/ecdsa-validator": "^5.4.5",
"@zerodev/intent": "^0.0.24",
"@zerodev/sdk": "^5.4.28",
"bs58": "^4.0.1",
"canonicalize": "^2.1.0",
"decimal.js": "^10.5.0",
"elliptic": "^6.6.1",
"ethers": "^6.13.5",
"@zerodev/ecdsa-validator": "^5.4.5",
"@zerodev/intent": "^0.0.24",
"@zerodev/sdk": "^5.4.28",
"js-sha3": "^0.9.3",
"md5": "^2.3.0",
"near-api-js": "^5.0.1",
"opensea-js": "^7.1.18",
"reflect-metadata": "^0.2.2",
"twitter-api-v2": "^1.18.2",
Expand Down
1 change: 1 addition & 0 deletions typescript/agentkit/src/action-providers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ export * from "./flaunch";
export * from "./onramp";
export * from "./vaultsfyi";
export * from "./zerodev";
export * from "./near";
42 changes: 42 additions & 0 deletions typescript/agentkit/src/action-providers/near/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# NEAR Action Provider

This directory contains the **NearActionProvider** implementation, which provides actions to interact with the [NEAR Protocol Chain Signatures](https://docs.near.org/chain-abstraction/chain-signatures), that allows a NEAR protocol account to control other accounts/addresses across multiple chains.

## Directory Structure

```
near/
├── nearActionProvider.ts # Main provider with Chain signatures functionality
├── nearActionProvider.test.ts # Test file for Near action provider
├── constants.ts # Constants and addresses of the MPC signer
├── schemas.ts # Action schemas
├── types.ts # Types
├── utils/address.ts # Address utilities for chain signatures
├── utils/mpcContract.ts # Utilities to interact with the MPC contract
├── utils/nearChainSignature.ts # Utilities for deriving addreses
├── utils/nearChainSignature.test.ts # Test file for Near chain signature utilities
├── index.ts # Main exports
└── README.md # This file
```

## Actions

- `get_cross_chain_address`: Compute a cross chain address
- `get_cross_chain_public_key`: Compute a cross chain public key
- `sign_payload`: Signs a transaction payload

## Adding New Actions

To add new NEAR chain signatures actions:

1. Define your action schema in `schemas.ts`
2. Implement the action in `nearActionProvider.ts`
3. Add tests in `nearActionProvider.test.ts`

## Network Support

The Morpho provider supports `near-testnet` and `near-mainnet`.

## Notes

For more information about **Chain Signatures**, visit [Chain Signatures](https://docs.near.org/chain-abstraction/chain-signatures)
32 changes: 32 additions & 0 deletions typescript/agentkit/src/action-providers/near/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { NEAR_MAINNET_NETWORK_ID, NEAR_TESTNET_NETWORK_ID } from "../../network/near";

export const SUPPORTED_NETWORKS = [NEAR_MAINNET_NETWORK_ID, NEAR_TESTNET_NETWORK_ID];

export const SUPPORTED_ADDRESS_TYPES = [
"evm",
"bitcoin-mainnet-legacy",
"bitcoin-mainnet-segwit",
"bitcoin-testnet-legacy",
"bitcoin-testnet-segwit",
];

export const DEFAULT_PATH = "account-1";

export const DEFAULT_KEY_VERSION = 0;

// https://docs.near.org/build/chain-abstraction/chain-signatures/#1-deriving-the-foreign-address
export const MPC_SIGNER_TESTNET = "v1.signer-prod.testnet";

export const MPC_SIGNER_MAINNET = "v1.signer";

export const ROOT_PUBLIC_KEY_TESTNET =
"secp256k1:4NfTiv3UsGahebgTaHyD9vF8KYKMBnfd6kh94mK6xv8fGBiJB8TBtFMP5WWXz6B89Ac1fbpzPwAvoyQebemHFwx3";

export const ROOT_PUBLIC_KEY_MAINNET =
"secp256k1:3tFRbMqmoa6AAALMrEFAYCEoHcqKxeW38YptwowBVBtXK1vo36HDbUWuR6EZmoK4JcH6HDkNMGGqP1ouV7VZUWya";

export const TGAS = 1000000000000n;

export const NEAR_MAX_GAS = 300000000000000n;

export const NO_DEPOSIT = "0";
2 changes: 2 additions & 0 deletions typescript/agentkit/src/action-providers/near/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./nearActionProvider";
export * from "./schemas";
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import { Connection } from "@near-js/accounts";
import { JsonRpcProvider } from "@near-js/providers";
import { InMemoryKeyStore } from "@near-js/keyStores";
import { NEAR_MAINNET_NETWORK, NEAR_MAINNET_NETWORK_ID, NEAR_NETWORK_ID } from "../../network";
import { NEARWalletProvider } from "../../wallet-providers";
import { NearActionProvider } from "./nearActionProvider";
import { MpcContract } from "./utils";

jest.mock("@near-js/utils", () => ({
...jest.requireActual("@near-js/utils"),
getTransactionLastResult: jest.fn().mockReturnValue({
big_r: {
affine_point: "02ACE91E6368E5859640CB8E988D70E6C1551E3B8AEC897084C5A2797EF606CCE8",
},
s: {
scalar: "3A84B3C0C157FFE0AC271A07F6ABB4BA8821E010F359FAEE05D82796122926F2",
},
recovery_id: 0,
}),
}));

describe("NearActionProvider", () => {
const actionProvider = new NearActionProvider();
let mockWallet: jest.Mocked<NEARWalletProvider>;
let mockProvider: jest.Mocked<JsonRpcProvider>;
let mockConnection: jest.Mocked<Connection>;
let mockSigner: jest.Mocked<InMemoryKeyStore>;

const MOCK_ADDRESS = "wallet.near";
const MOCK_CONTRACT = "contract.near";
const MOCK_DESTINATION = "destination.near";
const MOCK_TX_HASH = "5j2XGJZXq8McE9x4Y8EJ3f9tVQvFfY6zK7k1d9QXp6Bq";
const ACCOUNT_ID = "jsvm.testnet";
const MOCK_SIGNATURE = {
big_r: {
affine_point: "02ACE91E6368E5859640CB8E988D70E6C1551E3B8AEC897084C5A2797EF606CCE8",
},
s: {
scalar: "3A84B3C0C157FFE0AC271A07F6ABB4BA8821E010F359FAEE05D82796122926F2",
},
recovery_id: 0,
};

beforeEach(() => {
mockProvider = new JsonRpcProvider({
url: "https://rpc.testnet.near.org",
}) as jest.Mocked<JsonRpcProvider>;
mockSigner = new InMemoryKeyStore();
mockConnection = new Connection(NEAR_MAINNET_NETWORK, mockProvider, mockSigner, ACCOUNT_ID);

mockWallet = {
getAddress: jest.fn().mockReturnValue(MOCK_ADDRESS),
getNetwork: jest.fn().mockReturnValue(NEAR_MAINNET_NETWORK),
getName: jest.fn().mockReturnValue("NEAR Wallet"),
getBalance: jest.fn().mockResolvedValue(BigInt(100000000000000000000)),
nativeTransfer: jest.fn().mockResolvedValue(MOCK_TX_HASH as `0x${string}`),
getAccount: jest.fn().mockReturnValue({
accountId: MOCK_ADDRESS,
connection: mockConnection,
contract: MOCK_CONTRACT,
destination: MOCK_DESTINATION,
signAndSendTransaction: jest.fn().mockResolvedValue(MOCK_TX_HASH as `0x${string}`),
}),
getConnection: jest.fn().mockReturnValue(mockConnection),
getPublicKey: jest.fn().mockReturnValue("0494da"),
signAndSendTransaction: jest.fn().mockResolvedValue(MOCK_TX_HASH as `0x${string}`),
} as unknown as jest.Mocked<NEARWalletProvider>;
});

describe("getCrossChainAddress", () => {
it("should return the crosschain address when using default values", async () => {
const args = {
accountId: undefined,
networkId: undefined,
path: undefined,
addressType: "evm",
};

const response = await actionProvider.getCrossChainAddress(mockWallet, args);

expect(response).toEqual(
"Generated cross chain address of type evm for account id wallet.near, network near-mainnet and derivation path account-1 is 0x5cf7ac588d5cdb35d8a9ed3d884f1a4245338db7",
);
});

it("should return the crosschain address when using defined values", async () => {
const args = {
accountId: "omnitester.near",
networkId: NEAR_MAINNET_NETWORK_ID as NEAR_NETWORK_ID,
path: "account-1",
addressType: "evm",
};

const response = await actionProvider.getCrossChainAddress(mockWallet, args);

expect(response).toEqual(
"Generated cross chain address of type evm for account id omnitester.near, network near-mainnet and derivation path account-1 is 0x9ee8197e1a04cc53ee976894082449d2f450ae34",
);
});
});

describe("getCrossChainPublicKey", () => {
it("should return the crosschain public key when using default values", async () => {
const args = {
accountId: undefined,
networkId: undefined,
path: undefined,
};

const response = await actionProvider.getCrossChainPublicKey(mockWallet, args);

const expectedMessagePart =
"Computed public key for account id wallet.near, network near-mainnet and derivation path account-1 is";
const expectedPublicKey =
"04360c67764d827f09b08e8749eb4d7362ca825176f9d67c233b63aff64f4a6b947aee76cda76f1645952ed6e259bb270a76853da16d2601e4bf2e0c60b852c66d";

expect(response).toEqual(`${expectedMessagePart} ${expectedPublicKey}`);
});

it("should return the crosschain public key when using defined values", async () => {
const args = {
accountId: "omnitester.near",
networkId: NEAR_MAINNET_NETWORK_ID as NEAR_NETWORK_ID,
path: "account-1",
};

const response = await actionProvider.getCrossChainPublicKey(mockWallet, args);

const expectedMessagePart =
"Computed public key for account id omnitester.near, network near-mainnet and derivation path account-1 is";
const expectedPublicKey =
"0494da94af0a6b62a8d247e4a7915018cb5ce069bd2e81f90cf6b8351f8d34645ca78cfafdaeb2b1879f2501581500899de03a3b8b4f345278525206b21eaa8735";

expect(response).toEqual(`${expectedMessagePart} ${expectedPublicKey}`);
});
});

describe("signPayload", () => {
const big_r = MOCK_SIGNATURE.big_r.affine_point;
const big_s = MOCK_SIGNATURE.s.scalar;
const recoveryId = MOCK_SIGNATURE.recovery_id;

beforeEach(() => {
jest.spyOn(MpcContract.prototype, "getExperimentalSignatureDeposit").mockResolvedValue("1");
});

it("should sign a payload when passing non mandatory fields", async () => {
const args = {
path: undefined,
payload: "",
};

const response = await actionProvider.signPayload(mockWallet, args);

expect(response).toEqual(
`The signature result is big_r: ${big_r}, big_s: ${big_s} and recovery_id: ${recoveryId}`,
);
});

it("should sign a payload when passing all fields", async () => {
const args = {
path: "account-1",
payload: "470637f6dcc98931d6d22afa2b491c20caf0c3ba595d707606fe7915c30ef0a7",
};

const response = await actionProvider.signPayload(mockWallet, args);

expect(response).toEqual(
`The signature result is big_r: ${big_r}, big_s: ${big_s} and recovery_id: ${recoveryId}`,
);
});
});

afterEach(() => {
jest.clearAllMocks();
});
});
Loading