![Oracle Drags Its Feet in the JavaScript Trademark Dispute](https://cdn.sanity.io/images/cgdhsj6q/production/919c3b22c24f93884c548d60cbb338e819ff2435-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Oracle Drags Its Feet in the JavaScript Trademark Dispute
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
@near-eth/client
Advanced tools
@near-eth/client
– the Rainbow Bridge client library 🌈🌉Do you want to allow your users to send assets between Ethereum & NEAR & Aurora over the Rainbow Bridge?
Do you want to easily send assets between the two blockchains using your command line?
Did you build a custom Rainbow Bridge Connector and now you want to figure out how to build a client library for it, so other people can actually use it?
If you answered "Yes" to any of the above questions, this is the library for you! (Ok, ok, the CLI interface is not yet supported!)
Read on to find out how to:
To contribute to this library, see github.com/aurora-is-near/rainbow-bridge-client.
Let's say you want to allow users to send ERC20 tokens from Ethereum to NEAR, where they'll become NEP141 tokens.
You'll need to add two dependencies to your app:
npm install --save @near-eth/client @near-eth/nep141-erc20
Or, if using yarn:
yarn add @near-eth/client @near-eth/nep141-erc20
@near-eth/nep141-erc20
?The Rainbow Bridge between Ethereum and NEAR has many pieces. One piece is Connector contracts. The connector code for converting ERC20 tokens in Ethereum to NEP141 tokens in NEAR lives at github.com/aurora-is-near/rainbow-token-connector.
The code for using a given connector from an app has its own library. The one for the connector above is @near-eth/nep141-erc20
.
Anyone can make connector contracts, and anyone can make client libraries for these contracts. If they follow the format of @near-eth/nep141-erc20
, these client libraries will work automatically with the core Rainbow Bridge transfer library at @near-eth/client
.
Generally, each connector client library, like @near-eth/nep141-erc20
, will export four main interfaces, which can be used to:
For @near-eth/nep141-erc20
, these main exports are:
naturalErc20
– example: go from DAI (a popular ERC20 token) to nDAIbridgedNep141
– example: convert nDAI back to DAInaturalNep141
– example: go from a natural NEAR token, such as BNNA Tokens in berryclub.io, to eBNNA in EthereumbridgedErc20
– example: convert eBNNA back to BNNAYou can have multiple connector libraries in your app, some which may be maintained by NEAR and are in the @near-eth
organization, and some which are not. An example package.json
might end up looking something like:
"dependencies": {
"@near-eth/client": "*",
"@near-eth/nep141-erc20": "*",
"@near-eth/nep4-erc721": "*",
"rainbow-bridge-erc20-with-rebase-and-nep21": "*",
}
(Note: @near-eth/nep4-erc721
and rainbow-bridge-erc20-with-rebase-and-nep21
do NOT currently exist, and are only shown to illustrate how this could work. As an aside, the current ERC20 connector does NOT support tokens which use the rebase
feature like AMPL & BASE, which is why a hypothetical community-contributed "erc20-with-rebase" connector library is shown.)
These parameters are specific to the bridge being used.
import { setBridgeParams } from '@near-eth/client'
setBridgeParams({
nearEventRelayerMargin: 10, // 10 blocks margin for the Event relayer to finalize the transfer
sendToNearSyncInterval: 20000, // check light client sync every 20sec
sendToEthereumSyncInterval: 60000, // check light client sync every 60sec
ethChainId: 1, // mainnet
erc20Abi: process.env.ethErc20AbiText, // Standard ERC-20 ABI
erc20LockerAddress: '0x23ddd3e3692d1861ed57ede224608875809e127f',
erc20LockerAbi: process.env.ethLockerAbiText,
nep141Factory: 'factory.bridge.near',
ethClientAddress: '0x0151568af92125fb289f1dd81d9d8f7484efc362',
ethClientAbi: process.env.ethNearOnEthClientAbiText,
nearClientAccount: 'client.bridge.near'
})
A full transfer will make multiple calls to both the NEAR & Ethereum blockchains, and you'll need to make sure the user has an account/wallet on both chains.
setNearConnection
Your app needs to call setNearConnection
and pass it a WalletConnection
instance from near-api-js
. Example:
import { keyStores, Near, WalletConnection } from 'near-api-js'
import { setNearConnection } from '@near-eth/client'
window.nearConnection = new WalletConnection(
new Near({
keyStore: new keyStores.BrowserLocalStorageKeyStore(),
networkId: process.env.nearNetworkId,
nodeUrl: process.env.nearNodeUrl,
helperUrl: process.env.nearHelperUrl,
walletUrl: process.env.nearWalletUrl
})
)
setNearConnection(window.nearConnection)
If you don't know what to put for the settings passed to new Near
, check out the cheat sheet.
requestSignIn()
Additionally, you'll probably want to verify that a user has a NEAR account before they get started. Given a "Sign in with NEAR" button:
<button id="authNear">Sign in with NEAR</button>
You can add this handler:
document.querySelector('#authNear').onclick = () => {
window.nearConnection.requestSignIn()
}
Your app needs to call setEthProvider
. Given a "Connect to Ethereum" button:
<button id="authEthereum">Connect to Ethereum</button>
You can use web3modal to add this handler:
import Web3Modal from 'web3modal'
import { setEthProvider, setSignerProvider } from '@near-eth/client'
import { ethers } from 'ethers'
// Provider used for querying Ethereum data (transaction status, sync status ...)
setEthProvider(new ethers.providers.InfuraProvider('mainnet', INFURA_ID))
const web3Modal = new Web3Modal({ cacheProvider: true })
async function loadWeb3Modal () {
window.ethProvider = await web3Modal.connect()
// Provider used for signing transactions (MetaMask, WalletConnect...)
setSignerProvider(new ethers.providers.Web3Provider(window.ethProvider, 'any'))
}
document.querySelector('#authEthereum').onclick = loadWeb3Modal
// on page load, check if user has already connected
if (web3Modal.cachedProvider) loadWeb3Modal()
Great, now your user is authenticated with both NEAR & Ethereum. Now let's say you have a form.
<form id="sendErc20ToNear">
<input id="erc20Address" />
<input id="amount" />
</form>
Here's some JavaScript to make this work:
import { naturalErc20 } from '@near-eth/nep141-erc20'
document.querySelector('#sendErc20ToNear').onsubmit = async e => {
e.preventDefault()
const [sender] = await window.ethProvider.request({method: 'eth_requestAccounts'})
const recipient = window.nearConnection.getAccountId()
const { erc20Address, amount } = e.target.elements
// The ERC-20 should be approved before tokens can be transfered to the bridge.
// naturalErc20.approve() and naturalErc20.checkApprove() are available,
// but developpers is free to set approval any way they like depending on UX.
naturalErc20.sendToNear({
erc20Address: erc20Address.value,
amount: amount.value
recipient,
})
}
For the rest of the lifetime of the transfer you just initiated, you will use
exports from @near-eth/client
, rather than the connector-specific library.
Let's say you want to list in-progress transfers in this ol
:
<ol id="transfers-go-here"></ol>
Here's code to render the list of transfers:
import { get, onChange } from '@near-eth/client'
function renderTransfers () {
const transfers = get({ filter: t => t.status === 'in-progress' })
document.querySelector('#transfers-go-here').innerHTML =
transfers.map(renderTransfer).join('')
}
onChange(renderTransfers)
renderTransfers()
If using React, you'd want something like:
import React, { useState, useEffect } from 'react';
import { get, onChange } from '@near-eth/client'
// See below for an example Transfer component
import Transfer from './Transfer'
// You can write a simple custom hook to suit your needs;
// see https://reactjs.org/docs/hooks-custom.html
function useTransfers(filter) {
const [transfers, setTransfers] = useState([])
useEffect(() => {
get({ filter }).then(setTransfers)
onChange(() => get({ filter }).then(setTransfers))
}, [])
return transfers
}
export function Transfers () {
const transfers = useTransfers(t => t.status === 'in-progress')
return (
<ol>
{transfers.map(transfer =>
<Transfer key={transfer.id} transfer={transfer} />
)}
</ol>
)
}
And here's what renderTransfer
might look like, using vanilla JS:
import { act, decorate } from '@near-eth/client'
function renderTransfer (transfer) {
// "decorate" transfer with realtime info & other data that would bloat localStorage
transfer = decorate(transfer, { locale: 'en_US' })
return `
<li class="transfer" id="${transfer.id}">
${transfer.amount}
${transfer.sourceTokenName} from
${transfer.sender} to
${transfer.recipient}
${!transfer.callToAction ? '' : `
<button class="act-on-transfer">
${transfer.callToAction}
</button>
`}
</li>
`
}
// Vanilla JS shenanigans: add a click handler to `body`, because transfers are
// rendered with JS and therefore unavailable for adding click handlers at
// initial page load.
// This will be easier if you use React or something 😄
document.querySelector('body').addEventListener('click', event => {
const callToAction = event.target.closest('.act-on-transfer')
if (callToAction) {
const transferId = callToAction.closest('.transfer').id
act(transferId)
}
})
And an equivalent Transfer
component, if using React:
import { act, decorate } from '@near-eth/client'
export function Transfer (transfer) {
// "decorate" transfer with realtime info & other data that would bloat localStorage
transfer = decorate(transfer, { locale: 'en_US' })
return (
<li>
{transfer.amount}
{transfer.sourceTokenName} from
{transfer.sender} to
{transfer.recipient}
{transfer.callToAction &&
<button onClick={() => act(transfer.id)}>
{transfer.callToAction}
</button>
}
</li>
)
}
Here's some docs about act, and two example connector-specific behaviors. Here's some docs about decorate. Here's the attributes for two kinds of raw transfers, prior to being decorated.
Wait for the Ethereum & NEAR authentications described in Step 1 to complete, then call this:
import { checkStatusAll } from '@near-eth/client'
checkStatusAll({ loop: 15000 })
What's it do?
This library is designed to be non-blocking, which means a user can start multiple transfers at once, and the library won't pause to wait for blocks to be mined in Ethereum, finalized in NEAR, or synced between the two.
This means that with only the code from Steps 1-3, nothing else will happen. A user will have sent an initial transaction to the Ethereum or NEAR blockchain, but neither your app nor any other service will ever check to see if that transaction completes successfully. Nor will any app or service prompt the user to complete the next transaction in the process (any transfer requires multiple steps & multiple on-chain transactions to complete).
checkStatusAll
will loop as frequently as you tell it to. It will check to
see if transactions have been mined, synced, or finalized, and update transfers
in localStorage accordingly. When transfers are updated, the onChange
function in Step 3 will trigger a UI update.
That's it! You successfully integrated cross-chain transfers into your app in just four steps. 🌈🌉🎉
To make it more beautiful, check out the API docs and example code (implemented in vanilla/no-framework JavaScript).
Transfer statuses are recorded in the browser local storage so the information will be lost when users change browser or delete storage.
It is possible to find an account's transfer history using findAllTransfers
or a combination of findAllTransactions
and recover
for more flexibility.
Ethereum -> NEAR transfers are found using bridge token lock/burn events queried at an Ethereum archive node.
NEAR -> Ethereum transfers are found using the NEAR indexer.
import { findAllTransactions, recover } from '@near-eth/nep141-erc20/dist/bridged-nep141/sendToEthereum'
const transactions = await findAllTransactions({
fromBlock: process.env.nearAutoSyncFromBlock,
toBlock: 'latest',
sender: userAccountId,
erc20Address,
callIndexer: async (query) => await wampSession.call(`com.nearprotocol.mainnet.explorer.select:INDEXER_BACKEND`, [query])
})
// Using `findAllTransactions` enables filtering transfers already completed to optimise the number of queries.
// `findAllTransfers` will query and build proofs for all transfers from scratch.
const transfers = await Promise.all(transactions.map(async tx => await recover(tx)))
The user of this library should specify the callIndexer
callback with the preferred way of connecting to NEAR Indexer.
Browsers should connect to a backend providing Indexer data or can use a WAMP session to query the indexer via NEAR Explorer backend. Node.js applications can connect directly to the Indexer with Sequelize.
import {
nep141Erc20,
nearEther,
auroraErc20,
auroraEther,
auroraNep141,
} from '@near-eth/rainbow'
from Ethereum | to NEAR | to Aurora |
---|---|---|
ERC-20 | nep141Erc20/naturalErc20/sendToNear | auroraErc20/naturalErc20/sendToAurora |
nep141Erc20/bridgedErc20/sendToNear | auroraErc20/bridgedErc20/sendToAurora (TODO) | |
ETH | nearEther/naturalETH/sendToNear | auroraEther/naturalEther/sendToAurora |
NEAR | nearEther.bridgedNEAR.sendToNear | (TODO) |
ERC-721 | (TODO) | (TODO) |
from NEAR | to Ethereum | to Aurora |
---|---|---|
NEP-141 | nep141Erc20/bridgedNep141/sendToEthereum | auroraNep141/naturalNep141/sendToAurora |
nep141Erc20/naturalNep141/sendToEthereum | auroraNep141/bridgedNep141/sendToAurora (TODO) | |
ETH | nearEther/bridgedETH/sendToEthereum | auroraNep141/naturalNep141/sendToAurora |
NEAR | nearEther/naturalNEAR/sendToEthereum | auroraNep141/naturalNep141/wrapAndSendNearToAurora |
ERC-721 | (TODO) | (TODO) |
from Aurora | to Ethereum | to NEAR |
---|---|---|
ERC-20 | auroraErc20/bridgedErc20/sendToEthereum | auroraNep141/bridgedErc20/sendToNear * |
auroraErc20/naturalErc20/sendToEthereum (TODO) | auroraNep141/naturalErc20/sendToNear (TODO) * | |
ETH | auroraEther/bridgedEther/sendToEthereum | auroraNep141/bridgedEther/sendToNear * |
NEAR | auroraErc20/wNEAR/sendToEthereum | auroraNep141/bridgedErc20/sendToNear * |
ERC-721 | (TODO) | (TODO) |
* WARNING: The recipient of transfers from Aurora to NEAR must have paid NEAR storage fees otherwise tokens may be lost.
@near-eth/nep141-erc20
librarygetTransferType
lookup logic in @near-eth/client
import { setBridgeParams } from '@near-eth/client'
setBridgeParams({
nearEventRelayerMargin: 10, // blocks
sendToNearSyncInterval: 60000, // check light client sync interval (ms)
sendToEthereumSyncInterval: 60000, // check light client sync interval (ms)
maxFindEthProofInterval: 600000, // check finalization status max interval (ms)
ethChainId: 1,
auroraChainId: 1313161554,
// https://github.com/aurora-is-near/rainbow-bridge-frontend/blob/master/abi/erc20.abi
erc20Abi: process.env.erc20Abi,
// https://github.com/aurora-is-near/aurora-engine/blob/master/etc/eth-contracts/contracts/EvmErc20.sol
// https://github.com/aurora-is-near/rainbow-bridge-frontend/blob/aurora-near/abi/auroraErc20.abi
auroraErc20Abi: process.env.auroraErc20Abi,
// https://github.com/aurora-is-near/rainbow-token-connector
erc20LockerAddress: '0x23Ddd3e3692d1861Ed57EDE224608875809e127f',
// https://github.com/aurora-is-near/rainbow-bridge-frontend/blob/master/abi/ERC20Locker.full.abi
erc20LockerAbi: process.env.erc20LockerAbi,
nep141Factory: 'factory.bridge.near',
// https://github.com/aurora-is-near/eth-connector/tree/master/eth-custodian
etherCustodianAddress: '0x6BFaD42cFC4EfC96f529D786D643Ff4A8B89FA52',
// https://github.com/aurora-is-near/rainbow-bridge-frontend/blob/master/abi/etherCustodian.full.abi
etherCustodianAbi: process.env.etherCustodianAbi,
auroraEvmAccount: 'aurora',
auroraRelayerAccount: 'relay.aurora',
etherExitToEthereumPrecompile: '0xb0bD02F6a392aF548bDf1CfAeE5dFa0EefcC8EaB',
etherExitToNearPrecompile: '0xE9217BC70B7ED1f598ddD3199e80b093fA71124F',
// https://github.com/aurora-is-near/rainbow-bridge-frontend/blob/master/abi/nearOnEthClient.abi
ethClientAddress: '0x3fefc5a4b1c02f21cbc8d3613643ba0635b9a873',
// https://github.com/aurora-is-near/rainbow-bridge/tree/master/contracts/eth
ethClientAbi: process.env.ethNearOnEthClientAbi,
nearClientAccount: 'client-eth2.bridge.near',
// https://github.com/aurora-is-near/near-erc20-connector
eNEARAddress: '0x85F17Cf997934a597031b2E18a9aB6ebD4B9f6a4',
// https://github.com/aurora-is-near/rainbow-bridge-frontend/blob/master/abi/eNEAR.abi
eNEARAbi: process.env.eNEARAbi,
nativeNEARLockerAddress: 'e-near.near',
wNearNep141: 'wrap.near',
eventRelayerAccount: 'event-relayer.near',
// https://github.com/Near-One/near-erc20-connector/blob/main/aurora/contracts/NearBridge.sol
wNearBridgeAddress: '0x5D5a9D3fB8BD3959B0C9266f90e126427E83872d',
wNearBridgeAbi: process.env.wNearBridgeAbi,
// https://github.com/Near-One/rainbow-token-connector/tree/master/token-locker
nep141LockerAccount: 'ft-locker.bridge.near',
// https://github.com/Near-One/rainbow-token-connector/tree/master/erc20-bridge-token
erc20FactoryAddress: '0x252e87862A3A720287E7fd527cE6e8d0738427A2',
erc20FactoryAbi: process.env.erc20FactoryAbi,
})
import { setBridgeParams } from '@near-eth/client'
setBridgeParams({
nearEventRelayerMargin: 10, // blocks
sendToNearSyncInterval: 60000, // check light client sync interval (ms)
sendToEthereumSyncInterval: 60000, // check light client sync interval (ms)
maxFindEthProofInterval: 600000, // check finalization status max interval (ms)
ethChainId: 5,
auroraChainId: 1313161555,
// https://github.com/aurora-is-near/rainbow-bridge-frontend/blob/master/abi/erc20.abi
erc20Abi: process.env.erc20Abi,
// https://github.com/aurora-is-near/aurora-engine/blob/master/etc/eth-contracts/contracts/EvmErc20.sol
// https://github.com/aurora-is-near/rainbow-bridge-frontend/blob/aurora-near/abi/auroraErc20.abi
auroraErc20Abi: process.env.auroraErc20Abi,
// https://github.com/aurora-is-near/rainbow-token-connector
erc20LockerAddress: '0xC115851CA60Aed2CCc6EE3D5343F590834e4a3aB',
// https://github.com/aurora-is-near/rainbow-bridge-frontend/blob/master/abi/ERC20Locker.full.abi
erc20LockerAbi: process.env.erc20LockerAbi,
nep141Factory: 'factory.goerli.testnet',
// https://github.com/aurora-is-near/eth-connector/tree/master/eth-custodian
etherCustodianAddress: '0x84a82Bb39c83989D5Dc07e1310281923D2544dC2',
// https://github.com/aurora-is-near/rainbow-bridge-frontend/blob/master/abi/etherCustodian.full.abi
etherCustodianAbi: process.env.etherCustodianAbi,
auroraEvmAccount: 'aurora',
auroraRelayerAccount: 'relay.aurora',
etherExitToEthereumPrecompile: '0xb0bD02F6a392aF548bDf1CfAeE5dFa0EefcC8EaB',
etherExitToNearPrecompile: '0xE9217BC70B7ED1f598ddD3199e80b093fA71124F',
// https://github.com/aurora-is-near/rainbow-bridge-frontend/blob/master/abi/nearOnEthClient.abi
ethClientAddress: '0x37C2d89b55Bfd95532637554711441017eFabFef',
// https://github.com/aurora-is-near/rainbow-bridge/tree/master/contracts/eth
ethClientAbi: process.env.ethNearOnEthClientAbi,
nearClientAccount: 'client-eth2.goerli.testnet',
// https://github.com/aurora-is-near/near-erc20-connector
eNEARAddress: '0xe6b7C088Da1c2BfCf84aaE03fd6DE3C4f28629dA',
// https://github.com/aurora-is-near/rainbow-bridge-frontend/blob/master/abi/eNEAR.abi
eNEARAbi: process.env.eNEARAbi,
nativeNEARLockerAddress: 'enear.goerli.testnet',
wNearNep141: 'wrap.testnet',
eventRelayerAccount: 'event-relayer.goerli.testnet',
// https://github.com/Near-One/near-erc20-connector/blob/main/aurora/contracts/NearBridge.sol
wNearBridgeAddress: '0x329242C003Df320166F5b198dCcb22b0CFF1d91B',
wNearBridgeAbi: process.env.wNearBridgeAbi,
// https://github.com/Near-One/rainbow-token-connector/tree/master/token-locker
nep141LockerAccount: 'ft-locker.sepolia.testnet',
// https://github.com/Near-One/rainbow-token-connector/tree/master/erc20-bridge-token
erc20FactoryAddress: '0xa9108f7F83Fb661e611991116D526fCa1a9585ab',
erc20FactoryAbi: process.env.erc20FactoryAbi,
})
FAQs
Unknown package
We found that @near-eth/client demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.