Ethereum to NEAR
As an Ethereum developer, what should I know about NEAR's models and practices?
NEAR 102 Course
NEAR 102: Introduction to NEAR for Ethereum Developers
ETH v.s. NEAR
Side-by-side comparion between ETH v.s. NEAR for developers
-
Infrastructure
- scalability and speed
- cost
-
Account Model
- account v.s. address
- sub-accounts
- single key pair v.s. multiple key pairs
- key models: full access v.s. function call key
-
Solidity v.s Rust (AssemblyScript)
- cross-contract call
- (de)serialization
-
Deployment and Versioning
- upgradability
Rust Smart Contract
WebAssembly
Docs
Best Practices
Reference
- Austin Abell, Comparing Modern Smart Contracting Environments: Writing a smart contract with Solidity, NEAR, ink!, Solana, and CosmWasm, 2021/03/22
Play with NEAR CLI
Create xxx.near
or xxx.testnet
Account
near call testnet create_account \
'{
"new_account_id": "xxxxxxx.testnet",
"new_public_key": "ed25519:DAh6wwBYbakodZaA3QSZvojBF7EceeUkZsdELTEBRoYt"
}' \
--accountId bot.testnet --deposit 0.1
Read Parameters from JSON File
The JSON file could be params.json
, with content
{
"new_account_id": "xxxxxxx.testnet",
"new_public_key": "ed25519:DAh6wwBYbakodZaA3QSZvojBF7EceeUkZsdELTEBRoYt"
}
Run the command below to create the account:
near call testnet create_account "$(< params.json)" --accountId bot.testnet --deposit 0.1
Send NEP141 token to another account
Here we take Banana
from BerryClub for example.
Suppose we want to transfer 1 Banana from the user robertyan.testnet
to linus.testnet
.
- If the receiver hasn't regisered on NEP141 before, we first need to deposit storage cost for the receiver
linus.testnet
(i.e. register the account on the NEP141 contract) with a small amount of NEAR. - Then we'll be able to call
ft_transfer
to transfer Banana to the receiver. Since the precision of Banana is 18 digits, the amount is1000000000000000000
for sending 1 Banana
TestNet
You need to run storage_deposit
first to register the receiver account on Banana contract berryclub.testnet
near call berryclub.testnet \
storage_deposit '{"account_id": "linus.testnet"}' \
--account-id robertyan.testnet --amount 0.025
Then you can send some tokens to the receiver
near call berryclub.testnet ft_transfer \
'{
"receiver_id": "linus.testnet",
"amount": "1000000000000000000"
}' \
--account-id robertyan.testnet --amount 0.000000000000000000000001
MainNet
You need to run storage_deposit
first to register the receiver account on Banana contract berryclub.ek.near
near call berryclub.ek.near storage_deposit '{"account_id": "linus.near"}' \
--account-id robertyan.near --amount 0.025
Then you can send some tokens to the receiver
near call berryclub.ek.near ft_transfer \
'{
"receiver_id": "linus.near",
"amount": "1000000000000000000"
}' \
--account-id robertyan.near --amount 0.000000000000000000000001
Flexible Account Model
- NEAR Account Introduction: https://docs.near.org/docs/concepts/account | https://medium.com/nearprotocol/an-introduction-to-near-accounts-f96cb84ef091
- NEAR Account Spec: https://nomicon.io/DataStructures/Account.html
- NEAR Wallet: MainNet https://wallet.near.org/ | TestNet https://wallet.testnet.near.org/ (GitHub: https://github.com/near/near-wallet)
- NEAR Explorer: MainNet https://explorer.near.org/ | TestNet https://explorer.testnet.near.org/ (GitHub: https://github.com/near/near-explorer)
Hiding the Blockchain
Storage
Storage Staking on NEAR
Storage Management Standard
Decentralized Storage
Filecoin
- Filecoin-NEAR Bridge: https://near.storage
- Grant: https://github.com/filecoin-project/devgrants/blob/master/rfps/near-and-filecoin.md
Crust
- Post: https://medium.com/nearprotocol/crust-network-partners-with-near-protocol-to-introduce-decentralized-storage-solutions-a17edeaf29bb
Arweave
Ceramic
Sia
Wallet
Topics
- Wallet Login
- Account Creation
- Tokens: Fungible Tokens / Non-Fungible Tokens
- Linkdrop
Fungible Token
Awesome FTs Projects and Toolkits built with NEAR
Standards
Toolkits
- FT Contract: Fungible Token contract implementation
- FT Launcher: launch FT project with easy user on-boarding
- Interact with FT with CLI or RPC: basic operations with FT including read balance and metadata, transfer tokens, and
transfer and call
Core Contracts with FT Support
- linkdrop
- lockup
DApps
Token List
- https://tkn.farm/
Frequently Used Tokens
Name | Mainnet Address | Testnet Address |
---|---|---|
USDT | dac17f958d2ee523a2206206994597c13d831ec7.factory.bridge.near | usdt.fakes.testnet |
DAI | 6b175474e89094c44da98b954eedeac495271d0f.factory.bridge.near | dai.fakes.testnet |
USDC | a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.factory.bridge.near | usdc.fakes.testnet |
wNEAR | wrap.near | wrap.testnet |
REF | token.v2.ref-finance.near | ref.fakes.testnet |
SKYWARD | token.skyward.near | |
OCT | f5cfbc74057c610c8ef151a439252680ac68c6dc.factory.bridge.near | oct.beta_oct_relay.testnet |
PARAS | token.paras.near | paras.fakes.testnet |
stNEAR | meta-pool.near | |
PULSE | 52a047ee205701895ee06a375492490ec9c597ce.factory.bridge.near | pulse.fakes.testnet |
BANANA | berryclub.ek.near | banana.ft-fin.testnet |
WETH | c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2.factory.bridge.near | weth.fakes.testnet |
1INCH | 111111111117dc0aa78b770fa6a738034120c302.factory.bridge.near | |
GRT | c944e90c64b2c07662a292be6244bdf05cda44a7.factory.bridge.near | |
CUCUMBER | farm.berryclub.ek.near | |
HT | 6f259637dcd74c767781e37bc6133cd6a68aa161.factory.bridge.near | |
GTC | de30da39c46104798bb5aa3fe8b9e0e1f348163f.factory.bridge.near | |
UNI | 1f9840a85d5af5bf1d1762f925bdaddc4201f984.factory.bridge.near | |
WBTC | 2260fac5e5542a773aa44fbcfedf7c193bc2c599.factory.bridge.near | |
LINK | 514910771af9ca656af840dff83e8264ecf986ca.factory.bridge.near | |
HAPI | d9c2d319cd7e6177336b0a9c93c21cb48d84fb54.factory.bridge.near | hapi.fakes.testnet |
1MIL | a4ef4b0b23c1fc81d3f9ecf93510e64f58a4a016.factory.bridge.near | |
marmaj | marmaj.tkn.near | |
Cheddar | token.cheddar.near | |
ETH | aurora | eth.fakes.testnet |
PXT | pixeltoken.near | |
DBIO | dbio.near | |
AURORA | aaaaaa20d9e0e2461697782ef11675f668207961.factory.bridge.near | aurora.fakes.testnet |
$META | meta-token.near | |
POTATO | v1.dacha-finance.near | |
FLX | 3ea8ea4237344c9931214796d9417af1a1180770.factory.bridge.near | |
UMINT | e99de844ef3ef72806cf006224ef3b813e82662f.factory.bridge.near | |
nUSDO | v3.oin_finance.near | |
OIN | 9aeb50f542050172359a0e1a25a9933bc8c01259.factory.bridge.near | |
MYRIA | myriadcore.near |
Non-Fungible Token
Awesome NFTs Projects and Toolkits built with NEAR
Standards
- Non-Fungible Token (NEP-171)
- Non-Fungible Token Metadata (NEP-177)
- Non-Fungible Token Approval Management (NEP-178)
- Non-Fungible Token Enumeration (NEP-181)
- Non-Fungible Token Royalty Payout (NEP-199)
Example Projects
NFT Contract Examples
- NFT Example with
near-contract-standard
: Example implementation of a non-fungible token contract which usesnear-contract-standards
and simulation tests. - NFT Contract Simple Example: simple example of how NFT contract looks like
- NFT Contract Standard Implementation: NFT implementation in NEAR Rust SDK
Mint NFTs Tutorials
- Minting NFTs: In this tutorial you'll learn how to easily create your own NFTs without doing any software development by using a readily-available smart contract and a decentralized storage solution like IPFS.
- Create NFTs in Minecraft: This tutorial will run you through minting Minecraft structures of any size onto the NEAR blockchain.
NFT Market Examples
- NFT Marketplace (demo): PoC for NFT market projects
- NFT Launcher: launch NFT project with easy user on-boarding
REST API
- NEAR REST API Server: perform blockchain calls with the simple REST API, with NFT support such as mint NFT, transfer NFT, view NFT owners with the POST/GET requests
More NFT Examples
- 10K: Template for making a NFT contract with a raffle of tokens
DApps
- Mintbase: Digital assets minted and backed by you
- Paras: Create, Trade and Collect Digital Art Cards (DACs)
- Too Rich 秃力富房产: NFT digital art exhibited on Taobao Maker Festival
- NFT Hiphop: NFT collection that featured artists from the 70s to the present, built by Universal Hip Hop Museum, The NEAR Protocol, and Ed Young
- more NFT projects on NEAR
Game
Why Building Games on NEAR?
1. Fast and Scalable
NEAR’s sharded infrastructure make it possible to scale infinitely. The transactions like transfer can be completed instantly on NEAR, and with very low gas fees.
The real-time transaction, low gas fee and high scalability makes it possible to launch world-class game with millions of users.
2. Great User Experience
The NEAR Account and Keys model, Wallet and APIs make it easy to build games with great user experience on NEAR.
The NEAR account is human readable, which makes it able to be used directly for roles in games.
The Function Call Keys make it possible to create secure keys with restricted access.
With the help of NEAR's function call key, web wallet and near APIs, it's quite easy to integrate NEAR with game engines or your web/mobile frontend, and user don't have to install browser extensions to launch the game in web or mobile app.
The progressive onboarding process makes it quite easy for users to create a new account using email or SMS, without the necessity of learning about the concepts of seed phrases, gas fees, etc.
3. Developer Friendly
With NEAR, developers can build smart contracts with common languages that they're already familiar with, such as Rust, TypeScript, or build with Solidity on Aurora if they prefer EVM toolings.
Developers can also build the games with NEAR libraries in JavaScript, Python, or APIs integrated with game frameworks such as Unity, Godot.
Also, 30% of the gas fees spent on the contracts will be paid to developers.
4. Cross-Chain Interoperability
Assets including FTs / NFTs can be bridged to Ethereum efficiently and easily with the help of Rainbow Bridge.
Read more about why NEAR is attractive to developers on https://near.org/developers/
Build Games on NEAR
Read the best practices shared by Human Guild:
Learn with Examples
To learn with concrete examples about how to build games on NEAR, we recommend that you start with the examples of BerryClub and NEAR Lands:
Game Engines / Frameworks
Unity3D
Godot
Cocos2D
Games built on NEAR
Examples
- BerryClub: drawing pixesl to earn
- NEAR Lands: massive multiplayer online world
- OP Games: one game platform, procotol and community on NEAR
- Hash Rush: a mix between DOTA and Warcraft
- 鲱鱼罐头 / Feiyu: mobile app, 1~2M User Base
- Zed Run: horse racing and NFTs
- Corgis3D: NFTs similar to CryptoKitties
- Pixelparty: pixel games extended from BerryClub
- Marble Place: virtual world being built on NEAR
- Shroom Kingdom: play to Earn Game based on Mario
- MTVRS: game studio
Community
- Human Guild
- connected thousands of people
- Creator Economy / Gaming
- help dozens of projects launch on NEAR
Workshop
NEAR RPCs
Mainnet
Provider | Endpoint Root |
---|---|
NEAR | https://rpc.mainnet.near.org |
Pagoda | https://near-mainnet.api.pagoda.co/rpc/v1 |
1RPC | https://1rpc.io/near |
All That Node | https://near-mainnet-rpc.allthatnode.com:3030 |
ankr.com | https://rpc.ankr.com/near |
fast-near | https://rpc.web4.near.page |
Gateway.fm | https://rpc.near.gateway.fm/ |
GetBlock | https://getblock.io/nodes/near/ |
Lavender.Five Nodes | https://near.lavenderfive.com/ |
NodeReal | https://nodereal.io/api-marketplace/near-rpc |
NOWNodes | https://near.nownodes.io/ |
OMNIA | https://endpoints.omniatech.io/v1/near/mainnet/public |
QuickNode | - |
Seracle | https://api.seracle.com/saas/baas/rpc/near/mainnet/public/ |
Archival Nodes
Provider | Endpoint Root |
---|---|
NEAR | https://archival-rpc.mainnet.near.org |
ankr.com | https://rpc.ankr.com/near |
fast-near | https://rpc.web4.near.page |
Testnet
Provider | Endpoint Root |
---|---|
NEAR | https://rpc.testnet.near.org |
Pagoda | https://near-testnet.api.pagoda.co/rpc/v1 |
All That Node | https://near-testnet-rpc.allthatnode.com:3030 |
fast-near | https://rpc.web4.testnet.page/ |
OMNIA | https://endpoints.omniatech.io/v1/near/testnet/public |
Archival Nodes
Provider | Endpoint Root |
---|---|
NEAR | https://archival-rpc.testnet.near.org |
fast-near | https://rpc.web4.testnet.page |
Indexer
Introduction
Usage
NEAR Indexer for Explorer
Shared Public Access
NEAR runs the indexer and maintains it for NEAR Explorer, NEAR Wallet, and some other internal services. It proved to be a great source of data for various analysis and services, so we decided to give a shared read-only public access to the data:
- testnet credentials:
postgres://public_readonly:nearprotocol@35.184.214.98/testnet_explorer
- mainnet credentials:
postgres://public_readonly:nearprotocol@104.199.89.51/mainnet_explorer
Database Structure
Common SQL Recipes
Total New Accounts By Date
SELECT
TIMESTAMP ‘epoch’ + DIV(DIV(blocks.block_timestamp, 1000000000), 60 * 60 * 24) * INTERVAL ‘1 day’ AS “date”,
COUNT(*) as new_accounts_count_by_date
FROM accounts
JOIN receipts ON receipts.receipt_id = accounts.created_by_receipt_id
JOIN blocks ON blocks.block_hash = receipts.included_in_block_hash
GROUP BY “date”
ORDER BY “date”
Top 10 Accounts with most Transactions in Past Two Weeks
SELECT signer_account_id,
COUNT(*) AS transactions_count
FROM transactions
WHERE transactions.block_timestamp >= (cast(EXTRACT(EPOCH FROM NOW()) - 60 * 60 * 24 * 14 AS bigint) * 1000 * 1000 * 1000)
AND transactions.block_timestamp < (cast(EXTRACT(EPOCH FROM NOW()) AS bigint) * 1000 * 1000 * 1000)
GROUP BY signer_account_id
ORDER BY transactions_count DESC
LIMIT 10
Active Accounts by Date
SELECT
TIMESTAMP 'epoch' + DIV(DIV(transactions.block_timestamp, 1000000000), 60 * 60 * 24) * INTERVAL '1 day' AS "date",
COUNT(distinct transactions.signer_account_id) as active_accounts_count_by_date
FROM transactions
JOIN execution_outcomes ON execution_outcomes.receipt_id = transactions.converted_into_receipt_id
WHERE execution_outcomes.status IN ('SUCCESS_VALUE', 'SUCCESS_RECEIPT_ID') and
TIMESTAMP 'epoch' + DIV(DIV(transactions.block_timestamp, 1000000000), 60 * 60 * 24) * INTERVAL '1 day' > current_date -7
GROUP BY "date"
ORDER BY "date"
Real-World Examples
BerryClub Wayback
BerryClub Wayback used indexer to fetch 50 edits randomly from all the edits or by a user
find edits: source code
Fetch 50 edits randomly from all the edits or edits by a user
async function findEdits(accountId) {
console.log('findEdits', accountId);
return withPgClient(async client => {
const { rows } = await client.query(`
SELECT included_in_block_timestamp AS block_timestamp, included_in_block_hash AS block_hash
FROM receipts ${accountId ? '' : `TABLESAMPLE SYSTEM(0.05)`}
WHERE receiver_account_id = 'berryclub.ek.near'
${accountId ? `AND predecessor_account_id = $1` : ''}
ORDER BY random()
LIMIT 50
`, accountId ? [accountId] : []);
console.log(`Found ${rows.length} rows`);
return rows;
})
}
Wallet Contract Helper
NEAR Wallet used indexer to query necessary information related to accounts, such as activities, FTs/NFTs owned by the user, etc.
findAccountActivity: source code
Show account activities in wallet
const findAccountActivity = async (ctx) => {
const { accountId } = ctx.params;
let { offset, limit = 10 } = ctx.request.query;
if (!offset) {
offset = '9999999999999999999';
}
const { rows } = await pool.query(`
select
included_in_block_hash block_hash,
included_in_block_timestamp block_timestamp,
originated_from_transaction_hash hash,
index_in_action_receipt action_index,
predecessor_account_id signer_id,
receiver_account_id receiver_id,
action_kind,
args
from action_receipt_actions
join receipts using(receipt_id)
where
receipt_predecessor_account_id != 'system' and
(receipt_predecessor_account_id = $1 or receipt_receiver_account_id = $1) and
$2 > receipt_included_in_block_timestamp
order by receipt_included_in_block_timestamp desc
limit $3
;
`, [accountId, offset, limit]);
ctx.body = rows;
};
findAccountsByPublicKey: source code
Find accounts by public key, so when you input seed phrase, wallet is able to know which account is related to this seed phrase.
const findAccountsByPublicKey = async (ctx) => {
const { publicKey } = ctx.params;
const { rows } = await pool.query(`
SELECT DISTINCT account_id
FROM access_keys
JOIN accounts USING (account_id)
WHERE public_key = $1
AND accounts.deleted_by_receipt_id IS NULL
AND access_keys.deleted_by_receipt_id IS NULL
`, [publicKey]);
ctx.body = rows.map(({ account_id }) => account_id);
};
findLikelyTokens: source code
List the FT tokens related to the current user.
const findLikelyTokens = async (ctx) => {
const { accountId } = ctx.params;
const received = `
select distinct receipt_receiver_account_id as receiver_account_id
from action_receipt_actions
where args->'args_json'->>'receiver_id' = $1
and action_kind = 'FUNCTION_CALL'
and args->>'args_json' is not null
and args->>'method_name' in ('ft_transfer', 'ft_transfer_call')
`;
const mintedWithBridge = `
select distinct receipt_receiver_account_id as receiver_account_id from (
select args->'args_json'->>'account_id' as account_id, receipt_receiver_account_id
from action_receipt_actions
where action_kind = 'FUNCTION_CALL' and
receipt_predecessor_account_id = $2 and
args->>'method_name' = 'mint'
) minted_with_bridge
where account_id = $1
`;
const calledByUser = `
select distinct receipt_receiver_account_id as receiver_account_id
from action_receipt_actions
where receipt_predecessor_account_id = $1
and action_kind = 'FUNCTION_CALL'
and (args->>'method_name' like 'ft_%' or args->>'method_name' = 'storage_deposit')
`;
const { rows } = await pool.query([received, mintedWithBridge, calledByUser].join(' union '), [accountId, BRIDGE_TOKEN_FACTORY_ACCOUNT_ID]);
ctx.body = rows.map(({ receiver_account_id }) => receiver_account_id);
};
findLikelyNFTs: source code
List the NFT tokens related to the current user.
const findLikelyNFTs = async (ctx) => {
const { accountId } = ctx.params;
const received = `
select distinct receipt_receiver_account_id as receiver_account_id
from action_receipt_actions
where args->'args_json'->>'receiver_id' = $1
and action_kind = 'FUNCTION_CALL'
and args->>'args_json' is not null
and args->>'method_name' like 'nft_%'
`;
// TODO: How to query minted tokens?
const { rows } = await pool.query([received].join(' union '), [accountId]);
ctx.body = rows.map(({ receiver_account_id }) => receiver_account_id);
};
Aurora
Introduction to Aurora
Design & Discussion
Dev Docs
- Aurora Dev Docs
- Aurora Introduction
- Examples
Tooling
Rainbow Bridge
Frontend
Design
- ETH-NEAR Rainbow Bridge (中文版)
- How the NEAR Rainbow Bridge works
- Light Client Spec
- Bridge Upgradability and Governance
Repositories
- Bridge core infrastructure: relays, clients, provers, watchdog
- Bridge frontend and bridge client
- ERC20 / NEP141 token connector
- CLI scripts for transfers of ERC20 / NEP141 over the bridge
Community
Contract
Localization
Build DApp with Localization in Mind
In the Open Web world, we should keep in mind your apps will be accessed not only by users who speak English, but also people all around the world.
Considering around 30~40% of the users may actaully come from districts like China, Korea, Vietnam, etc., it's important to build your decentralized application with localization ready from the beginning.
To be specific, DApp localization means:
- i18n: Your DApp's user interface has i18n support from the beginning. So it costs minimal extra efforts to refator your code and add support to other languages.
- Web app deployment: Since the frontend of most DApps nowadays are actually web applications. The deployment of your frontend code, espeically the static sites with JAMStack (Next.js, Nuxt.js, etc.), should choose the appropriate CI/CD, and CDN solutions to make your site be able to be open in less than 3 seconds rather than 30 seconds which will scare away your users.
- RPC Node and Indexer: For NEAR RPC Node, and indexers, choose the nodes or servers that are most appropriate for your infrastructure and users to reduce the latency and improve stability.
- Decentralized Storage: For decentralized storage solutions such IPFS, Arweave, Sia, Ceramic, etc. choose an appropriate service provider which help make your images, videos, etc. accessible globally by default without much extra efforts.
- Backend Services: For any other dependent serivces, such as any helper services built with indexers, or other relevant data services, try to make the services accessible globally.
Internalization (i18n)
We suggest the DApp developers to build your web application with i18n from the first day.
React
You can use react-i18next
or any other frameworks you prefer if you're building with React or React Native.
Or you may use react-localize-redux
in case you don't want to keep the language route such as en
, zh
in your URLs.
Vue
vue-i18n may be a good solution for Vue developers, or you can simply use nuxt/i18n module if you're building with Nuxt.js.
Need Help with Translation?
In case you need help about translation your DApp into any languages, create an issue here following the template, and we'll help connect you with the community to set up bounties and ask verified translators to help with the translation of your project.
Web App Deployment
Static Site Deployment
If you're deploying your web app as a static site or SPA (Single Page Application), and would like to make your site easily accessible with fast loading speed in all areas including China, you need to carefully choose the deployment services, otherwise it's possible your users will complain why your sites take 30~60 seconds to open.
Unfortunately, the most popular static site hosting solutions simply doesn't work globally especially in China, including Netlify, Vercel, Render, etc.
The current recommended solution is Cloudflare Pages which has verified to be working well even if your JS bundle may be as large as 1M.
RPC Nodes and Indexers
RPC Node
If your app requires to use custom RPC Nodes, NEAR Protocol is working with RPC Node service providers such as Figment DataHub, Bison Trails, BSN (Blockchain-based Service Network), NEAR DRPC, etc., which will help to set up the best solutions for your DApps.
Please feel free to contact email: robert AT near DOT org if you need nodes from China, we can help to set up optimized RPC nodes for your DApps.
Indexer
For most DApps, now you can use the public indexer server as specifid in the indexer chapter, but in case you need any customized Indexer server, you can try to set up your own or discuss with us in community.
Decentralized Storage
NEAR Procotol is working closely with Decentralized Storage solutions such as Filecoin, Ceramic, Crust, etc., to make it extremely easy to integrate your DApp with decentralized storage solutions.
IPFS
You should look at the Filecoin-NEAR Bridge bulit by Textile if you're building with IPFS which provide free storage for NEAR users: https://near.storage/
Also we'd like to recommend you to look at the IPFS service providers such as ......, in case you'd like to have built-in CDN ready for your IPFS files.
Ceramic
To Be Added
Arweave
To Be Added
Backend Services
For backend services who'd like to achieve globally accessibility, you need to route your users to the optimal servers to reduce the latency.
Examples
- Mintbase
- Paras
- Pulse
- Ref Finance
- Aurora
- Rainbow Bridge
- SputnikDAO
Security
- NEAR Standard Contracts: https://github.com/near/near-sdk-rs/tree/master/near-contract-standards