Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
D4mph1r committed Sep 17, 2024
2 parents 9f73b92 + 40a2afd commit 62b083e
Show file tree
Hide file tree
Showing 13 changed files with 156 additions and 32 deletions.
4 changes: 3 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# The API Key for Ton RPC
TON_API_KEY=
# The PORT to serve HTTP Requests
SERVER_PORT=
SERVER_PORT=
# Nearblocks API Key
NEARBLOCKS_API_KEY=
16 changes: 14 additions & 2 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,18 @@ export const bridgeTestChains = [
nativeCoinSymbol: "ICP",
rpcURL: "https://tools.xp.network/",
},
// {
// chain: "NEAR",
// chainType: "near",
// contractAddress: "xp-bridge-test.testnet",
// decimals: 24,
// intialFund: "100000000000000000000000",
// lastBlock: 960126871,
// nativeCoinSymbol: "NEAR",
// nearBlocksUrl: "https://api-testnet.nearblocks.io/v1/",
// networkId: "testnet",
// rpcURL: "https://archival-rpc.testnet.near.org",
// },
] as const satisfies TChain[];

export const storageTestnetConfig: IEvmChainConfig = {
Expand Down Expand Up @@ -217,5 +229,5 @@ export const prodBridgeConfig: IBridgeConfig = {
};

export type TSupportedChainsConfig = (typeof bridgeTestChains)[number];
export type TSupportedChains = TSupportedChainsConfig["chain"];
export type TSupportedChainTypes = TSupportedChainsConfig["chainType"];
export type TSupportedChains = TChain["chain"];
export type TSupportedChainTypes = TChain["chainType"];
72 changes: 72 additions & 0 deletions src/deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,17 @@ import { Ed25519KeyIdentity } from "@dfinity/identity";
import type { EntityManager } from "@mikro-orm/sqlite";
import { Mutex } from "async-mutex";
import axios, { type AxiosInstance } from "axios";
import {
KeyPair,
InMemorySigner as NearInMemorySigner,
connect,
keyStores,
} from "near-api-js";
import { ERC20Staking__factory } from "./contractsTypes/evm";
import { cosmWasmHandler } from "./handler/cosmos";
import { evmStakingHandler } from "./handler/evm/stakingHandler";
import { icpHandler } from "./handler/icp";
import { nearHandler } from "./handler/near";
import type { LogInstance, THandler } from "./handler/types";
import MikroOrmConfig from "./mikro-orm.config";
import { Block } from "./persistence/entities/block";
Expand All @@ -46,6 +53,8 @@ import type {
IICPWallet,
IMultiversXChainConfig,
IMultiversXWallet,
INearChainConfig,
INearWallet,
ISecretChainConfig,
ISecretWallet,
IStakingConfig,
Expand Down Expand Up @@ -337,6 +346,53 @@ export async function configMultiversXHandler(
});
}

export async function configNearHandler(
conf: INearChainConfig,
storage: BridgeStorage,
em: EntityManager,
nearWallet: INearWallet,
serverLinkHandler: AxiosInstance | undefined,
nearLogger: LogInstance,
staking: ERC20Staking,
validatorAddress: string,
) {
const near = await connect({
networkId: conf.networkId,
nodeUrl: conf.rpcURL,
});

const ks = new keyStores.InMemoryKeyStore();

ks.setKey(
conf.networkId,
nearWallet.accountId,
KeyPair.fromString(nearWallet.secretKey as never),
);

return nearHandler({
near,
address: nearWallet.accountId,
bridge: conf.contractAddress,
chainIdent: "NEAR",
chainType: "near",
decimals: 24,
em: em.fork(),
initialFunds: BigInt(conf.intialFund),
lastBlock_: conf.lastBlock,
logger: nearLogger,
// biome-ignore lint/style/noNonNullAssertion: <explanation>
nearBlocksApiKey: process.env.nearBlocksApiKey!,
nearBlocksUrl: conf.nearBlocksUrl,
networkId: conf.networkId,
storage,
privateKey: nearWallet.secretKey,
signer: new NearInMemorySigner(ks),
serverLinkHandler: serverLinkHandler,
validatorAddress,
staking,
});
}

export async function configTonHandler(
conf: ITonChainConfig,
storage: BridgeStorage,
Expand Down Expand Up @@ -482,6 +538,21 @@ export async function configDeps(
)
: undefined;

const nearc = config.bridgeChains.find((e) => e.chainType === "near");

const near = nearc
? await configNearHandler(
nearc,
storage,
em.fork(),
secrets.nearWallet,
serverLinkHandler,
logger.getSubLogger({ name: "NEAR" }),
staking,
secrets.evmWallet.address,
)
: undefined;

return {
storage,
em,
Expand Down Expand Up @@ -548,6 +619,7 @@ export async function configDeps(
mx,
ton,
icp,
near,
].filter((e) => e !== undefined) as THandler[],
};
}
1 change: 1 addition & 0 deletions src/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ config();

export const Env = z.object({
TON_API_KEY: z.string().optional(),
NEARBLOCKS_API_KEY: z.string().optional(),
SERVER_PORT: z.string().optional(),
SERVER_LINK: z.string().optional(),
NETWORK: z.union([z.literal("testnet"), z.literal("mainnet"), z.undefined()]),
Expand Down
4 changes: 2 additions & 2 deletions src/handler/near/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ export async function nearHandler({
}: NearHandlerParams): Promise<THandler> {
const bc = new Contract(near.connection, bridge, {
changeMethods: [],
viewMethods: [],
useLocalViewExecution: true,
viewMethods: ["validator", "validator_count"],
useLocalViewExecution: false,
});
const nearBlocksApi = axios.create({
baseURL: nearBlocksUrl,
Expand Down
2 changes: 1 addition & 1 deletion src/handler/near/utils/addSelfAsValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default async function addSelfAsValidator(
}
try {
async function getStakingSignatureCount() {
return Number(await bridge.get_validator_count());
return Number(await bridge.validator_count());
}
let validatorsCount = await getStakingSignatureCount();
let signatureCount = Number(
Expand Down
7 changes: 4 additions & 3 deletions src/handler/near/utils/generateWallet.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { KeyPair } from "near-api-js";
import type { KeyPairEd25519 } from "near-api-js/lib/utils";

export default function nearGw() {
export default function generateWallet() {
const kp = KeyPair.fromRandom("ed25519") as KeyPairEd25519;
const publicKey = kp.getPublicKey().data;
const privateKey = kp.secretKey;

return Promise.resolve({
publicKey: Buffer.from(publicKey).toString("hex"),
privateKey: Buffer.from(privateKey).toString("hex"),
publicKey: publicKey.toString(),
secretKey: privateKey,
accountId: Buffer.from(kp.getPublicKey().data).toString("hex"),
});
}
29 changes: 19 additions & 10 deletions src/handler/near/utils/listenForLockEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,62 +19,71 @@ export default async function listenForLockEvents(
em: EntityManager,
logger: LogInstance,
) {
const lastBlock = lastBlock_;
let lastBlock = lastBlock_;
while (true)
try {
const response = await nearBlocksApi.get<{
cursor: number;
cursor?: number;
txns: unknown[];
}>(`/account/${bridge}/txns`);
if (!response.data.cursor) {
logger.trace(`0 Txns Since: ${lastBlock}. Awaiting 10s`);
await setTimeout(10000);
continue;
}

if (response.data.cursor <= lastBlock) {
if (response.data.cursor < lastBlock) {
logger.trace(`0 Txns Since: ${lastBlock}. Awaiting 10s`);
await setTimeout(10000);
continue;
}

const { data } = await nearBlocksApi.get<{
txns: Transaction[];
}>(`/account/${bridge}/txn?method=lock_nft&cursor=${lastBlock}`);
}>(`/account/${bridge}/txns?cursor=${lastBlock}`);
const newCursor = data.txns[0].id;

for (const tx of data.txns) {
const txn = await near.connection.provider.txStatusReceipts(
tx.transaction_hash,
bridge,
"FINAL",
"NONE",
);
//@ts-ignore
if (!("SuccessValue" in txn.status)) {
continue;
}
const log = txn.receipts_outcome
.flatMap((e) => e.outcome.logs)
.filter((e) => e.includes("locked"))[0];
if (!log) continue;
const parsed = JSON.parse(log).data;

cb(
await cb(
await builder.nftLocked(
parsed.token_id,
parsed.destination_chain,
parsed.destionation_address,
parsed.destination_user_address,
parsed.source_nft_contract_address,
parsed.token_amount,
"singular",
parsed.source_chain,
tx.transaction_hash,
"NEAR",
"",
parsed.metadata_uri,
undefined,
),
);
}

lastBlock = Number(newCursor);
await em.upsert(Block, {
chain: CHAIN_IDENT,
contractAddress: bridge,
lastBlock: Number(newCursor),
});
await em.flush();
} catch (e) {
logger.error(`${e} while listening for events. Sleeping for 10 seconds`);
logger.error("Error while listening for events", e);
await setTimeout(10000);
}
}
2 changes: 1 addition & 1 deletion src/handler/near/utils/nftData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default async function nftData(
symbol: collection_metadata.symbol,
metadata: nft_metadata.metadata.media || nft_metadata.metadata.extra,
royalty: BigInt(
Object.values(nft_metadata.metadata.royalty).reduce(
Object.values(nft_metadata.metadata.royalty || { a: 0 }).reduce(
//@ts-ignore ik it works
(e: number, c: number) => c + e,
) as number,
Expand Down
11 changes: 8 additions & 3 deletions src/handler/near/utils/selfIsValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ export default async function selfIsValidator(
bridge: Contract & Record<string, CallableFunction>,
publicKeyInHex: string,
) {
const validator = await bridge.validator({ public_key: publicKeyInHex });
if (!validator) return false;
return true;
try {
const validator = await bridge.validator({ public_key: publicKeyInHex });
if (!validator) return false;
return true;
} catch (e) {
console.log(e);
return false;
}
}
16 changes: 8 additions & 8 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ async function main() {
stylePrettyLogs: true,
});
await configureValidator(logger);

let config: IBridgeConfig = prodBridgeConfig;

const network = process.env.NETWORK;
if (network === "testnet") {
logger.info("Starting up testnet");
config = testnetBridgeConfig;
}
await syncWallets(logger);

const secrets: IGeneratedWallets = JSON.parse(
Expand All @@ -27,14 +35,6 @@ async function main() {
process.exit(0);
}

let config: IBridgeConfig = prodBridgeConfig;

const network = process.env.NETWORK;
if (network === "testnet") {
logger.info("Starting up testnet");
config = testnetBridgeConfig;
}

const deps = await configDeps(config, secrets, logger);
if (process.env.SERVER_PORT) {
const server = await configureRouter(deps.em.fork());
Expand Down
19 changes: 18 additions & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ type ITonWallet = {
secretKey: string;
};

type INearWallet = {
publicKey: string;
secretKey: string;
accountId: string;
};

type IEvmWallet = {
address: string;
privateKey: string;
Expand Down Expand Up @@ -68,6 +74,7 @@ type IGeneratedWallets = {
secretWallet: ISecretWallet;
tezosWallet: ITezosWallet;
icpWallet: IICPWallet;
nearWallet: INearWallet;
};

type IConfigAndWallets = {
Expand Down Expand Up @@ -110,6 +117,13 @@ type ITonChainConfig = {
rpcURL: string;
} & IChainConfig;

type INearChainConfig = {
chainType: "near";
rpcURL: string;
networkId: "testnet" | "mainnet";
nearBlocksUrl: string;
} & IChainConfig;

type ITezosChainConfig = {
chainType: "tezos";
restApiURL: string;
Expand Down Expand Up @@ -151,7 +165,8 @@ type TChain =
| ITezosChainConfig
| IHederaChainConfig
| ICosmWasmChainConfig
| IICPChainConfig;
| IICPChainConfig
| INearChainConfig;

type IBridgeConfig = {
bridgeChains: TChain[];
Expand Down Expand Up @@ -184,5 +199,7 @@ export type {
ITezosWallet,
ITonChainConfig,
ITonWallet,
INearChainConfig,
INearWallet,
TChain,
};
Loading

0 comments on commit 62b083e

Please sign in to comment.