sequenceDiagram
actor AppOperator
actor B3Admin
AppOperator->>AppRegistry: Register application
loop Every 2 weeks
B3Admin-->>PointsService: Grant points
AppOperator->>PointsService: Transfer points to users
end
yarn add @b3dotfun/b3-points.sdk
npm install @b3dotfun/b3-points.sdk
Intialize the library for AppRegistry.
import {AppRegistry} from '@b3dotfun/b3-points.sdk';
import { B3PointIndexerURLOnB3Sepolia, B3SepoliaAppRegistryContractAddress} from '@b3dotfun/b3-points.sdk'
import { b3Sepolia } from 'viem/chains'
import 'viem/window'
const registry = new AppRegistry(
B3SepoliaPointIndexerURL,
B3SepoliaAppRegistryContractAddress,
b3Sepolia,
);
Intialize the library for B3PointService (BPS).
import {BPS} from '@b3dotfun/b3-points.sdk';
import { B3PointIndexerURLOnB3Sepolia, B3SepoliaPointServiceContractAddress} from '@b3dotfun/b3-points.sdk'
import { b3Sepolia } from 'viem/chains'
import 'viem/window'
const bps = new BPS(
B3SepoliaPointIndexerURL,
B3SepoliaPointServiceContractAddress,
b3Sepolia,
);
Connecting the provider is only required for the write operations that interact with the contract. For listing and other read operations interact with the indexer, and thus connecting to rpc provider is not required.
registry.connect(window.ethereum); // for browser only. For Script registry.connect() to use defaull provider
Contract write call requires wallet account which can be initiated in two ways.
A JSON-RPC Account is an Account whose signing keys are stored on the external Wallet A JSON-RPC Account can just be initialized as an Address string. In the usage below, we are extracting the address from a Browser Extension Wallet (e.g. MetaMask) with the window.ethereum Provider via eth_requestAccounts
import 'viem/window'
const [account] = await window.ethereum.request({
method: 'eth_requestAccounts'
})
A Local Account is an Account whose signing keys are stored on the consuming user's machine. It performs signing of transactions & messages with a private key before broadcasting the transaction or message over JSON-RPC.
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount('0x...')
The register
function allows you to register an application to the AppRegistry. This function returns the app ID.
// Init AppRegistry
// Connect RPC
// Init Account
const appName = 'game.b3.fun';
const operator = '0xFD50b031E778fAb33DfD2Fc3Ca66a1EeF0652165';
const appId = registry.register({
appName: appName,
operator: operator,
account
});
The listApps
function returns all the registered apps. It accepts rankings
and pagination arguments.
You can filter apps by operator
and ensName
// Init AppRegistry
const response = await registry.listApps({
rankings: { direction: "DESC", attribute: "createdAt" },
pageNumber: 1,
pageSize: 10,
});
The grantPoints
function allows B3 admin to grant points to
qualified applications for the upcoming session. This is only callable by B3 Admin.
// Init BPS
// Connect RPC
// Init Account
bps.grantPoints({
requests: [
{appId: 2n, point: 10000},
{appId: 3n, point: 40000},
{appId: 4n, point: 80000},
...
]},
account: account,
);
The transferPoints
function allows app operator to distribute granted points to users only for the current ongoing session. Once finalized (the session is advanced), the points cannot be updated anymore.
// Init BPS
// Connect RPC
// Init Account
const appId = 2n; // app ID for 'game.b3.fun'
const transferUIDs = bps.transferPoints({
appId,
requests: [
{recipient: '', point: 325},
{recipient: '', point: 920},
{recipient: '', point: 21},
...
]},
account: account
);
The app operator can optionally call cancelTransfer
to cancel a pending transfer (that is in the current session) if needed to undo a transfer.
// Init BPS
// Connect RPC
// Init Account
bps.cancelTransfer({
uid: '0xb16fa048b0d597f5a821747eba64efa4762ee5143e9a80600d0005386edfc995'
},
account: account,
);
Advance Session creates a new session
// Init BPS
// Connect RPC
// Init Account
await bps.advanceSession(
account,
);
Returns the total point by the appId. Optionally you can provide session to get total points for the app for that session only.
// Init BPS
const response = await bps.getAppTotalPoints({
appId: 3n,
session: 1n,
});
Returns the total point by the appId after distributing it to the user. Optionally you can provide session to get total points for the app for that session only.
// Init BPS
await bps.getAppAvailablePoints({
appId: 3n,
session: 1n,
});
Returns a list of total points grouped by the appId. Optionally you can provide session to get total points for each app for that session only. You can also provide rankings and pagination arguments.
// Init BPS
const response = await bps.aggregateAppPoints({
session: 1n,
rankings: { direction: "ASC", attribute: "points" },
pageNumber: 1,
pageSize: 10,
});
Returns the points of a user. Provide session to get total points for a session.
// Init BPS
await bps.getUserTotalPoints({
account: "0x....",
});
Returns a list of total points grouped by the user address. Optionally you can provide session to get total points for each user for that session only. You can also provide rankings and pagination arguments.
// Init BPS
const response = await bps.aggregateUserPoints({
appId: 3n,
session: 1n,
rankings: { direction: "DESC", attribute: "points" },
pageNumber: 1,
pageSize: 10,
});
Returns a list of point transfers. Optionally you can provide appId, session, user, status, rankings, and pagination arguments.
// Init BPS
const response = await bps.listPointTransfers({
appId: 3n,
session: 1n,
user: "0x....",
status: "pending",
rankings: { direction: "DESC", attribute: "points" },
pageNumber: 1,
pageSize: 10,
});
For full examples of each operation follow src/example
folder
The transfer-points.ts
file provides functionality to transfer points to multiple recipients using a CSV file. Here's how to use it:
-
Prepare a CSV file with the following format:
recipient_address,points_amount 0x1234...,100 0x5678...,200
Save this file as
transfer-requests.csv
in thesrc/example/bps/
directory. -
Set up your environment:
- Create a
.env
file in the project root. - Add your moderator private key:
MODERATOR_PRIVATE_KEY=your_private_key_here
- Create a
-
Configure the application:
- In the
distributePointsCsv
function, set theappId
to your desired application ID. - Adjust the
filePath
if your CSV file is located elsewhere.
- In the
-
Run the script:
npx ts-node src/example/bps/transfer-points.ts
-
Follow the prompts:
- The script will display information about the transfer requests.
- Confirm the transfer by entering 'y' when prompted.
-
Monitor the output:
- The script will process transfers in batches of 100.
- It will display progress for each batch.
Note: This script filters out recipients who have already received points in the current session to avoid duplicate transfers.