Generating Reports: Single Values
This guide shows how to manually generate a CRE report containing a single value (like uint256, address, or bool). See Key Terms: Report for the full definition; in short, it is a DON-signed package from runtime.GenerateReport() / runtime.report() with your encoded data, workflow metadata, and signatures.
This guide covers creating the signed report (runtime.GenerateReport() / runtime.report()). Delivering it is a separate step: see the table below.
Use this approach when:
- You're sending a single primitive value (like
uint256,address,bool,bytes32) to your consumer contract - You don't have (or need) binding helpers for your contract
Don't meet these requirements? See the Onchain Write page to find the right approach for your scenario.
Prerequisites
- Familiarity with Working with Solidity input types
What this guide covers
Manually generating a report for a single value involves two main steps:
- ABI-encode the value into bytes using the
go-ethereum/accounts/abipackage - Generate a cryptographically signed report using
runtime.GenerateReport()
After GenerateReport() / report() | Guide | Who verifies? |
|---|---|---|
WriteReport() / writeReport() | Submitting Reports Onchain | KeystoneForwarder onchain |
SendReport() / sendReport() | Submitting Reports via HTTP | Receiver: Verifying CRE Reports Offchain or your API |
See API Interactions: CRE reports over HTTP for the sender → receiver mental model.
Step-by-step example
1. Create your value
Start with a Go value that you want to send. For example, a *big.Int for a Solidity uint256:
import "math/big"
myValue := big.NewInt(123456789)
logger.Info("Value to send", "value", myValue.String())
2. ABI-encode the value
Use the ethereum/go-ethereum/accounts/abi package to encode your value as a Solidity type:
import "github.com/ethereum/go-ethereum/accounts/abi"
// Create the Solidity type definition
uint256Type, err := abi.NewType("uint256", "", nil)
if err != nil {
return fmt.Errorf("failed to create type: %w", err)
}
// Create an arguments array with your type
args := abi.Arguments{{Type: uint256Type}}
// Pack (encode) your value
encodedValue, err := args.Pack(myValue)
if err != nil {
return fmt.Errorf("failed to encode value: %w", err)
}
3. Generate the report
Use runtime.GenerateReport() to create a signed, consensus-verified report from the encoded bytes:
reportPromise := runtime.GenerateReport(&cre.ReportRequest{
EncodedPayload: encodedValue,
EncoderName: "evm",
SigningAlgo: "ecdsa",
HashingAlgo: "keccak256",
})
report, err := reportPromise.Await()
if err != nil {
return fmt.Errorf("failed to generate report: %w", err)
}
logger.Info("Successfully generated report")
Field explanations:
EncodedPayload: The ABI-encoded bytes from step 2EncoderName: Always"evm"for Ethereum reportsSigningAlgo: Always"ecdsa"for EthereumHashingAlgo: Always"keccak256"for Ethereum
Understanding the report
The runtime.GenerateReport() function returns a *cre.Report object. This report contains:
- Your ABI-encoded data (the payload)
- Cryptographic signatures from the DON nodes
- Metadata about the workflow (ID, name, owner)
- Consensus proof that the data was agreed upon by the network
This report is designed to be passed directly to either:
evm.Client.WriteReport()for onchain deliveryhttp.Clientfor offchain delivery
4. Submit the report
Now that you have a generated report, choose where to send it:
- Submit it to the blockchain via
evm.Client.WriteReport() - Send it via HTTP via
http.Clientfor offchain delivery
Complete working example
Here's a workflow that generates a report from a single uint256 value:
//go:build wasip1
package main
import (
"fmt"
"log/slog"
"math/big"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron"
"github.com/smartcontractkit/cre-sdk-go/cre"
"github.com/smartcontractkit/cre-sdk-go/cre/wasm"
)
type Config struct {
Schedule string `json:"schedule"`
}
type MyResult struct {
OriginalValue string
EncodedHex string
}
func InitWorkflow(config *Config, logger *slog.Logger, secretsProvider cre.SecretsProvider) (cre.Workflow[*Config], error) {
return cre.Workflow[*Config]{
cre.Handler(cron.Trigger(&cron.Config{Schedule: config.Schedule}), onCronTrigger),
}, nil
}
func onCronTrigger(config *Config, runtime cre.Runtime, trigger *cron.Payload) (*MyResult, error) {
logger := runtime.Logger()
// Step 1: Create a value
myValue := big.NewInt(123456789)
logger.Info("Generated value", "value", myValue.String())
// Step 2: ABI-encode the value as uint256
uint256Type, err := abi.NewType("uint256", "", nil)
if err != nil {
return nil, fmt.Errorf("failed to create type: %w", err)
}
args := abi.Arguments{{Type: uint256Type}}
encodedValue, err := args.Pack(myValue)
if err != nil {
return nil, fmt.Errorf("failed to encode value: %w", err)
}
logger.Info("ABI-encoded value", "hex", fmt.Sprintf("0x%x", encodedValue))
// Step 3: Generate report
reportPromise := runtime.GenerateReport(&cre.ReportRequest{
EncodedPayload: encodedValue,
EncoderName: "evm",
SigningAlgo: "ecdsa",
HashingAlgo: "keccak256",
})
report, err := reportPromise.Await()
if err != nil {
return nil, fmt.Errorf("failed to generate report: %w", err)
}
logger.Info("Report generated successfully")
// At this point, you would typically submit the report:
// - To the blockchain: see "Submitting Reports Onchain" guide
// - Via HTTP: see "Submitting Reports via HTTP" guide
// For this example, we'll just return the encoded data for verification
_ = report // Report is ready to use
// Return results
return &MyResult{
OriginalValue: myValue.String(),
EncodedHex: fmt.Sprintf("0x%x", encodedValue),
}, nil
}
func main() {
wasm.NewRunner(cre.ParseJSON[Config]).Run(InitWorkflow)
}
Best practices
- Always check errors: Both encoding and report generation can fail—handle both error paths
- Use the correct Solidity type string: Type mismatches will cause ABI encoding failures. Verify your type strings match your contract exactly
- Log the encoded data: For debugging, log the hex-encoded bytes to verify your data is encoded correctly:
logger.Info("ABI-encoded value", "hex", fmt.Sprintf("0x%x", encodedValue)) - Refer to go-ethereum documentation: For complex types, consult the go-ethereum ABI package documentation
Troubleshooting
"failed to create type" error
- Verify the type string exactly matches Solidity syntax.
- For arrays, use
uint256[]for dynamic arrays oruint256[3]for fixed-size arrays. - Check the go-ethereum type documentation for supported types.
"failed to encode value" error
- Ensure your Go value matches the Solidity type (e.g.,
*big.Intforuint256,common.Addressforaddress). Find a list of mappings here. - For integers, use
big.NewInt()for values that fit inint64, ornew(big.Int).SetString()for larger values. - Verify you're packing the value with
args.Pack(myValue), not passing it directly.
Report generation succeeds but onchain submission fails
- This guide only covers report generation. See Submitting Reports Onchain for troubleshooting submission issues.
Learn more
- Onchain Write Overview: Understand all onchain write approaches
- Submitting Reports Onchain: Submit your generated report to the blockchain
- Generating Reports: Structs: Manually encode and generate reports for struct data
- Building Consumer Contracts: Create contracts that can receive your reports
- EVM Client Reference: Complete API documentation