@uptickproject/checkin-plugin
v0.1.1
Published
Uptick daily check-in plugin SDK: chain queries, EIP712 signing, check-in transactions, and API authentication.
Maintainers
Readme
@uptickproject/checkin-plugin
每日签到插件 SDK:链上查询、EIP712 签发、构造 checkIn calldata、可选上链。
App 必须走前端钱包登录 + token。apiKey 是公开标识,可以放在客户端;apiSecret 只能放服务端。合约 proxy 地址由 /v2/checkin/info 下发,不必写死在 App。
依赖
peerDependency(接入方已有则不必再装):
web3^1.10axios>= 0.27react-native-device-info>= 10(仅 RN 默认DeviceIdProvider;Node 须自注入)
内置:js-sha256(仅 v1 HMAC)。
App 接入(v2,推荐)
import { AuthManager, CheckInSDK, CheckInChain, buildSignMessage } from '@uptickproject/checkin-plugin';
const auth = new AuthManager({
authUrl: 'https://<uptick-plugin>',
apiKey: '<public-api-key>', // 前端模式公开标识
address: wallet.address,
signMessage: (message) => wallet.personalSign(message),
// 建议持久化 token,避免每次打开都签名登录
storage: { get, set },
});
await auth.login(); // personal_sign: Uptick sign-in\n{apiKey}\n{address}\n{nonce}
const sdk = new CheckInSDK(
{ signServiceUrl: authUrl, rpcUrl, chainId },
{ authManager: auth }, // RN 可省略 deviceIdProvider
);
const info = await sdk.getInfo(); // 写入 sdk.contractAddress
const can = await sdk.canCheckInToday(wallet.address);
const sign = await sdk.fetchCheckInSign(); // 采集 deviceId + nonce + EIP712
const data = sdk.buildCheckInData(sign.deviceId, sign.timestamp, sign.sign);
// 用接入方钱包签交易并广播(SDK 不上收用户私钥)
const chain = new CheckInChain(rpcUrl, sdk.getContractAddress()!);
const receipt = await sdk.checkIn(
wallet.address,
chain.createPrivateKeySigner(wallet.privateKey),
);buildSignMessage(apiKey, address, nonce) 与服务端 personal_sign 原文一致:Uptick sign-in\n{apiKey}\n{address}\n{nonce}。
更省事的接入方式:直接使用高层 CheckInClient,token 缓存、活动解析、余额判断、七日状态机都在 SDK 内完成。
import {
CheckInError,
createWeb3TransactionSigner,
getCheckInClient,
} from '@uptickproject/checkin-plugin';
const client = await getCheckInClient({
authUrl,
apiKey: '<public-api-key>',
address: wallet.address,
rpcUrl,
chainId,
signMessage: message => wallet.personalSign(message),
transactionSigner: createWeb3TransactionSigner({
signTransaction,
sendSignedTransaction,
privateKey,
rpcUrl,
}),
});
const state = await client.getState();
try {
const receipt = await client.checkIn();
} catch (error) {
if (error instanceof CheckInError && error.code === 'INSUFFICIENT_BALANCE') {
// 由 App 决定是否引导用户领取水龙头
}
}防伪:deviceId 与 IP
- deviceId:默认 RN
DeviceInfo.getUniqueId(),再normalizeDeviceId(去横线;长度 ≥32 时去掉前 5 位)。不要让业务层随意造一个 ID。 - 非 RN(Node 脚本等)必须注入
deviceIdProvider,否则会因缺少react-native-device-info抛错。 - IP:
getPublicIp()只是辅助指纹;限流以服务端连接层 IP 为准。 - v2 签发后,服务端会把 地址与 deviceId 绑定,换设备再签会被拒。
const sdk = new CheckInSDK(config, {
authManager: auth,
deviceIdProvider: { getDeviceId: async () => myId },
});分步 API
await sdk.getInfo();
const record = await sdk.getCheckInRecord(address);
const reward = await sdk.getAddressTotalReward(address);
const sign = await sdk.fetchCheckInSign();
const data = sdk.buildCheckInData(sign.deviceId, sign.timestamp, sign.sign);canCheckInToday() 返回的 code 是稳定错误码(如 ADDRESS_ALREADY_CHECKED_IN),
建议接入方优先用 code 判断,不要直接比较合约返回的英文 reason 字符串。
Node 冒烟(不打包 App)
cd web-plugins/checkin
npm install
# 默认连本机 3003、project 5、origin 1170,并广播上链
npm run smoke
# 只测登录 / info / 签发
SMOKE_SKIP_BROADCAST=1 npm run smoke
# 换钱包(需有 gas)
WALLET_JSON=/abs/path/0x....json npm run smoke脚本注入自定义 DeviceIdProvider,用钱包 json 做 personal_sign 与交易签名。
v1 HMAC(仅服务端)
有 apiKey/apiSecret 的机器调用 /api/1.0/checkin/sign。App 不要 走这条。
const sdk = new CheckInSDK({
signServiceUrl, apiKey, apiSecret, rpcUrl, chainId, contractAddress,
});
await sdk.getSign(user, deviceId, timestamp);目录
web-plugins/checkin/
├── src/ CheckInSDK、AuthManager、query、chain、device、types
├── scripts/ smoke-v2.ts
├── README.md
└── UPWARD_INTEGRATION.md