Reusable Functions
Debugging Techniques#
- Check the versions of dependencies like
ergo-lib-wasm-nodejs
andergo-lib-wasm-browser
to ensure you have the latest fixes. - If an issue is suspected to originate from the Nautilus wallet, try manually replacing the
.wasm
file in the extension directory with an updated version fromsigma-rust
. - Building Nautilus from source with updated dependencies can help identify issues.
- When encountering issues with on-chain boxes, you can try the following:
- Make temporary contract edits (e.g., set a condition to always evaluate to
true
). - Compile the modified contract and obtain the new ErgoTree hex.
- Replace the ErgoTree of the problematic box with the new hex (off-chain).
- Attempt to sign the transaction (this should work locally even if the modified tree wouldn't validate on-chain, helping isolate signing issues).
- For mocking boxes in unit tests, use the
mockUTxO
function from@fleet-sdk/mock-chain
instead of manually editing box contents.
FAQs#
Is the EIP-3 Secret similar to an account index for derived public keys?#
Yes, the EIP-3 secret functions similarly to an account index for deriving public keys. As confirmed by user 'Aberg (Satergo dev)', the Satergo wallet refers to this as the "address index," and custom indices can be utilized.
How do I convert a Coll[Byte] of proposition bytes to the SigmaProp type?#
The decodePoint
method is likely what you need to convert proposition bytes (Coll[Byte]
) into a SigmaProp
.
Can I insert two tokens with the same ID but different amounts into a box?#
Yes, you can, but be aware that some off-chain code might become confused. The amounts will be merged into a single entry in the box's tokens array.
How do I fix the "Tree root should be real but was UnprovenSchnorr(ProveDlog(Ecp(..." error?#
This error usually indicates that the transaction was signed using an incorrect private key (i.e., one that doesn't correspond to the public key expected by the script).
As a complete coding beginner, should I learn Java then Scala before ErgoScript?#
It's generally recommended to focus on understanding UTXO model concepts first, rather than diving deep into Java or Scala initially. The courses available at https://docs.ergoplatform.com/dev/get-started/ provide a good starting point without requiring prior Java or Scala knowledge.
How are dApp fees handled in ErgoScript contracts?#
In ErgoScript, fees are handled explicitly during the transaction building process, not directly within the script logic itself. The script verifies conditions based on the transaction outputs. See the Token Sale Service contract example for illustration: https://github.com/ergoplatform/ergoscript-by-example/blob/main/tokenSalesService.md
Key aspects:
- The transaction fee (
MinTxFee
) must be included in one of the output boxes (typically the last one, designated for the miner). - Other output boxes handle the distribution of payment and token amounts according to the contract's logic.
- The fee is paid from the value contained within the input boxes being spent.
How can Option/Some(...) be used in ErgoScript outside of registers and context variables?#
The use of Option
types (like Some(...)
) is effectively limited to values originating from registers (box.R<N>[Type]
) and context variables (getVar[T](...)
). A potential workaround for other scenarios involves using a "dummy" optional register value and applying a map operation: box.R4[Boolean].map(r => <some expression which doesn't depend on r>)
.
What's the proper syntax for fold/map/reduce operations in ErgoScript?#
Here are some examples demonstrating common collection operations:
// Simple sum using fold with an explicitly defined function
def sumFunc(a: Long, b: Box): Long = a + b.value
val totalValue = INPUTS.fold(0L, sumFunc)
// Using fold with an inline lambda function
val totalValueLambda = INPUTS.fold(0L, { (accum: Long, box: Box) => accum + box.value })
// Declaring a generic function (though type parameter often inferred)
// def sumGeneric[T](a: T, b: Box): T = ??? // Example structure
// val totalGeneric = INPUTS.fold(0L, sumGeneric) // Type parameter usually not needed here
// Note: Upcoming Sigma 6.0 might introduce more direct methods like:
// val total = INPUTS.sumBy(b => b.value)
How can I store a script hash in a register using Fleet for later comparison?#
To store the bytes of a script (ErgoTree) in a register, allowing an ErgoScript contract to later verify that an output box is protected by that specific script:
// In your off-chain Fleet code (JavaScript/TypeScript):
// Create an output box and set register R8 to the hex representation
// of the target script's ErgoTree bytes.
new OutputBuilder(SAFE_MIN_BOX_VALUE, /* Some Address */)
// ... other builder methods
.setAdditionalRegisters({
R8: SConstant(SColl(SByte, ErgoAddress.fromBase58(TARGET_SCRIPT_ADDRESS).ergoTree)).toHex()
});
// In your ErgoScript contract:
{
// Retrieve the expected script bytes from the register
val expectedScriptBytes = SELF.R8[Coll[Byte]].get
// Get the actual script bytes of an output box
val outputBoxScriptBytes = OUTPUTS(0).propositionBytes
// Verify that the output box uses the expected script
expectedScriptBytes == outputBoxScriptBytes
// ... other conditions
}
Noted Issues#
- A bug existed in
sigma-rust
wherecoll.slice
did not gracefully handle empty collections, differing from the Scala version used in nodes. This caused issues for approximately 3 weeks until fixed by user 'greenhat'. The fix has been merged into thedevelop
branch ofsigma-rust
. - This fix needs to propagate through the dependency tree (including updates to libraries like
ergo-lib-wasm
and wallets like Nautilus) before fully resolving issues for all end users. - Some unexpected exceptions have been reported when using
.toBigInt
onLong
register values in ErgoScript. Further investigation is needed. - With ErgoNames, if a token representing a registered name is burned, that name registration is permanently lost. Potential solutions are being researched.
Tutorial Code Snippets#
Summing nanoErgs of all inputs:
// Define a function to add a box's value to an accumulator
def sumValues(accum: Long, box: Box): Long = accum + box.value
// Use fold to apply the sum function across all INPUTS, starting with 0L
val totalNanoErgs = INPUTS.fold(0L, sumValues)
Storing a script hash in a register using Fleet:
// Off-chain code to create an output box storing the target script's hash in R8
const targetAddress = "TARGET_SCRIPT_ADDRESS"; // Replace with the actual address
const targetErgoTreeBytes = ErgoAddress.fromBase58(targetAddress).ergoTree;
new OutputBuilder(SAFE_MIN_BOX_VALUE, /* Some Address */)
.setAdditionalRegisters({
R8: SConstant(SColl(SByte, targetErgoTreeBytes)).toHex()
});
Additional Resources#
- ErgoScript Language Specification: https://github.com/ScorexFoundation/sigmastate-interpreter/blob/develop/docs/LangSpec.md
- Ergo Playground/eScript IDE: https://escript.online/