GithubHelp home page GithubHelp logo

near-ca's Introduction

NEAR Chain Abstraction Layer (NEAR-CA)

DISCLAIMER: This should only be used for educational purposes.

NEAR-CA is a TypeScript library designed to provide an abstraction layer for interacting with the NEAR blockchain, simplifying the process of performing transactions and managing accounts on both NEAR and Ethereum chains. This library is intended for use in server-side applications only.

Features

  • EVM Account Derivation from NEAR blockchain.
  • Transaction signing and sending on the Ethereum blockchain.
  • Key derivation functions for cryptographic operations.
  • Support for EIP-1559 transactions on Ethereum.
  • Wallet Connect intergration tools.

Contracts

Get Started

This project requires Node.js version 20.0.0 or higher. If you are using nvm, you can run nvm use to use the node version specified in .nvmrc.

To install dependencies and set up the project:

# Install dependencies
yarn
# Credentials
cp .env.example .env  <---- paste your Near credentials
# Send Eth. You'll need to fund your account first.
# More details in the 'Fund your account' part of this document
npx tsx examples/send-eth.ts

NEAR Credentials

Before using NEAR-CA, ensure you have the following environment variables set:

  • NEAR_ACCOUNT_ID: Your NEAR account identifier.
  • NEAR_ACCOUNT_PRIVATE_KEY: Your NEAR account private key.
  • NEAR_MULTICHAIN_CONTRACT: The NEAR contract that handles multichain operations.

Copy the .env.example file and add these values to the .env file.

For setting up a wallet, use the NEAR testnet wallet. The testnet wallet is different from the main wallet. For example, you can use the Mintbase Wallet.

Fund your account

Get your address

npx tsx examples/getEthAddress.ts

After getting your address fund it from one of your own wallets.

Examples

CLI

For Ethereum, you can derive addresses, create payloads for transactions, and send signed transactions.

For more detailed examples, see the Examples README.

Frontend

To install NEAR-CA in your project, run the following command:

yarn add near-ca

Example: Setup NearEthAdapter and Send ETH

Here's an example of how to set up the NearEthAdapter and send ETH:

import dotenv from "dotenv";
import {
  MultichainContract,
  NearEthAdapter,
  nearAccountFromKeyPair,
} from "near-ca";
import { KeyPair } from "near-api-js";

dotenv.config();
const { NEAR_ACCOUNT_ID, NEAR_ACCOUNT_PRIVATE_KEY } = process.env;

const account = await nearAccountFromKeyPair({
    accountId: NEAR_ACCOUNT_ID!,
    keyPair: KeyPair.fromString(NEAR_ACCOUNT_PRIVATE_KEY!),
    network: {
      networkId: "testnet",
      nodeUrl: "https://rpc.testnet.near.org",
    },
  });

const adapter = await NearEthAdapter.fromConfig({
  mpcContract: new MultichainContract(
    account,
    process.env.NEAR_MULTICHAIN_CONTRACT!
  ),
  // derivationPath: "ethereum,1",
});

await adapter.signAndSendTransaction({
  receiver: "0xdeADBeeF0000000000000000000000000b00B1e5",
  amount: 1n,
  chainId: 11_155_111,
  // Optional: Set nearGas (default is 250 TGAS, which sometimes might not be sufficient)
});

Other Examples

Each of the following scripts can be run with

npx tsx examples/*.ts
  1. (Basic) Send ETH
  2. WETH
  3. Transfer ERC721
  4. (Advanced) Buy NFT On Opensea

Configuration

Before using NEAR-CA, ensure you have the following environment variables set:

  • NEAR_ACCOUNT_ID: Your NEAR account identifier.
  • NEAR_ACCOUNT_PRIVATE_KEY: Your NEAR account private key.
  • NEAR_MULTICHAIN_CONTRACT: The NEAR contract that handles multichain operations.

Copy the .env.example file and place these values in .env

Steps to get your NEAR_ACCOUNT_ID and NEAR_ACCOUNT_PRIVATE_KEY:

  1. Create a mintbase wallet, super easy, here: https://wallet.mintbase.xyz/
  2. Your XYZ.testnet is your NEAR_ACCOUNT_ID.
  3. In mintbase, on the top right corner click on the gear (settings) icon.
  4. Go to "Security & Recovery" -> "Export Account".
  5. After the exporting is complete click on "Private Key" and copy it.
  6. Paste it to NEAR_ACCOUNT_PRIVATE_KEY in your .env file.

near-ca's People

Contributors

bh2smith avatar microchipgnu avatar poppyseeddev avatar lukisong82 avatar ppsimatikas avatar sgerodes avatar

Stargazers

manza avatar Nate Geier avatar Josh Ford avatar Timuçin YILMAZ avatar mav avatar  avatar Carlos Guimaraes avatar c0np4nn4 avatar Mike Purvis avatar

Watchers

Lucian avatar Nate Geier avatar  avatar  avatar Josh Ford avatar

near-ca's Issues

Integrate Multichain Gas Relayer

Near is building a multchain gas relayer service see example docs:
https://docs.near.org/build/chain-abstraction/multichain-gas-relayer/relayer-gas-example

However, getting setup is quite lengthy. We would ideally be able to integrate a route for users to opt in or out of relayer services (depending if they have a funded EVM account, or would prefer to pay all their tx/gas fees in Near).

There are many software components involved in running the relayer services that need to tweaks before this will work. Below are a list of relevant references:

Updated Instructions can be found in this GIST:
https://gist.github.com/bh2smith/0ed1dfb405e65277a148408c1442a229

Still having issues with relaying paymaster transactions and having them mined...

Example: 0xdc835a21b84f3c40b8819ca07ca6c442b4a5a630c74f77878d712dfae68f3334

Was posted but never mined...

(Minor) Update root pubkey in test

Looks like the root key was changed to:

secp256k1:4NfTiv3UsGahebgTaHyD9vF8KYKMBnfd6kh94mK6xv8fGBiJB8TBtFMP5WWXz6B89Ac1fbpzPwAvoyQebemHFwx3

Looks like this could get updated if you think it's important:

"ecp256k1:4HFcTSodRLVCGNVcGc4Mf2fwBBBxv9jxkGdiW2S2CA1y6UpVVRWKj6RX7d7TDt65k2Bj3w9FU4BGtt43ZvuhCnNt";

I found that updated on this page:

https://docs.near.org/build/chain-abstraction/chain-signatures#1-deriving-the-foreign-address

Handle Moar Wallet Connect Session Requests

At this moment we have handlers for

  • eth_sign
  • personal_sign
  • eth_sendTransaction
  • eth_signTypedData and
  • eth_signTypedData_v4

However there are many other session request types that could be supported...

Wallet Connect Docs: https://docs.walletconnect.com/web3wallet/wallet-usage#responding-to-session-requests

It is not yet clear how exactly we should respond to some of them or which are relevant for us.

Some unhandled request types that have been encountered so far as:

  • personal_expire
  • session_request_expire

A longer list of possibilities I am aware of, but have not encountered are:

            "eth_accounts",
            "eth_requestAccounts",
            "eth_sendRawTransaction",
            "eth_signTransaction",
            "eth_signTypedData_v3",
            "wallet_switchEthereumChain",
            "wallet_addEthereumChain",
            "wallet_getPermissions",
            "wallet_requestPermissions",
            "wallet_registerOnboarding",
            "wallet_watchAsset",
            "wallet_scanQRCode",
            "wallet_sendCalls",
            "wallet_getCallsStatus",
            "wallet_showCallsStatus",
            "wallet_getCapabilities",

WC: Approved Namespaces

Migrate the session approval code into here (so wallets using the library don't have to do it themselves). Not sure if this is the best idea, but at least for supported chains it would be better to have closer to the SUPPORTED_CHAINS constant:

    const approvedNamespaces = buildApprovedNamespaces({
      proposal: params,
      supportedNamespaces: {
        eip155: {
          chains: supportedChainIds.map((id) => `eip155:${id}`),
          methods: [
            "eth_accounts",
            "eth_requestAccounts",
            "eth_sendRawTransaction",
            "eth_sign",
            "eth_signTransaction",
            "eth_signTypedData",
            "eth_signTypedData_v3",
            "eth_signTypedData_v4",
            "eth_sendTransaction",
            "personal_sign",
            "wallet_switchEthereumChain",
            "wallet_addEthereumChain",
            "wallet_getPermissions",
            "wallet_requestPermissions",
            "wallet_registerOnboarding",
            "wallet_watchAsset",
            "wallet_scanQRCode",
            "wallet_sendCalls",
            "wallet_getCallsStatus",
            "wallet_showCallsStatus",
            "wallet_getCapabilities",
          ],
          events: [
            "chainChanged",
            "accountsChanged",
            "message",
            "disconnect",
            "connect",
          ],
          accounts: supportedChainIds.map(
            (id) => `eip155:${id}:${adapter.address}`
          ),
        },
      },
    });

Clean Up Tests and CI

As of #29, there are some "unit" tests that should be marked as integration tests and CI doesn't currently run the e2e tests at all (since the MPC contract is not returning signatures). We should rework this -- maybe only run e2e tests on merge to main.

Adapter: Deduplicate Signing Code

The NearEthAdapter class was initially configured and built to support Local Account (instantiated by Private Key). However, there are more general forms of accounts that people (like browser wallets) would prefer to use. Currently (with the recent introduction of Wallet Connect Support (cf #41 and #34) we have a bit of partially duplicated code between adapter.{sign, signMessage, signTypedData, recoverSignature} and the wallet connect handlers. WOuld be nice to make this more uniform, but might also require more generic handling of Accounts (found in https://github.com/Mintbase/near-ca/blob/main/src/chains/near.ts).

Note that browser wallets need to manage the near transactions on their end (i.e. calls to MPC contract).

Use Ethers Only!

This code base uses a messy mixture of both web3js and ethersjs. We should eliminate all of one (probably web3js). Maybe even both and use viem

Handle Wallet Connect `session_requests`

We should be able to transform any (or most) WC session_requests into Near MPC contract signature request payloads. Furthermore, we will also want to be able to decode the request payload to a human readable JSON document.

Example session_request Payloads:

personal_sign:

http://jsonblob.com/1237367682449137664

In case JSON blob expires
{
  "id": 1715076409273966,
  "topic": "21e63ecdd0960242a038a6836a75f3fe169b65090088146608fc25a2064a884b",
  "params": {
    "request": {
      "method": "personal_sign",
      "params": [
        "0x57656c636f6d6520746f204f70656e536561210a0a436c69636b20746f207369676e20696e20616e642061636365707420746865204f70656e536561205465726d73206f662053657276696365202868747470733a2f2f6f70656e7365612e696f2f746f732920616e64205072697661637920506f6c696379202868747470733a2f2f6f70656e7365612e696f2f70726976616379292e0a0a5468697320726571756573742077696c6c206e6f742074726967676572206120626c6f636b636861696e207472616e73616374696f6e206f7220636f737420616e792067617320666565732e0a0a57616c6c657420616464726573733a0a3078613631643938383534663761623235343032653364313235343861326539336130383063316639370a0a4e6f6e63653a0a30636331313237382d613533632d346336622d383965322d323231373435666230386439",
        "0xa61d98854f7ab25402e3d12548a2e93a080c1f97"
      ]
    },
    "chainId": "eip155:11155111"
  },
  "verifyContext": {
    "verified": {
      "verifyUrl": "https://verify.walletconnect.com",
      "validation": "VALID",
      "origin": "https://testnets.opensea.io",
      "isScam": false
    }
  }
}

eth_sendTransaction:

http://jsonblob.com/1237379262310113280

In case JSON Blob Expires
{
  "id": 1715084556718966,
  "topic": "687829fcccd97331aa3cdc7ca2a565c240f6ba8e1c4e6b6da2d3ec7e5f935cf1",
  "params": {
    "request": {
      "method": "eth_sendTransaction",
      "params": [
        {
          "gas": "0xd31d",
          "value": "0x16345785d8a0000",
          "from": "0xa61d98854f7ab25402e3d12548a2e93a080c1f97",
          "to": "0xfff9976782d46cc05630d1f6ebab18b2324d6b14",
          "data": "0xd0e30db0"
        }
      ]
    },
    "chainId": "eip155:11155111"
  },
  "verifyContext": {
    "verified": {
      "verifyUrl": "https://verify.walletconnect.com",
      "validation": "VALID",
      "origin": "https://swap.cow.fi",
      "isScam": false
    }
  }
}

EthSignTypedDataV4

http://jsonblob.com/1237385129717784576

In case JSON Blob Expires
{
  "id": 1715085981286145,
  "topic": "7d0a30c2f5b44650fbfcc90934530a0ceb468b0bbf41d18bceb9013588358737",
  "params": {
    "request": {
      "method": "eth_signTypedData_v4",
      "params": [
        "0xa61d98854f7ab25402e3d12548a2e93a080c1f97",
        "{\"types\":{\"Permit\":[{\"name\":\"owner\",\"type\":\"address\"},{\"name\":\"spender\",\"type\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\"},{\"name\":\"nonce\",\"type\":\"uint256\"},{\"name\":\"deadline\",\"type\":\"uint256\"}],\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}]},\"domain\":{\"name\":\"CoW Protocol Token\",\"version\":\"1\",\"chainId\":\"11155111\",\"verifyingContract\":\"0x0625afb445c3b6b7b929342a04a22599fd5dbb59\"},\"primaryType\":\"Permit\",\"message\":{\"owner\":\"0xa61d98854f7ab25402e3d12548a2e93a080c1f97\",\"spender\":\"0xc92e8bdf79f0507f65a392b0ab4667716bfe0110\",\"value\":\"115792089237316195423570985008687907853269984665640564039457584007913129639935\",\"nonce\":\"0\",\"deadline\":\"1872873982\"}}"
      ]
    },
    "chainId": "eip155:11155111"
  },
  "verifyContext": {
    "verified": {
      "verifyUrl": "https://verify.walletconnect.com",
      "validation": "VALID",
      "origin": "https://swap.cow.fi",
      "isScam": false
    }
  }
}

Other Things I've seen (possibly when session_request gets old...)

personal_expire
session_request_expire

TxStatus Types

Note that I think it is very strange to have to define types for RPC calls. There should be a library maintaining these types... like near-rpc or something. Note that the near docs do not specify a type for this response data (merely an example response with empty arrays in the any fields). Note that QuickNode does provide some vague docs on these types (but their example still returns an empty array -- i.e. not enough to declare types).

We have included a TODO in the code and commented out these two apparently useless fields.

  // input_data_ids: any[];
  // output_data_receivers: any[];

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.