Contract Changelog
Available updates to NFD Contracts will be documented here.
Users may 'lock' their NFD via Edit->Contract Version - 'Toggle Contract Lock'. If this is set, the contract can not be upgrade by NFDomains to add new features or fix security issues. If new contract versions are available and your NFD isn't expired, you can always unlock, and upgrade.
All NFDs MUST upgrade to 2.11(+) in order to allow any changes because of new storage model.
Current deployed contract versions:
betanet / testnet / mainnet : 3.8 [all new NFDs]
3.8
Fixed bug in segment pricing where treasury wasn't getting proper amounts compared to root owner for multi-year mints.
3.5 - 3.7: Released as 3.7
Fixed bug in setPrimaryAddress - it allowed someone other than owner to change the order (couldn't 'change/add/remove addresses' - could only change the order)
If NFD is for sale and then expires, disallow purchase, and clear 'for-sale' info when renewed.
If NFD was still for sale once it expired, then clearing of fields (necessary to renew by another user) was being blocked.
Fixed bug in not being able to unlink an address for an expired NFD via registry. Clearing of all data in an NFD is necessary before it can be renewed by a different owner (to take over ownership). Unlinking being blocked unless owner did it over which would happen if different owner tries to buy expired nfd)
3.4 Tracking/Updating of 'nfds owned by' box storage
The registry and NFDs will now create box values that will make it easier in the future to fetch all NFDs owned by a particular address via off-chain algod state fetches. While it won't support NFDs prior to 3.x, it provides a path forward for fetching owned NFDs without having to maintain an independent index and tracking of on-chain state changes.
3.3 Renewal model and Self-Minting GA (09/02/2024)
The changes are quite significant (rewriting from PyTeal to Tealscript for one) but at a high level, NFDs themselves are the same with use of global state and box storage not changing.
A new internal property was added in NFDS to track expiration time. If it doesn't exist, then the NFD is v1 or v2 and doesn't expire. V3 NFDs will always have an expiration set in the i.expirationTime property.
Expired NFDs can be renewed by the owner without having to first clear data. Anyone else can renew the NFD if expired but the NFD must be clear of all data first. If someone not the existing owner tries to renew the NFD, there is a 28 day reverse-auction pricing model where the price to renew scales from $100K down to the regular price over 28 days. The existing owner can just renew at base price at any time.
The registry itself now contains the byte code for NFDs and acts as a factory, controlling the minting of new NFDs, creating and assigning into the registry as part of a single mintNfd method. Previously TxnLab had to sign certain transactions as part of minting to ensure contract authenticity. With box storage, the Registry itself can now handle everything. All pricing and all minting is controlled entirely through the registry contract alone.
New NFDs will always be renewal based, with an expiration time equal to the proportional number of days the paid amount buys vs the yearly cost of that NFD. Expiration times can't go beyond 20 years into the future.
2.11 Box storage & NFD Vaults
Box Storage in NFDs and the NFD Global Registry contract.
The registry goes from local state in logic-sig accounts (per name and address lookup) to box storage per name and address in the registry.
Moving away from 'Global/Local State' in NFDs to new Algorand 'Box' storage. This will lower the carry cost as well as allow near unlimited properties in an NFD. Users will now 'pay as they go' for the MBR (Minimum Balance Requirement) of box storage for their metadata. Field additions/updates will add ALGO to the NFD contract account (only) as necessary to cover the required MBR of the additions to storage.
Internal properties remain in global state. (ie: i.name, i.owner, etc.)
User-defined and Verified NFD properties (u.xxxx / v.xxx) move to box storage
Limited to just under 2K each (up from 128 bytes). 2K is maximum size of arguments for any application call. The backend/api will still handle breaking larger values across properties - so an 7K value would be transparently split across 4 boxes (and combined on read) ie: u.preferences_00, u.preferences_01, u.preferences_02, u.preferences_03
1.x contracts all go completely read-only in the interface. Users upgrading their NFD to 2.x contract will migrate the name and addresses to the new registry (box) storage as well as all of the fields from global state to boxes.
Vault support added
Allows sending assets TO the NFD Vault account (the contract account that's 1:1 tied to each NFD - controlled by the NFD owner). The NFD Vault will auto opt-in to assets, allowing airdrops for the first time in Algorand.
The vault is 'locked' by default. When locked, only the owner can send assets into their vault (from owner account).
The owner can unlock the vault, in which case anyone can send to the vault, but they must also cover the .1 MBR cost of the vault in order to send the asset by sending .1 in prior transaction in an atomic transaction group.
Pricing slightly changed. The carry cost (MBR) of the contracts is now charged on top of the USD price of NFD roots. Previously it was part of the gross amount. However, the carry cost has dropped from 5 ALGO to 2 ALGO because of the switch to box storage (which is now 'pay as you go').
Additional updates during betanet/testnet:
2.2 Adds ability to set optionally set note in 'send from vault' transactions.
2.3 The box name for algo addresses is now based on a hash sha256(addr/algo/{32 byte pk})
2.4
Change vault_optin to allow multiple assets to be opted-in as a batch
vault_optin no longer pays back if already opted-in - its callers responsibility to know. Expectation is .1 * asset(s) opted-in
2.5
Changed to allow NFDomains to set verified avatar of an NFD still in pre-claim state, allowing avatars to be set for auction items
When putting up for sale, don't force '0 boxes' rule if still pre-claim and nfdomains is caller (this is so avatar can be set for nfd during auction re-pricing]
2.6 - Allow batch sends of multiple assets per txn 'from' a vault
2.7 - Added method to allow combining global state key values into new single box - used for v1->v2 migration of v.caAlgo.*.as to v.caAlgo.0.as
2.8 - Changed vault lock/unlock to allow setting a 'unlock UNTIL x' option in parameter. str:0 to unlock, str:1 to lock, or int:xxxx (timestamp in seconds) to unlock but specify a time at which the vault automatically re-locks. This is useful for 'allow airdrops for... 1 hour' sort of requests.
2.9 - Added read_property method for reading an NFD property via simulate calls or via c2c calls.
2.10 - Modified the fieldname used for 2-stage address verification - u.cav.algo is now u.cav.algo.a to properly reflect the 32-byte PK storage type.
2.11 - the default for Vaults will now be UNLOCKED. Purchasing also resets to the UNLOCKED default.
1.16 GA rollout of Segments feature
Added additional asserts in segment_lock / contract_lock calls.
Updated make_offer method (AKA: Purchase / Claim) to accept additional optional parameter, on whether to 'opt out' of receiving the NFD's NFT. Pass string "0" to opt-out. This is mainly for large projects, minting a significant number of segments in a central account and not wanting the extra MBR requirements on the owning account.
1.13 / 1.14 / 1.15 (beta segments)
Prevent segment minting, even by owner, if root is for sale.
Minimum segment price is now 400 ($4.00) Segment Discount table is now:
- Number MintedDiscount RatePrice (USD)
$ 4.00
10
20%
$ 3.20
100
30%
$ 2.80
1,000
40%
$ 2.40
10,000
50%
$ 2.00
100,000
60%
$ 1.60
1,000,000
70%
$ 1.20
Added ability to control/mint segments off of root NFDs - price is set in USD.
ALGO/USD price retrieved from new ALGO/USD contract w/ price regularly updated by NFDomains.
Added segment_lock method - allowing locking of NFD, or unlocking of NFD with USD price in cents.
str: segment_lock
str: 1 (to lock), 0 (to unlock)
int: {usd price in cents - ie: 300 for $3.00)
Added update_segment_count method to NFD - for updating i.segmentCount of parent when a segment is minted from it. Part of mint txn group - validates already created (in group) child is proper subset and is formally an NFD and registered properly on-chain via LSIG lookup/state data.
str: update_segment_count (parent of segment is called)
str: {child nfd name}
Updated create method to take additional arguments related to segment minting (if a segment) - parent NFD ID and address to get excess proceeds from sale (segment seller) if parent was open segment.
additional args:
int: {parent app id of segment or 0}
addr: {open segment parent seller or zero address}
1.12
Added escrow_offer contract call - which is only allowed pre-claim Auction NFDs and which provides ability for users to escrow sequentially higher 'floor' bids for auctions.
Two paired transactions in a group are required in the call.
[0]: payment to NFD's Account (nfdAccount property in metadata - the "Application account" natively)) of the offer.
[1]: Contract call to the NFD w/ 2 args:
escrow_offer
{offer amount as 8-byte Big-Endian - Itob format}
fee: 1 extra txn of fee needs to be added (ie: .002 total) to cover possible inner transaction cost inside the escrow_offer method to refund prior escrow.
Assuming the offer is at at least+10 the current highest floor (if set), then the sender is set in the i.mintingKickoffCreator.a property and the amount is set in i.mintingKickoffAmount.
If there was another floor already set in mintingKickoffCreator.a then they're refunded their bid as only one highest bid at a time is allowed for the 'floor' price of the dutch auction.
1.11
If buyer pays more than the sell amount of the NFD, refund the difference to the buyer via an inner-transaction in the make_offer NFD contract call. This should only happen if the user is paying for a dutch auction and the user pays the higher 'tick' amount yet the contract has just been re-priced. Think of it somewhat like slippage in DEXs. Now if the user ever overpays it just sends the excess immediately back in the same transaction. The user only pays .001 extra to cover the possible inner-transaction fee.
1.10
If NFD ASA is not in seller account, check NFD account instead when clawing to the buyer. The ASA can only be returned to the NFD account (the ASA's creator) if the owner 'closed the asset' - sending it back to its creator - the NFD account. In 1.08, this prevents the NFD from being sold, as the NFD will fail trying to send the asset from the seller to the buyer, as the asset won't be in the sellers account.
1.09
Update contract so that NFDomains can ONLY clear userDefined fields (as part of moving to verified, or to clear metadata prior to sale).
Previously, NFDomains could change the value even though this was never done. This change ensures it is enforced in the contract code.
1.08
The GA release contract version.
Last updated