Configure your smart contract
Verifying attestations
Digital signatures
Spearmint produces digital signatures by encoding the user's address (along with extra attestation data if applicable) into a message following EIP-191.
The message is signed using a randomly generated signer, the address for which is available on the Signatures subtab in the Developers section. This is the signer address that you will use in your smart contract to verify Spearmint signatures.

Note: you can roll to a new signer address at any time you wish. This option may be helpful if you've accidentally exposed your API before things were ready, and you fear that some people have grabbed a hold of the signatures prematurely. This will happen (hopefully) rarely in practice, but it's a good idea to work in the ability to update the signer address on your contract just in case.
The following example shows one way to verify Spearmint signatures in your smart contract. The AttestationData
struct used below can be conveniently copied from the Project subtab in the Developers section (see Set your attestation schema). The SignatureAttestable
contract used below, along with accompanying tests, can be found in this example repo.
Please Note!
This piece of code (and those in the example repo) is for demonstration purposes only and is not to be copied and pasted into production code without careful review.
// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;
import "./attestable/SignatureAttestable.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract SignatureClaimWithAttestationData is ERC20, SignatureAttestable {
struct AttestationData {
uint256 validAt;
uint256 quantity;
}
constructor(
address signerAddress
) ERC20("Spearmint", "SPEAR") SignatureAttestable(signerAddress) {}
function claim(
AttestationData calldata data,
bytes calldata signature
) external onlyValidSignature(_getHashedData(data), signature) {
if (data.validAt > block.timestamp) {
revert ClaimNotYetAvailable();
}
// TODO: Mark as claimed.
_mint(msg.sender, data.quantity);
}
function _getHashedData(
AttestationData calldata data
) internal view returns (bytes32 hashedData) {
hashedData = keccak256(abi.encode(msg.sender, data));
}
error ClaimNotYetAvailable();
}
Merkle proofs
On Spearmint, you can generate Merkle trees against which an address on the allowlist will be able to generate a Merkle proof to send to your smart contract. Unlike the digital signatures approach, a generated Merkle tree will be an immutable snapshot of the addresses (along with extra attestation data if applicable) at the time of generation and any changes to the entries or attestation schema/data will require a generation of a new Merkle tree.
The root hash of the generated Merkle tree can be copied by expanding the accordion for the given tree under the Merkle trees subtab. This is the root hash that you will use in your smart contract to verify Spearmint Merkle proofs.

The following example shows one way to verify Spearmint Merkle proofs in your smart contract. The AttestationData
struct used below can be conveniently copied from the Project subtab in the Developers section (see Set your attestation schema). The MerkleProofAttestable
contract used below, along with accompanying tests, can be found in this example repo.
Please Note!
This piece of code (and those in the example repo) is for demonstration purposes only and is not to be copied and pasted into production code without careful review.
// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;
import "./attestable/MerkleProofAttestable.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MerkleProofClaimWithAttestationData is ERC20, MerkleProofAttestable {
struct AttestationData {
uint256 validAt;
uint256 quantity;
}
constructor(
bytes32 rootHash
) ERC20("Spearmint", "SPEAR") MerkleProofAttestable(rootHash) {}
function claim(
AttestationData calldata data,
bytes32[] calldata proof
) external onlyValidProof(_getHashedData(data), proof) {
if (data.validAt > block.timestamp) {
revert ClaimNotYetAvailable();
}
// TODO: Mark as claimed.
_mint(msg.sender, data.quantity);
}
function _getHashedData(
AttestationData calldata data
) private view returns (bytes32 hashedData) {
hashedData = keccak256(abi.encode(msg.sender, data));
}
error ClaimNotYetAvailable();
}
Updated about 1 month ago