Today, we’re excited to announce Stack’s mainnet launch. Our L3 chain allows us to balance being a low-cost solution for loyalty management with the security of a verifiable blockchain, operating according to Ethereum community standards.
The chain runs a core points protocol that integrates with our points management UI and SDKs. The points protocol will lower costs, reduce platform risk, and increase reliability and security for loyalty management. Developers can learn more about integrating and extending the points protocol from our chain docs.
We are excited to bring loyalty points onchain in a sustainable way, showcasing points as a use case for blockchains that proudly sits alongside stablecoins, NFTs, and other tokens.
Stack first pitched the case for onchain point systems using L3s in October 2023 at the Coinbase Ventures Summit in Malibu. At the time, the only L3 solution was Arbitrum Orbit. Following the presentation we dove into whether L3s would be feasible on Base. While we prototyped our protocol using Orbit, the Base team executed on supporting L3s and Conduit stood out as a reliable service provider.
We are convinced that using a common standard like OP Stack with more developer tooling will reduce risks and that rolling up to Base aligns us with consumer apps who know and trust the Base chain.
Following Ethereum’s rollup-centric roadmap in October 2020, the Ethereum ecosystem has seen a proliferation of new blockchains that provide a variety of security and performance tradeoffs. For example, Zora launched a chain for creative artists, while Base targets consumer crypto apps.
The latest development in blockchain infrastructure is known as a "layer 3 blockchain" or "L3" because it rolls up to a "layer 2" (L2) that, in turn, rolls up to the main Ethereum chain. It is prudent to use these layer classifications for their most suitable applications. While L3s are fully verifiable blockchains, they may not necessarily provide a secure solution for financial applications (also known as DeFi).
We believe that L3s are well-suited for attestations, particularly quantitative attestations in the form of point systems for loyalty programs. Bringing loyalty programs onchain is only possible with scalable, cheap blockchains.
Network Name: Stack
Description: The public mainnet for Stack.
Chain ID: 78225
Currency Symbol: ETH
RPC Endpoint: https://rpc.stack.so
Bridge: https://bridge.stack.so
Block Explorer: https://explorer.stack.so
Points Protocol: 0x000000000c2B4A5816cbb76e9bb3f70D175940A3
Points Interface: IPoints.sol
Observer Interface: IPointsObserver.sol
The Points Protocol is a Solidity smart contract that enables the creation and management of point systems. It provides a flexible and modular approach to implementing point-based systems.
Create multiple point systems, each with its own unique ID
Add and subtract points from user balances within a point system
Retrieve point balances and total points within a point system
Perform batch operations to add or subtract points for multiple users simultaneously
Manage administrators and external contracts (issuers)
Set and retrieve metadata (URI) for each point system
Observe point balance changes through onchain hooks
To interact with the Points Protocol, you can use the [IPoints
interface](https://github.com/stack-so/protocol-interfaces). The contract is deployed at the address 0x000000000c2B4A5816cbb76e9bb3f70D175940A3
.
To create a new point system, call the createPointSystem()
function. It will return the ID of the newly created point system.
addPoints(uint256 systemId, address user, uint256 points)
: Add points to a user’s balance within a specific point system.
subtractPoints(uint256 systemId, address user, uint256 points)
: Subtract points from a user’s balance within a specific point system.
getPoints(uint256 systemId, address user)
: Retrieve the point balance of a user within a specific point system.
getTotalPoints(uint256 systemId)
: Retrieve the total points within a specific point system.
addPointsBatch(uint256 systemId, address[] calldata users, uint256[] calldata points)
: Add points to multiple users’ balances within a specific point system in a single transaction.
subtractPointsBatch(uint256 systemId, address[] calldata users, uint256[] calldata points)
: Subtract points from multiple users’ balances within a specific point system in a single transaction.
addPointsBatchMultipleSystems(uint256[] calldata systemIds, address[] calldata users, uint256[] calldata points)
: Add points to multiple users’ balances across different point systems in a single transaction.
subtractPointsBatchMultipleSystems(uint256[] calldata systemIds, address[] calldata users, uint256[] calldata points)
: Subtract points from multiple users’ balances across different point systems in a single transaction.
addAdmin(uint256 systemId, address admin)
: Add an administrator to a specific point system.
removeAdmin(uint256 systemId, address admin)
: Remove an administrator from a specific point system.
addIssuer(uint256 systemId, address contractAddress)
: Add an external contract (issuer) to a specific point system.
removeIssuer(uint256 systemId, address contractAddress)
: Remove an external contract (issuer) from a specific point system.
setObserver(uint256 systemId, address observer)
: Set an observer contract for a specific point system. The observer will be notified when points are added or subtracted from a user’s balance.
getObserver(uint256 systemId)
: Retrieve the observer contract for a specific point system.
setURI(uint256 systemId, string calldata uri)
: Set the URI (metadata) for a specific point system.
getURI(uint256 systemId)
: Retrieve the URI (metadata) for a specific point system.
The Points Protocol defines several custom errors to handle specific scenarios:
OnlyAdmin(uint256 systemId, address user)
: Thrown when a non-admin user tries to perform an admin-only action.
OnlyIssuer(uint256 systemId, address user)
: Thrown when a non-issuer contract tries to perform an issuer-only action.
InsufficientPoints(uint256 systemId, address user, uint256 available, uint256 required)
: Thrown when a user doesn’t have enough points for a specific operation.
ArrayLengthMismatch()
: Thrown when the lengths of input arrays for batch operations don’t match.
Make sure to handle these errors appropriately in your code.