教程地址:www.youtube.com/watch?v=gAT…
Moralis 官网:admin.moralis.io/dapps
文档:v1docs.moralis.io/introductio…
npm:www.npmjs.com/package/mor…
!!!修改教程源码(V1)
源码地址: https://github.com/ttwo22/Moralis-Web.git
修改添加功能:
- 连接/注销钱包
- 查询合约数据
- 动态添加查询
- 设置数据在本地Session
- 修改路由
- 修改获取合约数据的表格
遇到的坑:
- 版本问题,V1版本和V2很多API不兼容,环境bug异常频出
- V1依赖导入好几种方法,个别api失效
- V2只有nextjs的教学,这个源码是v1的
- moralis的服务器数据库增删改查调用api也有环境问题,服务器时不时访问不稳定
- v1个别api调用需要安装很多缺失依赖,详细看官方文档www.npmjs.com/package/mor…
一、教程笔记(V1)
设置 Moralis
进入Moralis官网免费注册一个用户,进入仪表盘创建一个新的Dapp
设置名称创建项目成功
设置 API 速率限制
再cloud.js里设置速率限制:v1docs.moralis.io/moralis-dap…
//限制用户可以向 web3Api 发出的请求数
Moralis.settings.setAPIRateLimit({
anonymous:10, authenticated:20, windowMs:60000
})
这会将未经身份验证的用户的请求数限制为每分钟 10 个(60000 毫秒),对于经过身份验证的用户,则限制为每分钟 20 个。
这里教程设置为anonymous:1000, authenticated:2000, windowMs:60000
在 IDE 中设置 Cloud Functions
您可以使用您最喜欢的 IDE 并通过使用moralis-admin-cli npm 包自动同步代码
- 首先全局安装moralis admin cli包
npm i -g moralis-admin-cli
- 执行 watch-cloud-file 并更改为您的云文件的正确路径
moralis-admin-cli watch-cloud-folder --moralisApiKey VKMD0iAFRrsiNQ4 --moralisApiSecret fU7nbkBx40xxBsf --moralisSubdomain 9ctqwh3fgrja.usemoralis.com --autoSave 1 --moralisCloudfolder D:\Project\Moralis\Test\cf
//替换一下为你自己的路径
D:\Project\Moralis\Test\cf
成功
点击头像返回旧版界面
点击test右边箭头拉开点击Cloud Functions ,查看文件是否同步
NFT 传输数据处理
切换到stats文件夹,使用命令行npm init 初始化package.json,新建stats.js
cd stats
npm init
npm i moralis
npm i fs
配置文件
到dapp里复制Dapp凭证,配置参数。
调用Web3API进行查询
/nft/{address}/transfers:admin.moralis.io/web3apis
获取与给定参数匹配的令牌传输。 返回 NFT 转账的集合
代码
const Moralis = require("moralis-v1/node");
const fs = require("fs");
const serverUrl = "https://9ctqwh3fgrja.usemoralis.com:2053/server";
const appId = "XhOTGb28N5lTeowwqTmJiRAJdtQFP8OJw3Mhj6yi";
const contractAddress = "0x23581767a106ae21c074b2276D25e5C3e136a68b"; //Moralis
async function getAllOwners(){
await Moralis.start({serverUrl:serverUrl,appId:appId});
let cursor = null;
let owners={};
let res;
let accountedTokens = [];
do{
const response = await Moralis.Web3API.token.getContractNFTTransfers({
address:contractAddress,
chain:"eth",
limit:100,
cursor:cursor,
});
res = response;
console.log(
`Got page ${response.page} of ${Math.ceil(response.total/response.page_size)},${response.total} total`
)
for(const transfer of res.result){
if(!owners[transfer.to_address] && !accountedTokens.includes(transfer.token_id)){
owners[transfer.to_address]={
address:transfer.to_address,
amount:Number(transfer.amount),
tokenId:[transfer.token_id],
prices:[Number(transfer.value)],
dates:[transfer.block_timestamp],
}
accountedTokens.push(transfer.token_id);
}else if(!accountedTokens.includes(transfer.token_id)){
owners[transfer.to_address].amount++;
owners[transfer.to_address].tokenId.push(transfer.token_id);
owners[transfer.to_address].prices.push(Number(transfer.value));
owners[transfer.to_address].dates.push(transfer.block_timestamp);
accountedTokens.push(transfer.token_id);
}
}
cursor = res.cursor;
}while(cursor != "" && cursor != null);
const jsonContentOwners = JSON.stringify(owners);
fs.writeFile("moonbirdsOwners.json",jsonContentOwners,"utf8",function(err){
if(err){
console.log("An error occured while writing JSON Object to File");
return console.log(err);
}
console.log("JSON file has been saved");
})
}
getAllOwners();
执行JS文件
node .\stats.js
运行报错的话,视频教程代码有几个bug
//版本问题,要下载旧版的moralis-v1使用
const Moralis = require("moralis-v1/node");
//合约地址不是那个Master Key:
//是你自己铸造的,可以用视频作者,有数据就行
//简单测试代码,返回json
async function getAllOwners() {
await Moralis.start({serverUrl:serverUrl,appId:appId});
const options = {
chain: "eth",
address: "0x23581767a106ae21c074b2276D25e5C3e136a68b",
};
const nftTransfers = await Moralis.Web3API.token.getContractNFTTransfers(
options
);
console.log(nftTransfers);
}
成功会生成json文件
继续修改json文件,添加生成一个历史记录的文件
const express = require("express");
const cors = require("cors");
const moonbirds = require("./moonbirdsOwners");
const moonbirdsH = require("./moonbirdsHistory");
const collections = {
"0x23581767a106ae21c074b2276D25e5C3e136a68b":{
owners: moonbirds,
history: moonbirdsH
},
}
const app = express();
const port = 4000;
app.use(cors());
app.get("/", (req, res) => {
res.send("Welcome to the Whale NFT server");
});
app.get("/collection", (req, res) => {
const slug = req.query.slug;
res.send(collections[slug].owners);
});
app.get("/user", (req, res) => {
const slug = req.query.slug;
const address = req.query.address;
res.send(collections[slug].history[address]);
});
app.listen(port, () =>
console.log(`Whale NFT server running on ${port}`)
);
复制两个文件的数据到server文件夹下,加个默认导出
设置节点 JS 服务器
cd server
npm init -y
npm i express
npm i cors
//新建index.js
const express = require("express");
const cors = require("cors");
const moonbirds = require("./moonbirdsOwners");
const moonbirdsH = require("./moonbirdsHistory");
const collections = {
"0x23581767a106ae21c074b2276D25e5C3e136a68b":{
owners: moonbirds,
history: moonbirdsH
},
}
const app = express();
const port = 4000;
app.use(cors());
app.get("/", (req, res) => {
res.send("Welcome to the Whale NFT server");
});
app.get("/collection", (req, res) => {
const slug = req.query.slug;
res.send(collections[slug].owners);
});
app.get("/user", (req, res) => {
const slug = req.query.slug;
const address = req.query.address;
res.send(collections[slug].history[address]);
});
app.listen(port, () =>
console.log(`Whale NFT server running on ${port}`)
);
React程序
教程的github源码配置了一下大概了解,不过用的是json死数据,还有版本问题的web3api调用没成功
二、Moralis V1
每个 Dapp 都有一个链上部分(智能合约)和一个链下部分(服务器)。服务器用于从区块链收集数据并将其提供给客户端,例如 Web 和移动应用程序
入门
什么是 Moralis Dapp?
每个 Dapp 通常分为 2 个部分:
- 1 .链上: 智能合约、代币和 NFT 等链上资产、链上交易等。
- 2 .链下: 从区块链收集数据的后端基础设施,为 Web 应用程序和移动应用程序等客户端提供 API,索引区块链,提供实时警报,协调不同链上发生的事件,处理用户生命周期还有更多。
Moralis Dapp 用于加速链下基础设施的实施。Moralis Dapp 是一个捆绑解决方案,包含大多数 Dapp 所需的所有功能,以便尽快启动。
1.创建一个免费帐户
前往Moralis并注册一个免费帐户。
2.创建 Moralis 服务器
点击右上角的新建服务器。
您可以使用 Moralis 开发 dApps主网、测试网和本地开发链(例如 Hardhat 和 Ganache)。
现在,请选择Mainnet Server 。
3.设置所需的环境
出于本演示的目的,我们选择了 Ethereum、Polygon、BSC 和 Avalanche。
4. 探索 Dapp 仪表板
现在您将在仪表板中看到您的服务器,我们可以继续并创建一个与服务器对话并能够登录用户、获取用户数据(令牌、NFT、历史交易)等等的 Web 应用程序!当然默认所有跨链🤯
服务器显示几个重要指标如上图所示:
- Network:每秒网络流量
- CPU: 服务器的 CPU 使用率
- RAM: 服务器的内存使用情况
- DISK: 服务器的磁盘使用情况
- Number of Users: 已在服务器中认证的用户数
将 Dapp 迁移到 Nitro 版本
现在,在 Moralis 中创建的每个新 Dapp 都将默认为 Nitro。但是,在 Moralis Nitro 推出之前创建的那些 Dapps 可能仍在使用旧版本。要将服务器升级到 Nitro,只需单击此处安装 coreservices 插件。
请记住,一旦添加了 coreservices 插件,就无法删除它。这意味着从 Legacy 到 Nitro 的迁移将是不可逆转的。在您的服务器上,您可以将coreservices其视为插件之一。
与SDK连接(React)
初始化Moralis框架需要服务器地址和api
//Creating React App
yarn create react-app moralis-react-app
// Install the SDK
cd moralis-react-app
yarn add moralis-v1 react-moralis
// Initialize the SDK
//初始化框架,在index.js加入react-moralis
import { MoralisProvider } from "react-moralis";
ReactDOM.render(
<React.StrictMode>
<MoralisProvider serverUrl="https://9ctqwh3fgrja.usemoralis.com:2053/server" appId="XhOTGb28N5lTeowwqTmJiRAJdtQFP8OJw3Mhj6yi">
<App />
</MoralisProvider>
</React.StrictMode>,
document.getElementById("root")
);
会报错很多缺失依赖库,webpack打包的环境配置项缺失
安装依赖完后配置完后还是会弹出一个Right-hand side of instanceof is not callable这个bug
官网这个bug也没有修复,找到解决的方法
连接钱包
<script src="https://unpkg.com/moralis@1.5.9/dist/moralis.js"></script>
<script>
window.Moralis = Moralis;
</script>
/** Add from here down */
async function login() {
let user = Moralis.User.current();
if (!user) {
try {
user = await Moralis.authenticate({ signingMessage: "Hello World!" });
console.log(user.get("ethAddress"));
} catch (error) {
console.log(error);
}
}
}
async function logOut() {
await Moralis.User.logOut();
console.log("logged out");
}
useEffect(() => {
const appId = "XhOTGb28N5lTeowwqTmJiRAJdtQFP8OJw3Mhj6yi";
const serverUrl = "https://9ctqwh3fgrja.usemoralis.com:2053/server";
window.Moralis.start({
serverUrl: serverUrl,
appId: appId,
});
}, []);
document.getElementById("btn-login").onclick = login;
document.getElementById("btn-logout").onclick = logOut;
\
三、新版Moralis(V2)
Moralis 是将 web3 功能添加到任何技术堆栈中的最简单、最可靠的方法。Moralis 默认是跨链的,支持以太坊、BNB 链、Polygon、Avalanche、Fantom、Solana 和 Elrond 等许多链和 L2。
(一)使用NodeJS实现基本查询dapp
启动您的第一个 dapp!提前准备:
- 创建一个 Moralis 帐户
- 安装并设置您选择的编辑器( VsCode)
- 安装 NodeJs
1. 创建 NodeJs Web3 应用程序
创建一个应用程序,显示任何地址和 EVM 链的原生余额、ERC20 代币和 NFT!
mkdir Moralis nodejs
cd Moralis nodejs
npm init -y
npm install moralis express
//设置脚本调用
"scripts": {
"start": "node index.js"
},
2. 导入并设置最新的 Moralis NodeJs SDK
从Moralis 仪表板获取您的信息Web3 Api Key
//Moralis->Accounts Setting->KEY
5To9SQIceq7nHKILbYGAXhyLd08fAgWMa4hhD8XUvMNgHNzefwmqDT1jwM7wlTpL
3. 设置一个简单的 Express 服务器
const express = require("express");
//Import Moralis
const Moralis = require('moralis').default;
//Import the EvmChain dataType
const {EvmChain} = require("@moralisweb3/evm-utils");
const app = express();
const port=4000;
const MORALIS_API_KEY = "5To9SQIceq7nHKILbYGAXhyLd08fAgWMa4hhD8XUvMNgHNzefwmqDT1jwM7wlTpL";
const address = "";
const chain = EvmChain.ETHEREUM;
app.get("/",(req,res)=>{
res.send("Hello world")
})
// Add this a startServer function that initialises Moralis
const startServer = async ()=>{
await Moralis.start({
apiKey:MORALIS_API_KEY,
})
}
app.listen(port,()=>{
console.log(`http://localhost:${port}`)
})
startServer();
4. 将您的应用程序与 Moralis Services 集成
获取并显示原生余额getNativeBalance()
const nativeBalance = await Moralis.EvmApi.account.getNativeBalance({
address,
chain,
})
获取并显示 ERC20 余额getTokenBalances()
const tokenBalance = await Moralis.EvmApi.account.getTokenBalances({
address,
chain
});
const tokens = tokenBalance.result.map((token) => token.display());
获取并显示带有元数据的 NFTgetNFTs()
const nftsBalance = await Moralis.EvmApi.account.getNFTs({
address,
chain,
limit:10,
})
const nfts = nftsBalance.result.map((nft)=>({
name:nft.result.name,
amount:nft.result.amount,
metadata:nft.result.metadata,
}));
5. 从任何区块链读取任何区块链数据
您已经使用 Express 和 Moralis 创建了一个简单的 NodeJs 服务器,用于获取所提供地址和链的加密数据。
const express = require("express");
//Import Moralis
const Moralis = require("moralis").default;
//Import the EvmChain dataType
const { EvmChain } = require("@moralisweb3/evm-utils");
const app = express();
const port = 4000;
const MORALIS_API_KEY =
"5To9SQIceq7nHKILbYGAXhyLd08fAgWMa4hhD8XUvMNgHNzefwmqDT1jwM7wlTpL";
const address = "0x3692415e6f4aaeA2d3B356D83415c53A06b15Fec";
const chain = EvmChain.ETHEREUM;
app.get("/", (req, res) => {
res.send("Hello world");
});
// Add this a startServer function that initialises Moralis
const startServer = async () => {
await Moralis.start({
apiKey: MORALIS_API_KEY,
});
};
async function getBalancedata() {
const nativeBalance = await Moralis.EvmApi.account.getNativeBalance({
address,
chain,
});
const native = nativeBalance.result.balance.ether;
const tokenBalance = await Moralis.EvmApi.account.getTokenBalances({
address,
chain
});
const tokens = tokenBalance.result.map((token) => token.display());
const nftsBalance = await Moralis.EvmApi.account.getNFTs({
address,
chain,
limit:10,
})
const nfts = nftsBalance.result.map((nft)=>({
name:nft.result.name,
amount:nft.result.amount,
metadata:nft.result.metadata,
}));
return {native,tokens,nfts};
}
app.get("/balance", async (req, res) => {
try {
const data = await getBalancedata();
res.status(200);
res.json(data)
} catch (error) {
console.log(error);
res.status(500);
res.json({ error: error.message });
}
});
app.listen(port, () => {
console.log(`http://localhost:${port}`);
});
startServer();
(二)使用NextJS实现Web3身份验证
创建一个允许用户使用他们的 web3 钱包登录的 NextJS 应用程序
在 web3 钱包身份验证之后,next-auth库创建一个会话 cookie,其中存储了加密的JWT (JWE)。它包含用户浏览器中的会话信息(例如地址、签名消息和到期时间)。这是在没有数据库的情况下存储用户信息的安全方式,没有密钥就不可能读取/修改 JWT 。
用户登录后,他们将能够访问显示所有用户数据的页面。
您可以在此处找到包含最终代码的存储库:https ://github.com/MoralisWeb3/demo-apps/tree/main/nextjs_moralis_auth
1. 创建一个Next.js应用并安装依赖
yarn create next-app moralis-app --typescript
cd moralis-app
//安装moralis、next-auth库创建一个会话cookie、axios发起请求
yarn add moralis next-auth axios
//使用 web3 钱包(例如 Metamask)实现身份验证,我们需要使用 web3 库
yarn add wagmi ethers
//wagmi是 React Hooks 的集合,包含开始使用以太坊所需的一切。wagmi 可以轻松“连接钱包”、显示 ENS 和余额信息、签署消息、与合约交互等等——所有这些都具有缓存、请求重复数据删除和持久性。
npm run dev
2. 在应用根目录的文件中添加新的环境变量:.env
- APP_DOMAIN:请求签名的 RFC 4501 DNS 授权
- MORALIS_API_KEY : 你可以在这里获取
- NEXTAUTH_URL:您的应用地址。在开发阶段使用http://localhost:3000
- NEXTAUTH_SECRET:用于加密用户的 JWT 令牌。您可以在此处输入任何值或在这里生成它generate-secret.now.sh/32
APP_DOMAIN=amazing.finance
MORALIS_API_KEY=xxx
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=84b047cbf06e8e6f299f1f50dc0e0a09
3.配置入口首页index.js添加一个按钮登录进行路由跳转
import Link from "next/link";
export default function HomePage() {
return (
<>
<div>Welcome to my Next.js dApp!</div>
<Link href="/user">
<button>登录</button>
</Link>
</>
);
}
4. 创建一个登录页面
import { InjectedConnector } from 'wagmi/connectors/injected';
import { signIn } from 'next-auth/react';
import { useAccount, useConnect, useSignMessage, useDisconnect } from 'wagmi';
import { useRouter } from 'next/router';
import axios from 'axios';
export default function SignIn() {
const { connectAsync } = useConnect();
const { disconnectAsync } = useDisconnect();
const { isConnected } = useAccount();
const { signMessageAsync } = useSignMessage();
const { push } = useRouter();
const handleAuth = async () => {
//判断钱包是否连接,如果已连接就断开连接
if (isConnected) {
await disconnectAsync();
}
//从窗口注入的钱包扩展属性获取钱包账户地址和链
const { account, chain } = await connectAsync({ connector: new InjectedConnector() });
//处理信息包装成一个对象
const userData = { address: account, chain: chain.id, network: 'evm' };
//用axios发送用户数据请求api进行签名验证
const { data } = await axios.post('/api/auth/request-message', userData, {
headers: {
'content-type': 'application/json',
},
});
const message = data.message;
//弹出签署消息弹窗
const signature = await signMessageAsync({ message });
// 成功认证后将用户重定向到“/user”页面,传递(信息,签名结果,重定向,路径)
const { url } = await signIn('credentials', { message, signature, redirect: false, callbackUrl: '/user' });
//我们从回调中获取 url 并将其推送到路由器以避免页面刷新
push(url);
};
return (
<div>
<h3>Web3 验证</h3>
<button onClick={() => handleAuth()}>通过 Metamask 进行身份验证</button>
</div>
);
}
请求connectAsync返回对象,就是钱包扩展注入的全局属性
请求request-message返回一个对象
5. api/auth文件夹下的request-message.js
//导入Moralis
import Moralis from 'moralis';
//配置
const config = {
domain: process.env.APP_DOMAIN,
statement: 'Please sign this message to confirm your identity.',
uri: process.env.NEXTAUTH_URL,
timeout: 60,
};
//处理程序
export default async function handler(req, res) {
//结构传过来的账户地址、链、网络
const { address, chain, network } = req.body;
//传入api.key
await Moralis.start({ apiKey: process.env.MORALIS_API_KEY });
//请求信息,身份认证的一个API,返回请求回来的数据
try {
const message = await Moralis.Auth.requestMessage({
address,
chain,
network,
...config,
});
res.status(200).json(message);
} catch (error) {
res.status(400).json({ error });
console.error(error);
}
}
6. 用户界面,签名成功后把结果显示在用户页面
import { getSession, signOut } from "next-auth/react";
//获取本地的CSRF令牌请求Session展示到页面
export async function getServerSideProps(context) {
const session = await getSession(context);
//登出session删除了重定向页面
if (!session) {
return {
redirect: {
destination: "/signin",
permanent: false,
},
};
}
//返回session
return {
props: { user: session.user },
};
}
export default function User({ user }) {
return (
<div>
<h4>User session:</h4>
<pre>{JSON.stringify(user, null, 2)}</pre>
{/* 通过删除会话 cookie 将用户注销。 自动将 CSRF 令牌添加到请求中。 */}
<button onClick={() => signOut({ redirect: "/signin" })}>Sign out</button>
</div>
);
}
7. 动态路由声明文件[...nextauth].js
import CredentialsProvider from 'next-auth/providers/credentials';
import NextAuth from 'next-auth';
import Moralis from 'moralis';
export default NextAuth({
providers: [
CredentialsProvider({
name: 'MoralisAuth',
credentials: {
message: {
label: 'Message',
type: 'text',
placeholder: '0x0',
},
signature: {
label: 'Signature',
type: 'text',
placeholder: '0x0',
},
},
async authorize(credentials) {
try {
const { message, signature } = credentials;
await Moralis.start({ apiKey: process.env.MORALIS_API_KEY });
const { address, profileId, expirationTime } = (await Moralis.Auth.verify({ message, signature, network: 'evm' })).raw;
const user = { address, profileId, expirationTime, signature };
return user;
} catch (e) {
// eslint-disable-next-line no-console
console.error(e);
return null;
}
},
}),
],
callbacks: {
async jwt({ token, user }) {
user && (token.user = user);
return token;
},
async session({ session, token }) {
session.expires = token.user.expirationTime;
session.user = token.user;
return session;
},
},
session: {
strategy: 'jwt',
},
});
总结:
- 创建一个Nextjs应用,安装依赖
moralis next-auth axios wagmi ethers - 注册moralis服务器账户获取
web3.api,创建配置文件.env - 调用库依赖的api进行查询交互
`disconnectAsync`断开钱包连接
`connectAsync`获取钱包信息
`signMessageAsync`进行钱包签名连接
`signIn`登入自动将 CSRF 令牌添加到请求中
`signOut`删除会话 cookie 将用户注销
`getSession`获取CSRF发起请求获取session
`await Moralis.start({ apiKey: process.env.MORALIS_API_KEY });`调用Moralis.API之前启用
`Moralis.Auth.requestMessage`身份认证的一个API,返回签名认证的信息
`Moralis.EvmApi.account.getNativeBalance`查询合约余额