Skip to content

Commit

Permalink
Prepare for Mainnet Deployment (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
bh2smith authored Aug 5, 2024
1 parent 1c97d54 commit b8939f3
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 66 deletions.
4 changes: 3 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
NEAR_ACCOUNT_ID=
NEAR_ACCOUNT_PRIVATE_KEY=
NEAR_MULTICHAIN_CONTRACT=v1.signer-prod.testnet

MPC_CONTRACT_ID=v1.signer-prod.testnet
NETWORK=testnet
2 changes: 1 addition & 1 deletion .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ jobs:
- name: E2E Test
run: yarn && yarn test e2e
env:
NEAR_MULTICHAIN_CONTRACT: v1.signer-dev.testnet
MPC_CONTRACT_ID: v1.signer-dev.testnet
NEAR_ACCOUNT_ID: ${{secrets.NEAR_ACCOUNT_ID}}
NEAR_ACCOUNT_PRIVATE_KEY: ${{secrets.NEAR_PK}}
41 changes: 13 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ npx tsx examples/send-eth.ts

### NEAR Credentials

Before using NEAR-CA, ensure you have the following environment variables set:
Before using NEAR-CA, ensure you have the following environment variables set in your `.env` file:

- `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.
- `MPC_CONTRACT_ID`: The NEAR contract that handles multichain operations.
- `NETWORK`: Either `near` or `testnet`.

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

Expand Down Expand Up @@ -77,31 +78,15 @@ Here's an example of how to set up the `NearEthAdapter` and send ETH:

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

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",
const adapter = await setupAdapter({
accountId: NEAR_ACCOUNT_ID!,
privateKey: NEAR_ACCOUNT_PRIVATE_KEY!,
mpcContractId: MPC_CONTRACT_ID!,
});

await adapter.signAndSendTransaction({
Expand Down Expand Up @@ -129,18 +114,18 @@ npx tsx examples/*.ts

## Configuration

Before using NEAR-CA, ensure you have the following environment variables set:
Before using NEAR-CA, ensure you have the following environment variables set in your `.env` file:

- `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`
- `MPC_CONTRACT_ID`: The NEAR contract that handles multichain operations.
- `NETWORK`: Either `near` or `testnet`.

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

Steps to get your `NEAR_ACCOUNT_ID` and `NEAR_ACCOUNT_PRIVATE_KEY`:

1. Create a mintbase wallet, super easy, here: https://wallet.mintbase.xyz/
1. Create a mintbase wallet, super easy, here: https://wallet.bitte.ai/
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".
Expand Down
33 changes: 12 additions & 21 deletions examples/setup.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,22 @@
import dotenv from "dotenv";
import {
MultichainContract,
NearEthAdapter,
nearAccountFromKeyPair,
} from "../src";
import { KeyPair } from "near-api-js";
import { NearEthAdapter, setupAdapter } from "../src";

// This is Sepolia, but can be replaced with nearly any EVM network.
export const SEPOLIA_CHAIN_ID = 11_155_111;
const TESTNET_CONFIG = {
networkId: "testnet",
nodeUrl: "https://rpc.testnet.near.org",
};

export async function setupNearEthAdapter(): Promise<NearEthAdapter> {
dotenv.config();
const account = await nearAccountFromKeyPair({
keyPair: KeyPair.fromString(process.env.NEAR_ACCOUNT_PRIVATE_KEY!),
accountId: process.env.NEAR_ACCOUNT_ID!,
network: TESTNET_CONFIG,
});
return NearEthAdapter.fromConfig({
mpcContract: new MultichainContract(
account,
process.env.NEAR_MULTICHAIN_CONTRACT!
),
// derivationPath: "ethereum,1",
const { NEAR_ACCOUNT_ID, NEAR_ACCOUNT_PRIVATE_KEY, MPC_CONTRACT_ID } =
process.env;
if (!(NEAR_ACCOUNT_ID && NEAR_ACCOUNT_PRIVATE_KEY && MPC_CONTRACT_ID)) {
throw new Error(
"One of env vars NEAR_ACCOUNT_ID, NEAR_ACCOUNT_PRIVATE_KEY, or MPC_CONTRACT_ID is undefined"
);
}
return setupAdapter({
accountId: NEAR_ACCOUNT_ID,
privateKey: NEAR_ACCOUNT_PRIVATE_KEY,
mpcContractId: MPC_CONTRACT_ID,
});
}

Expand Down
58 changes: 48 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { KeyPair } from "near-api-js";
import { Account, KeyPair } from "near-api-js";
import { NearEthAdapter } from "./chains/ethereum";
import { MultichainContract } from "./mpcContract";
import { NearConfig } from "near-api-js/lib/near";
Expand All @@ -14,21 +14,59 @@ export * from "./utils/transaction";

interface SetupConfig {
accountId: string;
network: NearConfig;
mpcContractId: string;
network?: NearConfig;
privateKey?: string;
mpcContractId?: string;
derivationPath?: string;
}

type NetworkId = "near" | "testnet";

function getNetworkId(accountId: string): NetworkId {
const networkId = accountId.split(".").pop() || "";
if (!["near", "testnet"].includes(networkId)) {
throw new Error(`Invalid network extracted from accountId ${accountId}`);
}
return networkId as NetworkId;
}

export function configFromNetworkId(networkId: NetworkId): NearConfig {
const network = networkId === "near" ? "mainnet" : "testnet";
return {
networkId,
nodeUrl: `https://rpc.${network}.near.org`,
};
}

export async function setupAdapter(args: SetupConfig): Promise<NearEthAdapter> {
const { privateKey, mpcContractId, derivationPath } = args;
const account = await createNearAccount(
args.accountId,
args.network,
privateKey ? KeyPair.fromString(privateKey) : undefined
);
const {
accountId,
privateKey,
mpcContractId,
derivationPath = "ethereum,1",
} = args;
// Load near config from provided accountId if not provided
const accountNetwork = getNetworkId(accountId);
const config = args.network ?? configFromNetworkId(accountNetwork);
if (accountNetwork !== config.networkId) {
throw new Error(
`The accountId ${accountId} does not match the networkId ${config.networkId}. Please ensure that your accountId is correct and corresponds to the intended network.`
);
}

let account: Account;
try {
account = await createNearAccount(
accountId,
config,
privateKey ? KeyPair.fromString(privateKey) : undefined
);
} catch (error: unknown) {
console.error(`Failed to create NEAR account: ${error}`);
throw error;
}
return NearEthAdapter.fromConfig({
mpcContract: new MultichainContract(account, mpcContractId),
derivationPath: derivationPath || "ethereum,1",
derivationPath: derivationPath,
});
}
4 changes: 1 addition & 3 deletions src/mpcContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import { TGAS, ONE_YOCTO } from "./chains/near";
import { MPCSignature, FunctionCallTransaction, SignArgs } from "./types/types";
import { transformSignature } from "./utils/signature";

const DEFAULT_MPC_CONTRACT = "v1.signer-prod.testnet";

/// Near Contract Type for change methods
export interface ChangeMethodArgs<T> {
/// Change method function agruments.
Expand Down Expand Up @@ -41,7 +39,7 @@ export class MultichainContract {
contract: MultichainContractInterface;
connectedAccount: Account;

constructor(account: Account, contractId: string = DEFAULT_MPC_CONTRACT) {
constructor(account: Account, contractId: string) {
this.connectedAccount = account;

this.contract = new Contract(account.connection, contractId, {
Expand Down
30 changes: 28 additions & 2 deletions tests/unit/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { setupAdapter } from "../../src/";
import { configFromNetworkId, setupAdapter } from "../../src/";
describe("index", () => {
it("setupAdapter", async () => {
const adapter = await setupAdapter({
Expand All @@ -13,7 +13,7 @@ describe("index", () => {
expect(adapter.address).toBe("0x5898502fc8577c5a0ae0c6984bb33c394c11a0a5");
});

it("setupAdapter fails", async () => {
it("setupAdapter with private Key", async () => {
const adapter = await setupAdapter({
accountId: "your-account.testnet",
network: {
Expand All @@ -28,4 +28,30 @@ describe("index", () => {
});
expect(adapter.address).toBe("0x5898502fc8577c5a0ae0c6984bb33c394c11a0a5");
});

it("setupAdapter fails", async () => {
const config = {
accountId: "your-account.testnet",
network: {
networkId: "near",
nodeUrl: "https://rpc.mainnet.near.org",
},
mpcContractId: "v1.signer-prod.testnet",
};
await expect(() => setupAdapter(config)).rejects.toThrow(
"The accountId your-account.testnet does not match the networkId near."
);
});

it("configFromNetworkId", async () => {
expect(configFromNetworkId("near")).toStrictEqual({
networkId: "near",
nodeUrl: "https://rpc.mainnet.near.org",
});

expect(configFromNetworkId("testnet")).toStrictEqual({
networkId: "testnet",
nodeUrl: "https://rpc.testnet.near.org",
});
});
});

0 comments on commit b8939f3

Please sign in to comment.