Aere Network public source. Everything here can be checked against the live chain (chain id 2800, https://rpc.aere.network). Scope note, stated up front rather than buried: consensus on chain 2800 is classical secp256k1 ECDSA QBFT. The post-quantum work in this repository is at the signature, precompile, account and transport layers. Nothing here makes the consensus post-quantum, and no document in it should be read as claiming so.
64 lines
2.7 KiB
Solidity
64 lines
2.7 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.23;
|
|
|
|
import "./AereRandomnessBeacon.sol";
|
|
|
|
/**
|
|
* @title AereDrandConsumer
|
|
* @notice Reference example of consuming verifiable randomness on AERE.
|
|
* Pattern: dApp picks a future drand round, waits for it to be
|
|
* submitted (by anyone — typically the dApp itself), then reads
|
|
* the randomness.
|
|
*
|
|
* This is a minimal lottery — illustration only, not a production lottery.
|
|
* Any dApp on AERE can use the same pattern. Two lines of integration code.
|
|
*/
|
|
contract AereDrandConsumer {
|
|
AereRandomnessBeacon public immutable beacon;
|
|
uint64 public targetRound;
|
|
bytes32 public winnerSeed;
|
|
|
|
event RandomnessCommitted(uint64 targetRound, uint64 willResolveAt);
|
|
event RandomnessRevealed(uint64 round, bytes32 randomness, bytes32 winnerSeed);
|
|
|
|
constructor(AereRandomnessBeacon _beacon) {
|
|
beacon = _beacon;
|
|
}
|
|
|
|
/**
|
|
* @notice Commit to a future drand round as the source of randomness.
|
|
* The round must be in the future at commit time so its
|
|
* signature cannot already be known.
|
|
*/
|
|
function commitToFutureRound(uint64 minSecondsInFuture) external returns (uint64) {
|
|
uint64 targetTime = uint64(block.timestamp) + minSecondsInFuture;
|
|
targetRound = beacon.roundAtTime(targetTime);
|
|
emit RandomnessCommitted(targetRound, beacon.DRAND_GENESIS() + targetRound * beacon.DRAND_PERIOD());
|
|
return targetRound;
|
|
}
|
|
|
|
/**
|
|
* @notice Reveal the random outcome. Caller submits the drand signature
|
|
* for `targetRound` (anyone can; signature is public on api.drand.sh).
|
|
*/
|
|
function reveal(bytes calldata signature) external returns (bytes32 randomness) {
|
|
require(targetRound != 0, "Consumer: not committed");
|
|
randomness = beacon.submitRound(targetRound, signature);
|
|
// Derive the winnerSeed deterministically from the randomness + this contract.
|
|
winnerSeed = keccak256(abi.encodePacked(randomness, address(this), targetRound));
|
|
emit RandomnessRevealed(targetRound, randomness, winnerSeed);
|
|
}
|
|
|
|
/**
|
|
* @notice If the round has already been submitted by someone else,
|
|
* just consume it without paying gas for re-submission.
|
|
*/
|
|
function consumeExistingRound() external returns (bytes32 randomness) {
|
|
require(targetRound != 0, "Consumer: not committed");
|
|
randomness = beacon.getRandomness(targetRound);
|
|
require(randomness != bytes32(0), "Consumer: round not submitted yet");
|
|
winnerSeed = keccak256(abi.encodePacked(randomness, address(this), targetRound));
|
|
emit RandomnessRevealed(targetRound, randomness, winnerSeed);
|
|
}
|
|
}
|