For the complete documentation index, see llms.txt. This page is also available as Markdown.

Run a cyberRAISE round

Create a SAFE round on a cyberCORP, take an investor's Expression of Interest, allocate it and close the round

This guide creates a SAFE round on a cyberCORP's RoundManager, takes an investor's Expression of Interest (EOI), allocates it and closes the round. Allocation issues the investor's SAFE as a Ledger Entry Token (LET). The Round and EOI structs are large, and the snippets show only the fields this flow sets, so check the source for every field.

You need a cyberCORP from Incorporate a cyberCORP: its roundManager address and an officer key.

1. Build the round

A round is a Round struct (RoundLib.sol). Build it by chaining the RoundLib builder's draft(), setTickets and setAgreement.

import {RoundLib, Round, RoundType} from "src/libs/RoundLib.sol";
import {SecuritySeries} from "src/CyberCorpConstants.sol";
using RoundLib for Round;

Round memory round = RoundLib.draft()
    .setTickets(
        SecuritySeries.NA,        // seriesType
        RoundType.FounderApproved,// FCFS or FounderApproved
        false,                    // publicRound
        true,                     // allowTimedOffers
        false,                    // restrictEndTimeReduction
        2_000_000e18,             // raiseCap   (USD, 18 decimals)
        25_000e18,                // minTicket
        500_000e18,               // maxTicket
        USDC,                     // paymentToken
        1e18,                     // pricePerUnit (USD, 18 decimals)
        20_000_000e18,            // valuation
        block.timestamp,          // startTime
        block.timestamp + 30 days // endTime
    )
    .setAgreement(
        TEMPLATE_ID,              // agreement template id
        officer,                  // authorityOfficer
        "Jane Founder",           // officerName
        "Chief Executive Officer",// officerTitle
        legalDetails,             // string[] (one per LET contract)
        roundPartyValues,         // string[]
        extensionData,            // bytes[]  (one per LET contract)
        conditions,               // address[] of ICondition gates
        escrowedSignature         // bytes, the officer's escrowed signature
    );

RoundType.FCFS accepts EOIs first-come. RoundType.FounderApproved requires the officer to allocate each one.

The escrowedSignature is the authorityOfficer's EIP-712 signature over the round's economic parameters (the EscrowedSignatureData struct in RoundManagerStorage.sol), under the domain "RoundManager", version "1", with the RoundManager as verifying contract. createRound recomputes the hash from the draft and reverts InvalidEscrowedSignature if the signature does not verify.

2. Create the round

createRound also creates a LET contract for each CyberCertData entry you pass.

3. Submit the investor's EOI

The investor signs the round's agreement offchain and submits an EOI struct (RoundManagerStorage.sol). The signature is the agreement registry's EIP-712 SignatureData for the EOI agreement that submitEOI creates (the round's template, the investor's salt and secretHash, and the RoundManager as finalizer), with the investor as signer. Sign a cyberAgreement gives the typed data. The registry verifies the signature inside submitEOI, so a signature over the wrong id or type reverts the whole call.

4. Allocate the EOI

In a founder-approved round the officer allocates each accepted EOI. An FCFS round allocates inside submitEOI, so it skips this step. allocate prices the ticket, mints a SAFE LET from each of the round's LET contracts, attaches the officer's escrowed signature and an endorsement, and refunds any rounding dust.

5. Close the round

closeRoundNow closes the round before its endTime. Without it, the round closes at endTime.

The investor now holds a SAFE LET. To trade it, run a secondary trade through the DealManager or scripify it and settle in scrip. Function-level detail is in RoundManager.

Last updated

Was this helpful?