# Welcome!

Transient Labs is the premier digital art platform on Ethereum.

### Mission

Transient Labs empower digital artists with the leading onchain toolkit and marketplace. We create sovereign tools that give artists the control of their work. Create, list, and sell on Transient.

### Partnerships

We are always looking to partner with the right artists, platforms, projects, and more! If you're interested, please email <team@transientlabs.xyz>. We look forward to hearing from you!


# Creator Contracts Overview

TL Creator Contracts offer unmatched innovation and gas efficiency while adhering to NFT standards.

## General Contract Details

### Creator Sovereignty

All Creator Contracts are owned by the creator. Full stop. There is no other option.

### Proxy Pattern

TL Creator Contracts are [ERC-1167](https://eips.ethereum.org/EIPS/eip-1167) immutable proxies in order to allow for cheap deployment costs, customization, and transparency. After deployment, the contract logic is not upgradeable and if any new implementation contracts are released, creators must deploy a new contract.&#x20;

For more background on proxy patterns in, checkout this [great article](https://blog.openzeppelin.com/proxy-patterns/) from OpenZeppelin.

For how to deploy our contracts, read more [here](/integrations/deploying-tl-contracts).

### Security

All Transient Labs contracts inherit either from code we have written, or the battle-tested and audited [OpenZeppelin](https://openzeppelin.com/) contracts. We take security very seriously and utilize fuzz testing with a minimum of 10,000 runs prior to any release.

## Source Code

The source code for the TL Creator Contracts can be found on our GitHub.&#x20;

<https://github.com/Transient-Labs/tl-creator-contracts>


# Implementation Contracts

The latest implementation addresses for our creator contracts.

The latest implementation addresses are listed here for each token type. Contracts are deployed with `CREATE2` opcodes and thus the implementation addresses are the same across [supported chains](/miscellaneous/supported-blockchains).

<table><thead><tr><th width="157">Type</th><th>Address</th></tr></thead><tbody><tr><td>ERC721TL</td><td>0x72be8d37610ee69c72a50fa9728cb4a795fbcf38</td></tr><tr><td>ERC1155TL</td><td>0xe99fe9606b76a42b7ed69e13c6abbadb462626b8</td></tr><tr><td>ERC7160TL</td><td>0x95c79af9e585751069fd710e05c78fbeb7679827</td></tr><tr><td>Doppelganger</td><td>0x053f8f66936e306cc8a5b24f2c111e90891f588e</td></tr><tr><td>Collector's Choice</td><td>0x96310a20ffb00e0d1d29fc44cabed721d0fa7ee1</td></tr><tr><td>Shatter</td><td>0xc41ea82091fe01dd3a853cad2e766e924e49f653</td></tr></tbody></table>


# v4.x.x

Version 4.x.x contracts are deployed with `CREATE2` opcodes and thus the implementation addresses are the same across [supported chains](/miscellaneous/supported-blockchains). v4 introduced enforceable royalties.

## ERC721TL

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>4.1.0</td><td><code>0x44a46be01bf45358bbc850a1fa1e1fa390756166</code></td></tr><tr><td>4.0.0</td><td><code>0x86d8608c912be35a81b21aa692d67eb73d173daa</code></td></tr></tbody></table>

## ERC1155TL

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>4.1.0</td><td><code>0xb91995d6efd3d9fd1598867fd17949344c418e93</code></td></tr><tr><td>4.0.0</td><td><code>0x5e5adf596209bd9e5c2d489216c7d3075ad17860</code></td></tr></tbody></table>

## ERC7160TL

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>4.1.0</td><td><code>0x8c60e11572d4a6c238792cd84ec5ef910f073ea2</code></td></tr><tr><td>4.0.0</td><td><code>0x9c397afe50423048f40274385246cbf930e9477b</code></td></tr></tbody></table>


# v3.x.x

Version 3.x.x contracts are deployed with `CREATE2` opcodes and thus the implementation addresses are the same across [supported chains](/miscellaneous/supported-blockchains).

## ERC721TL

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>3.4.0</td><td>0x516b8ca95eb59e7a69d79a27522ed63fcbe22b64</td></tr><tr><td>3.1.0</td><td>0xd631b04e8fdbe152ee4c05273588f444efdedfaf</td></tr><tr><td>3.0.1</td><td>0x72be8d37610ee69c72a50fa9728cb4a795fbcf38</td></tr><tr><td>3.0.0</td><td>0x610538c97f8049b2bfa30990c66eb98b046ff336</td></tr></tbody></table>

## ERC1155TL

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>3.1.0</td><td>0xe4c2c3f4a96f848dabffd2a69fb19675ae9c9cbc</td></tr><tr><td>3.0.1</td><td>0xe99fe9606b76a42b7ed69e13c6abbadb462626b8</td></tr><tr><td>3.0.0</td><td>0x4b699189317c4ddea27661d16cfe28911c032776</td></tr></tbody></table>

## ERC7160TL

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>3.1.1</td><td>0x8bb44dc96d222f170efea8a60a389bd5c0c886a5</td></tr><tr><td>3.1.0</td><td>0xccbf31e3e7853709a40f9bc5f319afae6ba968a6</td></tr><tr><td>3.0.1</td><td>0x95c79af9e585751069fd710e05c78fbeb7679827</td></tr><tr><td>3.0.0</td><td>0x5eb2d9ea72b597a06d3f67ecb09fe13eb0954c9f</td></tr></tbody></table>

## Shatter

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>3.1.0</td><td>0xdae91e055bcc3a40c6154a003abc82d967627726</td></tr><tr><td>3.0.1</td><td>0xc41ea82091fe01dd3a853cad2e766e924e49f653</td></tr><tr><td>3.0.0</td><td>0x7f82c6aaef0779e03c7c731522c517787798d4dd</td></tr></tbody></table>

## Doppelganger

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>3.1.1</td><td>0xc3225e41e5c88277e637f5298c9932b89d6ec3fa</td></tr><tr><td>3.1.0</td><td>0x78891719d07a2610d1c27ff40cd4eb40a6ee3ef6</td></tr><tr><td>3.0.1</td><td>0x053f8f66936e306cc8a5b24f2c111e90891f588e</td></tr><tr><td>3.0.0</td><td>0xf98ef02b606ecc210e3d35cd4731b69bad880c8e</td></tr></tbody></table>

## Collector's Choice

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>3.1.1</td><td>0x8e163c6145182123ae55a5dbe386ac58bcf9e984</td></tr><tr><td>3.1.0</td><td>0x63f90b43dad3d82d69bc95f36523972cbb6c3c2a</td></tr><tr><td>3.0.1</td><td>0x96310a20ffb00e0d1d29fc44cabed721d0fa7ee1</td></tr><tr><td>3.0.0</td><td>0xcc9fcb4b2dddd6f91eac68c5a4a4d72c80c9b8a7</td></tr></tbody></table>


# v2.x.x

Version 2.x.x of TL Creator Contract

## ERC721TL

### Ethereum

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>2.3.0</td><td>0x12Ab97BDe4a92e6261fca39fe2d9670E40c5dAF2</td></tr><tr><td>2.5.0</td><td>0x154DAc76755d2A372804a9C409683F2eeFa9e5e9</td></tr><tr><td>2.10.1</td><td>0xD724c9223760278933A6F90c531e809Ec1Baca1c</td></tr></tbody></table>

### Arbitrum One

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>2.3.0</td><td>0x0E841ae8f9CCDa3bDC14780216B974a477978Fec</td></tr><tr><td>2.5.0</td><td>0x3C96779d00fA48439Ecb91A0323ee7A936E6859E</td></tr><tr><td>2.10.1</td><td>0xca99678048a9554C2B9798c66d866AF0295594ae</td></tr></tbody></table>

### Goerli

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>2.3.0</td><td>0x403201aC548dba0e889148137dab984b71230F6c</td></tr><tr><td>2.5.0</td><td>0x372f9bd6003b08DE19223e96AD8ef1A35cD8bcbF</td></tr><tr><td>2.10.1</td><td>0xc1F55dfCdA28bf10C3dC1ACA10bc8Dc85f73d976</td></tr></tbody></table>

### Arbitrum Goerli

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>2.3.0</td><td>0x00059878282ec217c761F20e668932D1A7f3bb97</td></tr><tr><td>2.5.0</td><td>0x894bC02f9424B8Ab882F787912e173e7fAcA0065</td></tr><tr><td>2.10.1</td><td>0x3C33Ec85c30C270904c3d55a7d11F42dC06F6F76</td></tr></tbody></table>

***

## ERC7160TL

### Ethereum

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>2.10.0</td><td>0x2eb9B14677Df35998A4393cDefab352b526239eB</td></tr><tr><td>2.10.1</td><td>0x4c5046FbD2bfc678B6AB140ce2468BF79f4e8008</td></tr></tbody></table>

### Aribtrum One

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>2.10.0</td><td>0x7eFF56e3dBEb5ec6056Da79b70281Efba295d7B7</td></tr><tr><td>2.10.1</td><td>0x3569631dBfBfd48CDa963C565Fe6b06870C2B1B1</td></tr></tbody></table>

### Goerli

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>2.10.0</td><td>0x68920FB653c57730b8eb7E61F72aC67C3D2Dfe5d</td></tr><tr><td>2.10.1</td><td>0x21229867EdC1df541e85A38D5d97C3b34A4d4b1A</td></tr></tbody></table>

### Arbitrum Goerli

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>2.10.0</td><td>0xc192C96aE16E81a06cA4e52046C8c79aBAd63EB9</td></tr><tr><td>2.10.1</td><td>0xca330F1b9f59199b251059c9c9B3b6754Eef1D69</td></tr></tbody></table>

***

## ERC1155TL

### Ethereum

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>2.3.0</td><td>0xAa6AB798c96f347f079Dd2148d694c423aea8C81</td></tr></tbody></table>

### Aribtrum One

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>2.3.0</td><td>0xaD5AA880f860a88605c23869bA12428958d7cB3E</td></tr></tbody></table>

### Goerli

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>2.3.0</td><td>0x41EE8562c0483cB81B2Ef81C2fEF14A266F3b136</td></tr></tbody></table>

### Arbitrum Goerli

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>2.3.0</td><td>0x0E841ae8f9CCDa3bDC14780216B974a477978Fec</td></tr></tbody></table>

***

## Shatter

### Ethereum

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>2.5.0</td><td>0x996B0EE86c6817DD4d627d23CAe1a58e37E9a702</td></tr></tbody></table>

### Aribtrum One

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>2.5.0</td><td>0xa534769e68B4c5cc06cF4b12AFf51f90C5068893</td></tr></tbody></table>

### Goerli

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>2.5.0</td><td>0x95860a851A0e0dC12390dcB74Db69d1cBC4b00ef</td></tr></tbody></table>

### Arbitrum Goerli

<table><thead><tr><th width="125">Version</th><th>Address</th></tr></thead><tbody><tr><td>2.5.0</td><td>0x722456B934CCB958835553Ff1ec85b9E8E986A91</td></tr></tbody></table>


# v1.x.x

## ERC721TL

### Ethereum

<table><thead><tr><th width="113">Version</th><th>Address</th></tr></thead><tbody><tr><td>1.0.0</td><td>0x2De0972Fcd8ab0788697f92984b0D578F4c9ECA3</td></tr><tr><td>1.1.0</td><td>0xFb1647BD77D28d0aCAB0c3632CeEF87E7CD62b04</td></tr></tbody></table>

### Goerli

<table><thead><tr><th width="113">Version</th><th>Address</th></tr></thead><tbody><tr><td>1.0.0</td><td>0x0E841ae8f9CCDa3bDC14780216B974a477978Fec</td></tr><tr><td>1.1.0</td><td>0xe6de8cCFE609aef6de78DC6C9F409C6762f58EC5</td></tr></tbody></table>

## ERC1155TL

### Ethereum

<table><thead><tr><th width="113">Version</th><th>Address</th></tr></thead><tbody><tr><td>1.0.0</td><td>0x00059878282ec217c761F20e668932D1A7f3bb97</td></tr><tr><td>1.1.0</td><td>0xe6de8cCFE609aef6de78DC6C9F409C6762f58EC5</td></tr></tbody></table>

### Goerli

<table><thead><tr><th width="113">Version</th><th>Address</th></tr></thead><tbody><tr><td>1.0.0</td><td>0xaD5AA880f860a88605c23869bA12428958d7cB3E</td></tr><tr><td>1.1.0</td><td>0x9FCa89F0101F985D65c7442363830485873B2baf</td></tr></tbody></table>


# Royalties & Enforcement Options

TL Creator Contracts utilize EIP-2981 to configure royalties on-chain.

### Configuration

All TL Creator Contracts implement [EIP-2981](https://eips.ethereum.org/EIPS/eip-2981) compliant royalties. The implementation we created allows for a default royalty configuration set at the contract level and then individual token overrides.&#x20;

Only the owner of the contract can edit the royalty configuration either at the contract or token level.

It is important to note that individual token royalties are respected at marketplaces like SuperRare and Foundation, but NOT respected by OpenSea at this time. We have asked them about it and it is on the roadmap, but until then, the default royalty configuration is used.

### Enforcement

Version 4 of our creator contracts implement [Limit Break's V5 Transfer Validator](https://apptokens.com/docs/integration-guide/creator-token-standards/overview) architecture to enforce royalties on OpenSea. This is a feature that creators can opt in or out of.

<mark style="color:$warning;">NOTE: If a creator opts out of enforcement, they CANNOT turn it back on later starting with v4.1.0 of our creator contracts (first productized version).</mark>

Transient Labs maintains our own list of approved marketplaces that can be used to sell NFTs. Creators have the ability to make their own list as well through [https://developers.apptokens.com](https://developers.apptokens.com/).&#x20;

#### Default Whitelisted Marketplaces

* OpenSea
* Transient
* Gondi
* SuperRare
* Manifold
* Ninfa
* PND by Ripe0x

If you run into issues or need a marketplace added to this list, please reach out to <team@transientlabs.xyz> or message <https://x.com/mpeyfuss>


# Common Features

All TL Creator Contracts have the following common features

Read on to learn more about all common features of the TL Creator Contracts!


# Access Control

TL Creator Contracts implement access control mechanisms to allow for ease of use while promoting security.

## Ownable Access Control

We have combined OpenZeppelin's Ownable contract with role based access mechanisms to make a simple, effective ownership model.

{% @github-files/github-code-block url="<https://github.com/Transient-Labs/tl-sol-tools/blob/main/src/access/OwnableAccessControl.sol>" %}

## Roles

TL Creator Contracts have two roles defined

<details>

<summary>ADMIN_ROLE</summary>

This role is able to mint tokens, add `APPROVED_MINT_CONTRACT` roles, propose/push token metadata updates, and add creator stories on behalf of the contract owner.

</details>

<details>

<summary>APPROVED_MINT_CONTRACT</summary>

This role is allowed to mint using the `externalMint` functions in `ERC721TL` and `ERC1155TL`.

</details>


# Story Inscriptions

Stories are integral to extending on-chain provenance and adding value to tokens.

## Background

Art has so much more to it than just the piece of art itself. There is the story of the artist, the inspiration behind the piece of art, and the story from each collector of the piece.

There is no easy way to have all of these stories available to potential collectors and the community as a whole. Typically, it’s just verbally relayed amongst all parties.

In crypto art, piece descriptions get us part of the way there… but we can do so much better by leveraging blockchain technology.

## Read more

{% content-ref url="/pages/MPXvdIJoND4nuB4XoLme" %}
[Story Inscriptions Overview](/story-inscriptions/story-inscriptions-overview)
{% endcontent-ref %}


# NFT Delegation

Transient Labs allows token owners to inscribe stories, accept metadata updates, and pin metadata from delegate wallets. This is done to ensure NFT security while enabling the functionality built into our contracts.&#x20;

Transient Labs does NOT allow delegates to transfer, burn, or do anything else that affects ownership on the blockchain.

You can read more about it [here](/integrations/nft-delegation)


# ERC721TL

ERC721TL is Transient Labs' Creator Contract compliant with the ERC-721 specification.

## Airdrops

ERC721TL allows for single token and multi-token airdrops. Multi-token airdrops are more expensive than batch mints, however, still are market leading for code-less solutions.&#x20;

| Number of Tokens | Market    | ERC721TL  |
| ---------------- | --------- | --------- |
| 5                | 450,000   | 420,000   |
| 10               | 830,000   | 675,000   |
| 100              | 6,200,000 | 5,500,000 |

## Batch Minting

ERC721TL implements market leading batch mint operations, while adhering to the ERC-721 specification. This is achieved through the use of custom ownership logic.&#x20;

The table and chart below shows gas usage comparison to the current market for batch mints, in gas units.&#x20;

When plotted out, you can see that the slope of Transient's batch mint is basically flat compared to that of other options on the market.

<table><thead><tr><th width="123">Tokens</th><th width="144">Market</th><th width="220">ERC721TL Batch Mint</th><th data-hidden>ERC721TL Batch Mint Ultra</th></tr></thead><tbody><tr><td>1</td><td>210,000</td><td>176,000</td><td>176,000</td></tr><tr><td>5</td><td>450,000</td><td>198,000</td><td>187,000</td></tr><tr><td>10</td><td>830,000</td><td>209,000</td><td>187,000</td></tr><tr><td>100</td><td>6,200,000</td><td>402,000</td><td>187,000</td></tr><tr><td>200</td><td>12,000,000</td><td>616,000</td><td>187,000</td></tr><tr><td>1,000</td><td>Not Possible</td><td>2,331,000</td><td>187,000</td></tr></tbody></table>

## External Mint

ERC721TL has been outfitted with an external mint function that allows for approved mint contracts to mint tokens. This is extremely useful when it comes to minting for direct sales, edition sales, and more! For more on access control, see below.

## Burn

ERC721TL allows for any collector to burn tokens. This is intended to be used by creators with burn and redeem contracts in the future, but nothing stops collectors from burning tokens as they wish.

The burn function allows for the owner of the token or an approved operator to burn. The operator approval is required for burn and redeem contracts. This allows burn and redeem contracts to be configurable and determined at a later time.

### Access Control

There is a built in access control mechanism for admins & mint contracts. This can be used to generate systems for novel mint mechanics, updatable metadata based on offchain mechanisms, and much more.

### Rendering Contract

There is the ability to use a separate rendering contract for token uri generation. This allows for mint & reveal schemes, fully onchain metadata, and more.

## Source

<https://github.com/Transient-Labs/tl-creator-contracts/blob/main/src/erc-721/ERC721TL.sol>


# ERC1155TL

Transient Labs ERC-1155 Creator Contract is packed with more innovation than another other solution on the market.

## Overview

ERC721TL is Transient Labs' Creator Contract compliant with the [ERC-1155](https://eips.ethereum.org/EIPS/eip-1155) specification.&#x20;

## Airdrops

ERC1155TL makes it extremely easy for creators to mint and distribute a token to many recipients in one single transaction.

## Batch Token Creation

With our implementation of ERC-1155 tokens, creators must create a token. This allows for a unique token URI per token and for checking if a token exists in the contract. Minting a newly created token can happen in the same transaction, but what if a creator wants to create 10 tokens?

Well they can do this and distribute the tokens in a single transaction!&#x20;

## Batch Burn

ERC1155TL allows for ultra-efficient token burning. A single collector can burn a batch of tokens (different token ids and amounts) in a single transaction!&#x20;

The burn feature is open to the collector or any operators approved by the collector. This is useful for burn and redeem contracts. This allows burn and redeem contracts to be configurable and determined at a later time.

## Updating Token Metadata

Synergy is not possible with the ERC-1155 specification, since there are technically more than one owner of a token. We recognize that metadata updates may be needed so we have included a method to do this. But we encourage artists to avoid updating unless necessary and such caution artists about this in The Lab.

## Source

<https://github.com/Transient-Labs/tl-creator-contracts/blob/main/src/erc-1155/ERC1155TL.sol>


# ERC7160TL

Transient Labs ERC-7160 Creator Contract is packed with more innovation than another other solution on the market.

## Overview

ERC7160TL is Transient Labs' Creator Contract compliant with the [ERC-7160](https://eips.ethereum.org/EIPS/eip-7160) specification.&#x20;

## Airdrops

ERC7160TL allows for single token and multi-token airdrops. Multi-token airdrops are more expensive than batch mints, however, still are market leading for code-less solutions.&#x20;

| Number of Tokens | Market    | ERC721TL  |
| ---------------- | --------- | --------- |
| 5                | 450,000   | 420,000   |
| 10               | 830,000   | 675,000   |
| 100              | 6,200,000 | 5,500,000 |

## Batch Minting

ERC7160TL implements market leading batch mint operations, while adhering to the ERC-721 specification. This is achieved through the use of custom ownership logic. The table and chart below shows gas usage comparison to the current market for batch mints, in gas units.

<table><thead><tr><th width="123">Tokens</th><th width="144">Market</th><th width="220">ERC721TL Batch Mint</th></tr></thead><tbody><tr><td>1</td><td>210,000</td><td>176,000</td></tr><tr><td>5</td><td>450,000</td><td>198,000</td></tr><tr><td>10</td><td>830,000</td><td>209,000</td></tr><tr><td>100</td><td>6,200,000</td><td>402,000</td></tr><tr><td>200</td><td>12,000,000</td><td>616,000</td></tr><tr><td>1,000</td><td>Not Possible</td><td>2,331,000</td></tr></tbody></table>

<figure><img src="/files/4DcYRvpSokDt4BJYTxG7" alt=""><figcaption></figcaption></figure>

## External Mint

ERC721TL has been outfitted with an external mint function that allows for approved mint contracts to mint tokens. This is extremely useful when it comes to minting for direct sales, edition sales, and more! For more on access control, see below.

## Multi-Metadata

ERC7160TL follows the ERC-7160 specification, allowing each token to have an array of metadata associated with it. This allows for extra functionality and design for creators & collectors.

Collectors of the tokens on this contract can choose to change their token's metadata to any option in the array. This emits a `MetadataUpdate` event that let's marketplaces re-index the metadata and display it.&#x20;

## Burn

ERC721TL allows for any collector to burn tokens. This is intended to be used by creators with burn and redeem contracts in the future, but nothing stops collectors from burning tokens as they wish.

The burn function allows for the owner of the token or an approved operator to burn. The operator approval is required for burn and redeem contracts. This allows burn and redeem contracts to be configurable and determined at a later time.

## Source

<https://github.com/Transient-Labs/tl-creator-contracts/blob/main/src/erc-721/multi-metadata/ERC7160TL.sol>


# Story Inscriptions Overview

Stories are extending on-chain provenance and add human-provenance, increasing token value and history.

## Background

Art has so much more to it than just the piece of art itself. There is the story of the artist, the inspiration behind the piece of art, and the story from each collector of the piece.

There is no easy way to have all of these stories available to potential collectors and the community as a whole. Typically, it’s just verbally relayed amongst all parties.

In crypto art, piece descriptions get us part of the way there… but we can do so much better by leveraging blockchain technology.

## Solution

Originally developed as a collaboration with Michelle Viljoen, the Story Contract was developed to overcome the limitations of traditional storytelling.

This contract allows both the artist and collector(s) can write their stories to the blockchain, where they are stored immutably and for infinitum, without censorship.

Transient Labs plans to provide a new experience where people can explore stories, in general or for a specific piece of art. We are also working with marketplaces to get this integrated.

## Gas Efficiency

Based on local testing, the gas cost of a 5000 word story (a research paper) costs `694795 gas`. At 100 gwei gas, this coverts to a gas cost of `0.0694795 ETH`. This is extrememly gas efficient. Stories will also likely be much shorter in length and submitted when gas is lower.

## Source Code

<https://github.com/Transient-Labs/tl-story-inscriptions>


# Story Inscription Format

Story Inscriptions utilize Markdown as the formal language for formatting text, with the ability to extend if needed.

## Schema

Story Inscriptions are markdown text blobs, supporting both portions of Markdown: Frontmatter and Content.

### Frontmatter

Frontmatter is a JSON blob, with curly braces starting and ending on their own lines (as shown below). Any structured data can be put in here. Transient Labs uses namespacing for specific products, [such as T.R.A.C.E.](/trace/record-schema)

JSON was chosen as it is the most secure and easiest to serialize across web frameworks. YAML is not secure enough in our opinion and TOML is harder to work with. There is no standard way to specify JSON Frontmatter, however, the method chosen here is widely supported across programming languages (Javascript, Python, Go).

### Content

Content is markdown text that should be parsed and escaped to avoid XSS and other attack vectors. This guide shows what is accepted as Markdown syntax: <https://www.markdownguide.org/basic-syntax/>

### Example

```markdown
{
  "data": "some json data in Frontmatter"
}
# Markdown Content starts here!
You can write whatever you want down here!
```


# Smart Contract Documentation

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/// @title Transient Labs Story Inscriptions Interface
/// @dev Interface id: 0x2464f17b
/// @dev Previous interface id that is still supported: 0x0d23ecb9
/// @author transientlabs.xyz
/// @custom:version 6.0.0
interface IStory {
    /*//////////////////////////////////////////////////////////////////////////
                                Events
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Event describing a collection story getting added to a contract
    /// @dev This event stories creator stories on chain in the event log that apply to an entire collection
    /// @param creatorAddress The address of the creator of the collection
    /// @param creatorName String representation of the creator's name
    /// @param story The story written and attached to the collection
    event CollectionStory(address indexed creatorAddress, string creatorName, string story);

    /// @notice Event describing a creator story getting added to a token
    /// @dev This events stores creator stories on chain in the event log
    /// @param tokenId The token id to which the story is attached
    /// @param creatorAddress The address of the creator of the token
    /// @param creatorName String representation of the creator's name
    /// @param story The story written and attached to the token id
    event CreatorStory(uint256 indexed tokenId, address indexed creatorAddress, string creatorName, string story);

    /// @notice Event describing a collector story getting added to a token
    /// @dev This events stores collector stories on chain in the event log
    /// @param tokenId The token id to which the story is attached
    /// @param collectorAddress The address of the collector of the token
    /// @param collectorName String representation of the collectors's name
    /// @param story The story written and attached to the token id
    event Story(uint256 indexed tokenId, address indexed collectorAddress, string collectorName, string story);

    /*//////////////////////////////////////////////////////////////////////////
                                Story Functions
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Function to let the creator add a story to the collection they have created
    /// @dev Depending on the implementation, this function may be restricted in various ways, such as
    ///      limiting the number of times the creator may write a story.
    /// @dev This function MUST emit the CollectionStory event each time it is called
    /// @dev This function MUST implement logic to restrict access to only the creator
    /// @param creatorName String representation of the creator's name
    /// @param story The story written and attached to the token id
    function addCollectionStory(string calldata creatorName, string calldata story) external;

    /// @notice Function to let the creator add a story to any token they have created
    /// @dev Depending on the implementation, this function may be restricted in various ways, such as
    ///      limiting the number of times the creator may write a story.
    /// @dev This function MUST emit the CreatorStory event each time it is called
    /// @dev This function MUST implement logic to restrict access to only the creator
    /// @dev This function MUST revert if a story is written to a non-existent token
    /// @param tokenId The token id to which the story is attached
    /// @param creatorName String representation of the creator's name
    /// @param story The story written and attached to the token id
    function addCreatorStory(uint256 tokenId, string calldata creatorName, string calldata story) external;

    /// @notice Function to let collectors add a story to any token they own
    /// @dev Depending on the implementation, this function may be restricted in various ways, such as
    ///      limiting the number of times a collector may write a story.
    /// @dev This function MUST emit the Story event each time it is called
    /// @dev This function MUST implement logic to restrict access to only the owner of the token
    /// @dev This function MUST revert if a story is written to a non-existent token
    /// @param tokenId The token id to which the story is attached
    /// @param collectorName String representation of the collectors's name
    /// @param story The story written and attached to the token id
    function addStory(uint256 tokenId, string calldata collectorName, string calldata story) external;
}
```


# T.R.A.C.E. Overview

What is T.R.A.C.E. and why is it needed?

## Tokenized Records for Artwork/Asset Certification and Evolution

T.R.A.C.E. is a system of smart contracts and hardware to provide a digital Certificate of Authenticity (dCOA) backed by the blockchain for physical art or assets. T.R.A.C.E. is comprised of 4 different components that all work together in harmony.

### T.R.A.C.E. Chips

* TRACE chips are cryptography-enabled chips that have an ethereum address and can sign messages, similar to wallets like Rainbow or Metamask.&#x20;
* The private key for each chip generated within the chip itself, which is a secure, tamper-proof element, and is never exposed during or after the manufacturing process.&#x20;
* Interaction with the chip is accomplished via NFC technology so an NFC enabled Android or iPhone XS and later is required.&#x20;
* The dCOA minted on the creator-owned contract is owned by the T.R.A.C.E. chip and can never be transferred from the chip by anyone other than the creator. In other words, the physical actually owns the its own dCOA.&#x20;
* For most artworks, chips can be securely fastened in a way that would result in visual indication if ever tampered with.&#x20;
* For textiles and garments, the chips can be embedded with embroidery, patches, sewn into a corner, and more.&#x20;
* For other materials, the chips can be pressed into vinyl, adhered to glass, hidden under a wood inlay, and more.

### T.R.A.C.E. Creator Contract

* T.R.A.C.E. dCOAs are minted on sovereign, creator-owned T.R.A.C.E. contracts.
* Functionality mirrors that of our ERC721TL creator contracts, but is tuned for T.R.A.C.E.
  * Batch Minting is removed
  * Synergy does not make sense in this application and instead metadata can be updated whenever needed. This is not a risk as the dCOA is not what holds value and all records are stored on-chain, regardless of metadata.
  * The creator can transfer a T.R.A.C.E. dCOA token whenever needed. This keeps the provenance chain intact in case a chip stops working for any reason.
  * There is no Blocklist functionality

### T.R.A.C.E. Records

* T.R.A.C.E. chips are used to verify T.R.A.C.E. records, which are then inscribed permanently on the blockchain using [Story Inscriptions](/story-inscriptions/story-inscriptions-overview).&#x20;
* These records store information about the history and evolution of an artwork. Examples of record types include ownership history, sales, display details, alterations, and much more. See T.R.A.C.E. Record Schema for more details.
* Creators also have the ability to add free-form records that add to the history of the piece as they see fit.&#x20;
* Records can be added by the creator or registered agents.&#x20;
* Registered agents must always validate the records by having the T.R.A.C.E. chip sign a message that is included with the on-chain inscription.&#x20;
* Creators can always add records without interacting with the chip.

### T.R.A.C.E. Registered Agents

* T.R.A.C.E. Registered Agents are trusted third parties to validate the different records added to physical art. Some examples include, auction houses, galleries, museums, and more.&#x20;
* Creators can add their own registered agents for their T.R.A.C.E. contracts, which can include their estate, managers, and more.&#x20;
* Creators can also override any global agents and block them from verifying records on their T.R.A.C.E. contracts.


# Record Schema

T.R.A.C.E. Records utilize a specific schema with Story Inscriptions to store data on the blockchain permanently.

## `TRACE Authentication`

This event is emitted upon mint or creator token transfer and indicates the on-chain authentication to TRACE chips. This is typically auto-emitted by the TRACE contract

```markdown
{
  "trace": {
    "type": "trace_authentication"
  }
}
```

## `Creation`

This event SHOULD only be emitted once and indicates when the physical piece was created. Allows for backdating.

```markdown
{
  "trace": {
    "type": "creation",
    "timestamp": int
  }
}
```

## `Freeform`

Freeform data, typically restricted to the creator.

```markdown
{
  "trace": {
    "type": "freeform"
  }
}
<FREEFORM MARKDOWN DATA>
```

## `Media`

Media to meant to be displayed in a carousel

```markdown
{
  "trace": {
    "type": "media",
    "mime_type": "str",
    "uri": "str"
  }
}
```

## `Sale`

An event indicating a sale

```markdown
{
  "trace": {
    "type": "sale",
    "sold_from": "str",
    "sold_to": "str",
    "sale_type": "str",
    "sold_at": "str",
    "value": "str",
    "timestamp": int,
    "uri": "str"
  }
}
```

## `Trade`

An event indicating a trade

```markdown
{
  "trace": {
    "type": "trade",
    "traded_from": "str",
    "traded_to": "str",
    "timestamp": int
  }
}
```

## Transfer

An event indidicating a generic transfer

```
{
  "trace": {
    "type": "transfer",
    "transfer_from": "str",
    "transfer_to": "str",
    "timestamp": int
  }
}
```

## `Exhibition`

An event indicating an exhibition

```markdown
{
  "trace": {
    "type": "exhibition",
    "timestamp": int,
    "end_timestamp": int,
    "exhibitor": "str",
    "location": "str",
    "uri": "str"
  }
}
```

## `Alteration`

An event indicating an alteration took place

```markdown
{
  "trace": {
    "type": "alteration",
    "timestamp": int
  }
}
<Freeform markdown summarizing alteration>
```

## `LEGAL`

An event indicating that legal copy was attached

```markdown
{
  "trace": {
    "type": "legal"
  }
}
<Freeform markdown for legal purposes>
```

## `Appraisal`

An event indicating that an appraisal took place

```markdown
{
  "trace": {
    "type": "appraisal",
    "appraiser": "str",
    "value": "str",
    "timestamp": int
  }
}
<Freeform markdown for appraisal, which can include links>
```

## `Third Party Authentication`

An event indicating that a 3rd party authenticated the physical asset/artwork

```markdown
{
  "trace": {
    "type": "third_party_authentication",
    "timestamp": int
  }
}
<Freeform markdown describing authentication, which can be used for history of a piece and more>
```


# Implementation

Implementation of T.R.A.C.E. Contracts

## TRACE

The latest implementation (v4.1.0) is deployed to the following address on supported chains: `0x8a13adc2fbd6f39850aa78d0d602df0cef477f72`

<details>

<summary>Previous Deployments</summary>

v4.0.0: `0xf827780e542570ae753da9288625bf687286bb35`

v3.6.0: `0x1a102edcfbcf077762945651efc820fca9929fba`

v3.1.2: `0xada0e41a41081ecd4803a3070e399bc3adaa0970`

v3.1.0: `0x4e489788b7e5d5c1fd245eb237b2c0e1cbaa3a0b`

v3.0.1: `0xd3a6ca43e1568815bbad091c36e531eb994b2a31`

v3.0.0: `0x199907607b9b486f964df8d32d3784e77f6e79d8`

</details>

<https://github.com/Transient-Labs/tl-creator-contracts/blob/main/src/erc-721/trace/TRACE.sol>

## TRACERSRegistry

This registry is deployed to the following address on TRACE supported chains: `0xdfe07d3da805d645a2ec2a83ec5f25763f7c0d25`

<details>

<summary>Previous Deployments</summary>

</details>

<https://github.com/Transient-Labs/tl-tracers-registry/blob/main/src/TRACERSRegistry.sol>


# Smart Contract Documentation


# TRACE

Smart contract documentation for TRACE can be found here: [Broken mention](broken://pages/uJjfQ6KjAhnkKnh4QO1L)


# TRACERSRegistry

### Latest Version (3.0.0)

<https://cdn.transientlabs.xyz/docs/tracers-registry/v3.0.0/>

### All Versions

<table><thead><tr><th width="112">Version</th><th>Link</th></tr></thead><tbody><tr><td>3.0.0</td><td><a href="https://cdn.transientlabs.xyz/docs/tracers-registry/v3.0.0/">https://cdn.transientlabs.xyz/docs/tracers-registry/v3.0.0/</a></td></tr><tr><td></td><td></td></tr><tr><td></td><td></td></tr></tbody></table>


# Overview

Sale contracts made easy.

The mint contracts have unique sales functionalities for ERC-721 and ERC-1155 tokens while the auction house supports auctions and buy now pricing for minted ERC-721 tokens.

## Lazy Mint Mechanics

### Regular Limited Edition Sale

Sell a limited supply of ERC-721 or ERC-1155 editions to an allowlist, the public, or both!

### Regular Open Edition Sale

Sell an unlimited supply of ERC-721 or ERC-1155 editions to the public. It is possible to have an allowlist for a cheaper sale if desired as well.

### Limited Series Unique Sale

Sell a limited set of unique ERC-721 tokens. Note that these would need to be instantly revealed if using a contract with Synergy.

### Velocity Sale

This is a variant of an Open Edition sale, although an allowlist is not allowed. Whenever a mint occurs, time is removed from the sale duration, creating a sense of FOMO for buyers. This technically puts a theoretical limit on the number that can be purchased and follows this equation.

```
theoretical_max = sale_duration / decay_rate + mint_allowance_per_wallet
```

### Marathon Sale

This is the opposite of Velocity Sales, with the `decay_rate` being positive instead of negative. There is no theoretical limit to the number purchased and in theory the mint could go on forever.

## Auction House Mechanics

### Reserve Auction

This is by far the most popular auction format where the piece has a minimum price to kick off the auction and then once started, the auction lasts for a predefined duration set by the token owner.

### Scheduled Auction

Works the same way as a Reserve Auction, except the auction starts prior to the first bid. This means that the auction can end without any bids on the piece. This auction type works great for exhibitions where you want to put pressure on collectors to bid.

### Buy Now

This is a fixed price sale that can be met at any time. This can be set in addition to the reserve auction to allow for more complex purchase options.

## Fees

Transient Labs does not charge creator fees and instead charges fees to the buyer. The mint contracts apply a flat ETH fee per NFT bought. The auction house applies a capped percentage fee  to the buyer.

| Contract                       | Fee        |
| ------------------------------ | ---------- |
| ERC-721 Mint (TLStacks721)     | 0.0009 ETH |
| ERC-1155 Mint (TLStacks1155)   | 0.0009 ETH |
| Auction House (TLAuctionHouse) | 2.5%       |


# Deployments

## ERC-721 Mint Contracts

The latest version (2.3.1) of the Stacks 721 contract is deployed at `0x384092784cfaa91efaa77870c04d958e20840242` on all supported [blockchains](/miscellaneous/supported-blockchains).

<details>

<summary>Previous Implementations</summary>

### 2.3.0

`0xe920c218c70aa253b10b0e074741cbe50102935e`

### **1.0.0**

#### Ethereum

[0x785d0B89499EbAE634E1791987c267B011B154aE](https://etherscan.io/address/0x785d0B89499EbAE634E1791987c267B011B154aE)

#### Goerli

[0x37847eC90b2C619e6390A2bbaEeCfc47E80ef60C](https://goerli.etherscan.io/address/0x37847eC90b2C619e6390A2bbaEeCfc47E80ef60C)

#### Arbitrum

[0x2De0972Fcd8ab0788697f92984b0D578F4c9ECA3](https://arbiscan.io/address/0x2De0972Fcd8ab0788697f92984b0D578F4c9ECA3)

#### Arbitrum Goerli

[0xA7BD5af7DDBe244eC423e29C1521326D81700FC2](https://goerli.arbiscan.io/address/0xA7BD5af7DDBe244eC423e29C1521326D81700FC2)

</details>

##

## ERC-1155 Mint Contracts

The latest version (2.3.1) of the Stacks 1155 contract is deployed at `0x32953d7ae37b05075b88c34e800ae80c1cb1b794` on all supported [blockchains](/miscellaneous/supported-blockchains).

<details>

<summary>Previous Implementations</summary>

### **2.3.0**

`0x4f78edcef4400cd6ebee16026eb4e5eef6e651e5`

### **1.0.0**

#### Ethereum

[0x454A3B647C7e9F4270175285c978dFb9D1f7Af15](https://etherscan.io/address/0x454A3B647C7e9F4270175285c978dFb9D1f7Af15)

#### Goerli

[0x80B1c1e64e152495fACd2860aF903E8770e878BF](https://goerli.etherscan.io/address/0x80B1c1e64e152495fACd2860aF903E8770e878BF)

#### Arbitrum

[0x00059878282ec217c761F20e668932D1A7f3bb97](https://arbiscan.io/address/0x00059878282ec217c761f20e668932d1a7f3bb97)

#### Arbitrum Goerli

[0x2De0972Fcd8ab0788697f92984b0D578F4c9ECA3](https://goerli.arbiscan.io/address/0x2De0972Fcd8ab0788697f92984b0D578F4c9ECA3)

</details>

## Auction House

The latest version (2.6.1) of the Transient Auction House contract is deployed at `0x6f66b95a0c512f3497fb46660e0bc3b94b989f8d` on all supported [blockchains](/miscellaneous/supported-blockchains).

<details>

<summary>Previous Implementations</summary>

### 2.1.0

Ethereum: `0x681bc9A3326F05A8e3c736995A3A04E60D118B73`&#x20;

Arbitrum One: `0x17e8Bbe0B4936Ed20fFA23f421226cf4000f8619`

### 2.0.0

Ethereum: `0x23A0990634E2B7deCd3a28A10cBd8838ed1BE142`&#x20;

Arbitrum One: `0x4aD30EeAb328C380f0F5d256Dd89bd87f63c6b79`

</details>


# Smart Contract Documentation

Links to documentation for different versions of Stacks smart contracts

<https://github.com/Transient-Labs/tl-stacks>


# Dynamic Art Overview

NFTs are the true home for dynamic art.

## What is Dynamic Art?

An overwhelming majority of NFTs on the market currently consist of what we call passive metadata (i.e. jpegs, mp4s). Dynamic NFTs on the other hand, can change state based on external factors (real world data, events, etc.). They can also be manipulated by the viewer, providing a highly unique interactive experience. Even generative art is a subset of dynamic art typically!&#x20;

Here are some great examples of Dynamic Art:

#### 24: The Sentinel

Changes with time & moon phase

<https://opensea.io/assets/ethereum/0xb018e5fd857b46910d053c7fb4cf590f404fcd99/3>

#### Solstice: Homebound

Changes with touch

<https://opensea.io/assets/ethereum/0xb018e5fd857b46910d053c7fb4cf590f404fcd99/4>

#### Impermanence by Josh Pierce

Changes with weather

<https://opensea.io/assets/ethereum/0x5466e0637dc327e7ee69b2708d85b2e52a260532/1>


# How to Create

Creating Dynamic Art couldn't be easier with The Lab!

Up until The Lab, creating dynamic art required hiring a developer. No more! The Lab provides templates to generate dynamic art with only a few clicks!

## Templates

### Time-Changing Art

The Lab provides templates to create art that changes with time. Want something that changes by the hour of day or day of the week? The Lab has it!

### Interactive Art

Want to incorporate real-time fluid simulation or toggle between photos? The Lab provides!

### Books

Are you an author? NFT books are completely possible!

### More to come!

## Need Something Custom?

Contact us!

{% embed url="<https://www.transientlabs.xyz/submit-a-proposal>" %}


# How to Display

Displaying Dynamic Art online is easy!

## How to Display Online

Dynamic art is an html file that can be loaded into an iframe to display online. Of course, security is important so it is best to sandbox the iframe. You can use the code below to load into an iframe.

```html
<iframe allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" sandbox="allow-scripts" src=""></iframe>
```

## How to Display on a Digital Frame

Unfortunately, the dynamic art support is lacking for digital frames. There are a few promising frames being developed and we will update this as they release!


# Deploying TL Contracts

Deploy a TL Creator Contract, TRACE Contract, or BlockListRegistry from any dApp using our Universal Deployer contract factory.

## Overview

As mentioned, all of our creator contracts are deployed via [ERC-1167](https://eips.ethereum.org/EIPS/eip-1167) immutable proxies. In addition, T.R.A.C.E. and BlockListRegistry contracts are also deployed in this manner.

All of this is accomplished with our Universal Deployer contract factory. We've developed this as a public good and our primary contract deployment method.&#x20;

You can simply deploy contracts by encoding some initialization code and calling a single on-chain function. the `CREATE2` opcode is used in order to predetermine contract addresses and deploy the same exact contract across EVM chains to the same address (pretty neat huh?).

Enjoy!

## Deployed Address&#x20;

The Universal Deployer is deployed to all [supported chains](/miscellaneous/supported-blockchains) at `0x7c24805454F7972d36BEE9D139BD93423AA29f3f`

## Available Contract Types

* ERC721TL
* ERC1155TL
* ERC7160TL
* ERC7160TLEditions
* TRACE

## Generating Initialization Code

Whenever you deploy with this universal deployer, you need to pass calldata as bytes for intialization code of the contract. You can encode the parameters with the function signature using many different tools, including web3py, web3js, etherjs, viem, and foundry (cast). The following example shows how to accomplish this for an ERC721TL contract with cast.

### web3py

```python
# omitted imports and creating a contract
# for more, visit https://web3py.readthedocs.io/en/stable/quickstart.html

contract_address = "" # can use any address
erc721tl_abi = '' # can get from etherscan
contract = web3.eth.contract(address=contract_address, abi=erc721tl_abi)

init_code = contract.encodeABI(
    fn_name="initialize",
    args=[
        "Test 721",
        "T721",
        "personalization",
        "0x0000000000000000000000000000000000C0FFEE",
        1000,
        "0x0000000000000000000000000000000000C0FFEE",
        [],
        "0x0000000000000000000000000000000000000000",
        "0x0000000000000000000000000000000000000000"
    ]
)

print(init_code)
```

### web3js

```javascript
// see more here: https://web3js.readthedocs.io/en/v1.10.0/web3-eth-contract.html#methods-mymethod-encodeabi

console.log(contract.methods.initialize(
  "Test 721",
  "T721",
  "personalization",
  "0x0000000000000000000000000000000000C0FFEE",
  1000,
  "0x0000000000000000000000000000000000C0FFEE",
  [],
  "0x0000000000000000000000000000000000000000",
  "0x0000000000000000000000000000000000000000"
).encodeABI());
```

### ethersjs

```javascript
// see more here: https://docs.ethers.org/v5/api/utils/abi/interface/#Interface--encoding
import { ethers } from "ethers";

const iFace = new ethers.utils.Interface([
  "function initialize(string,string,string,address,uint256,address,address[],bool,address,address)"
]);

console.log(iFace.encodeFunctionData("initialize", [
  "Test 721",
  "T721",
  "personalization",
  "0x0000000000000000000000000000000000C0FFEE",
  1000,
  "0x0000000000000000000000000000000000C0FFEE",
  [],
  "0x0000000000000000000000000000000000000000",
  "0x0000000000000000000000000000000000000000"
]);
```

### Viem

```javascript
// see more here: https://viem.sh/docs/contract/encodeFunctionData

import { parseAbi, encodeFunctionData } from 'viem';

const abi = parseAbi([
  "function initialize(string,string,string,address,uint256,address,address[],bool,address,address)"
]);
const initCode = encodeFunctionData({
  abi,
  functionName: "initialize",
  args: [
    "Test 721",
    "T721",
    "personalization",
    "0x0000000000000000000000000000000000C0FFEE",
    BigInt(1000),
    "0x0000000000000000000000000000000000C0FFEE",
    [],
    "0x0000000000000000000000000000000000000000",
    "0x0000000000000000000000000000000000000000"
  ]
});
console.log(initCode);
```

### Cast

{% code overflow="wrap" %}

```sh
cast calldata "initialize(string,string,string,address,uint256,address,address[],bool,address,address)" "Test 721" "T721" "personalization" 0x0000000000000000000000000000000000C0FFEE 1000 0x0000000000000000000000000000000000C0FFEE "[]" true 0x0000000000000000000000000000000000000000 0x0000000000000000000000000000000000000000 
```

{% endcode %}

## General Clone Deployer

Additionally, we have deployed a general clone deployer for anyone to use for deploying minimal proxies to any implementation contract.\
\
Deployed to all chains at `0x3b3b425b96286c86dcb7bb8585dbf4642c7fea2e`

## Github Repo

<https://github.com/Transient-Labs/tl-universal-deployer>


# NFT Delegation

## Background

NFT security is one of the biggest concerns in our space. As such, most people keep their NFTs in wallets/vaults that they don't connect to any dApps. This can either be in the form of a hardware wallet or a mutli-sig smart contract wallet. If someone ones to sell an NFT, they just simply transfer the NFT to a selling wallet that they can connect to marketplaces.

Transient Labs contracts have features that are unique and provide more utlity to NFT owners. To start, we initially required the NFT owner to send the transaction to either add a story inscription, accept a metadata update, or something else. Looking towards the future, with NFT security in mind, we want to create a universal interface for Transient Labs contracts to check NFT ownership delegations.

## Solution

NFT delegation is not new. [delegate.xyz](https://delegate.xyz) has done a good job of bringing NFT delegation to the market and many projects are integrating with it for allowlisting, airdrops, etc. There are also other products coming to the market outside of delegate.xyz. For example, Punk 6529 and his team have created their own delegation registry, [NFTDelegation](https://docs.nftdelegation.com/), that allows for more fine-grained control. This registry is used for all memecard drops from 6529.

The purpose of this NFT Delegation Registry is not to sping up our own version, but rather to provide a universal interface that our contracts can call, without having to worry about what delegation solutions are being checked under the hood. We think that there will be many delegation solutions in the future and want to support them all.

To start, the Transient Labs NFT Delegation Registry just checks [delegate.xyz v2](https://docs.delegate.xyz/delegate/upgrade-to-v2/v2-is-a-separate-contract). We considered supporting NFTDelegation, however, we have several questions and concerns and are in discussion with that team to address prior to integrating into this project.

## Immutable by Design

The registry we create follows a specific interface `src/ITlNftDelegationRegistry.sol`. However, we are not making the implementation upgradeable and rather will build our creator contracts to be able to migrate registries in the future.

## How This Registry Should Be Used

This registry MUST NEVER be used for any on-chain functionality that affects NFT ownership. As an example, delegates MUST NOT be able transfer or sell tokens on behalf of the token owner. ERC-721 and ERC-1155 already have mechanisms in place to handle this. Future token standards will also have those provisions in place.

## Smart Contract Documentation

The registry is deployed on all our [supported chains](/miscellaneous/supported-blockchains) at `0x05060a6dade0ab0a9f762976f03634ff9a14e3a3`

### Latest Docs (1.0.0)

<https://cdn.transientlabs.xyz/docs/nft-delegation/v1.0.0/>

### All Docs

<table><thead><tr><th width="112">Version</th><th>Link</th></tr></thead><tbody><tr><td>1.0.0</td><td><a href="https://cdn.transientlabs.xyz/docs/nft-delegation/v1.0.0/">https://cdn.transientlabs.xyz/docs/nft-delegation/v1.0.0/</a></td></tr><tr><td></td><td></td></tr><tr><td></td><td></td></tr></tbody></table>


# Integrating with Marketplaces

Integrating should be as easy as 1-2-3!

TL Creator Contracts can integrate seamlessly with any marketplaces that support ERC-721 or ERC-1155 standards.

## Open Marketplaces

Open marketplaces, like OpenSea, Rarible, LooksRare, Blur, etc should work out of the box. These marketplaces simply look at a user's wallet for any NFTs and can index those easily.

## Closed Marketplaces

Closed marketplaces are those marketplaces that index contracts after they have been validated. This includes marketplaces like SuperRare and Foundation. We are willing to help any of these marketplaces index over our contracts in an automated fashion as well.

### Verification

Please view the source code on our GitHub and see the deployed implementation contract addresses in these docs as well.&#x20;

{% content-ref url="/pages/6DFhn5gjYFb6zyfFi8aI" %}
[Implementation Contracts](/tl-creator-contracts/implementation-contracts)
{% endcontent-ref %}

### Automation

#### Contract Introspection

Since all TL contracts implement ERC-1967 or ERC-1167, it is possible to look up what implementation contract is utilized by getting the value at the following storage slot (ERC-1967) or looking at the bytecode (ERC-1167)

```solidity
0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc
```

From this, it can be verified that the NFT uses an approved implementation contract. Ideally this determines that the NFT should be indexed.


# Metadata Structure

Transient Labs structures metadata in accordance with major marketplaces, plus a few extra fields

TL Metadata is supported by all major marketplaces, such as SuperRare, OpenSea, LooksRare, and Nifty Gateway. The metadata follows widely accepted standards, with a few additional fields.

## Metadata Structure

```json
{
    "name": "string",
    "description": "string",
    "external_url": "string",
    "attributes": [
        {
            "trait_type": "string",
            "value": "string"
        },
        ...
    ],
    "tags": [
        "string",
        "string",
        ...
    ],
    "image": "string",
    "image_sha256": "string",
    "animation_url": "string",
    "animation_sha256": "string",
    "media": {
        "dimensions": "<number>x<number>",
        "size": "<number>",
        "mimeType": "string"
    }
}
```

### Details

<details>

<summary>name (required)</summary>

The title of the NFT

</details>

<details>

<summary>description (required)</summary>

The description that goes along with the NFT. You can use Markdown on OpenSea and SuperRare, although markdown links are not supported on SuperRare (regular links are).

A note on line breaks in Markdown: You need two spaces in front of the escape characters. For example: `\n`

</details>

<details>

<summary>external_url (optional)</summary>

A url string that would show up under the item on OpenSea and can be used to direct people to your website or other content you want them to see.

</details>

<details>

<summary>attributes (optional)</summary>

A list of key-value pair objects. The `trait_type` is always the key and `value` is the value. You can read more about these [here](https://docs.opensea.io/docs/metadata-standards#attributes). Note, boosts or anything like that are not supported outside of OpenSea.

</details>

<details>

<summary>tags (optional)</summary>

These are essentially hashtags on SuperRare. OpenSea does not yet support although they may be looking into this based on some beta features available in collection settings. We shall see.

</details>

<details>

<summary>image (required)</summary>

The uri of the image. Supported file types are `jpeg`, `png`, and `gif`.

</details>

<details>

<summary>image_sha256 (optional)</summary>

The sha256 hash of the image. Useful for assuring that the downloaded file is correct.

</details>

<details>

<summary>animation_url (only required for videos, 3d, and html)</summary>

The uri of the animation. Supported file types are `mp4`, `mp3`, `glb`, `gltf`, `html`

</details>

<details>

<summary>animation_sha256 (optional)</summary>

The sha256 hash of the animation. Useful for assuring that the downloaded file is correct.

</details>

<details>

<summary>media (optional)</summary>

An object containing some details about the main asset for faster indexing.

* `uri` - the link to the main asset (either `image` or `animation_url`)
* `size` - the size of the main asset in bytes shown as a string
* `dimensions` - the dimensions of the main asset if available, otherwise the dimensions of the thumbnail image ex: `100x100`
* `mimeType` - the mime type of the main asset

</details>


# Inheriting TL Contracts

Inheriting TL contracts into your project is straightforward and simple.

## Using Foundry

If you are using [Foundry](https://book.getfoundry.sh/), it is really simple to integrate TL contracts into your project. You just simply have to run the following, depending on which repo you want to integrate.

```bash
forge install Transient-Labs/tl-creator-contracts
forge install Transient-Labs/blocklist
forge install Transient-Labs/story-contract
forge install Transient Labs/tl-sol-tools
```

## Using Hardhat

If your project is using Hardhat, you can use the [Hardhat-Foundry plugin](https://hardhat.org/hardhat-runner/docs/advanced/hardhat-and-foundry) to integrate our contracts. This still requires Foundry to be installed though.

The one caveat is that we typically have some custom remappings that you may need. They are shown below. These can be added to the `remappings.txt` file as applicable and may need modification depending on your use case.

```
tl-story=<YOUR_PROJECT_ROOT>/lib/tl-creator-contracts/lib/story-contract/src/
tl-blocklist=<YOUR_PROJECT_ROOT>/lib/tl-creator-contracts/lib/blocklist/src/
```

## Using Brownie

Unfortunately [Brownie](https://eth-brownie.readthedocs.io/en/stable/) does not allow solidity files to be defined outside of a `contracts` folder for packages and thus our repositories can't be used in Brownie projects. Hopefully [ApeWorx](https://www.apeworx.io/) fixes this, as Brownie is sunsetting soon.


# Onchain Art

How to mint onchain art with Transient contracts

It's totally possible to mint fully onchain art with Transient contracts!

## Requirements

* Metadata must meet the Transient metadata specs: [Metadata Structure](/integrations/metadata-structure)
* Total size of the data must be below 24kb
* All uris must be base 64 encoded data uris
  * You can use this tool to convert images to data uris: <https://dopiaza.org/tools/datauri/index.php>
* Generate the JSON by pasting the following template into this tool and then editing the values: <https://www.objgen.com/json>

```
name = title
description = description
image = data:image/jpeg;base64,asgasdgjasdga
media
  size = 1234
  dimensions = 300x300
  mimeType = image/jpeg
```

* Convert this json to a base64 data uri using the [data uri tool](https://dopiaza.org/tools/datauri/index.php) with the following settings:&#x20;
  * ![](/files/Yri0652dEZF21hnNw6qU)

## Minting

You must use a block explorer to mint onchain art with Transient contracts.

1. Go to [The Lab](https://lab.transient.xyz) and create a new contract
2. Once deployed, you need to click on the block explorer icon to be taken to the approprite url
   1. ![](/files/7OAt77TSJyjWrZPEr3e1)
3. Click on the "Contract" tab
4. Click on "Write contract as proxy"
5. Connect your wallet
6. Scroll to the "mint" function
7. Enter in the final data uri (json that is base64 encoded) as the \`uri\`
8. Enter in your address as the \`recipient\`
9. Hit write and send the transaction
10. Done!


# Embeddable Components

Drop-in Web3 building blocks for any website.

Drop-in Web3 building blocks for any website.

These are small, ready-made HTML elements (web components) that add blockchain features — connecting a wallet, running an auction, minting an NFT, redeeming tokens — to any web page. You add two lines to your page's `<head>`, then place the elements you want in the page like regular HTML tags. No React or build step required: they work in plain HTML and inside any framework (React, Vue, Svelte, WordPress, Webflow, etc.).\
\
`Latest Version: 1.9.0`

### What's included

| Element                     | What it does                                                               |
| --------------------------- | -------------------------------------------------------------------------- |
| `<tl-connect-button>`       | A "Connect Wallet" button.                                                 |
| `<tl-siwe-button>`          | "Sign in with Ethereum" — proves a user owns their wallet.                 |
| `<tl-auction>`              | A live NFT auction (bid, buy now, settle).                                 |
| `<tl-mint-page-721>`        | A mint page for a 1-of-1 / ERC-721 NFT collection.                         |
| `<tl-mint-page-1155>`       | A mint page for an edition / ERC-1155 token.                               |
| `<tl-snr-erc1155tl-raffle>` | "Send and receive" raffle: send tokens in, get a raffle entry.             |
| `<tl-snr-erc1155tl>`        | Send tokens in, receive a fixed ERC-1155 token back.                       |
| `<tl-snr-erc721tl>`         | Send tokens in, receive a freshly minted ERC-721 NFT back (with a reveal). |
| `<tl-snr-currency>`         | Send currency in, redeem according to the contract's rules.                |

### Usage

Use in any webpage!

#### 1. Configure and load (in the `<head>`)

`window.tlConfig` is optional — every field has a sensible default — but setting `appName` and a `walletConnectProjectId` is recommended for a polished wallet flow.

```
<head>
  <script>
    window.tlConfig = {
      mode: "light",                          // "light" or "dark"
      appName: "My Cool App",                 // shown in the wallet connect dialog
      appDescription: "My cool app's description",
      walletConnectProjectId: "wallet-connect-id",
      testnet: false,                         // set true to use test networks (Sepolia, etc.)

      // Optional: override the default RPC URL per chain. Any you leave out use
      // the public default shown below. Testnet keys are only used when testnet: true.
      rpcUrls: {
        // Mainnets
        ethereum: "",       // defaults to https://ethereum-rpc.publicnode.com
        shape: "",          // defaults to https://mainnet.shape.network
        base: "",           // defaults to https://base-rpc.publicnode.com
        arbitrum: "",       // defaults to https://arbitrum-one-rpc.publicnode.com
        // Testnets (used when testnet: true)
        sepolia: "",        // defaults to https://ethereum-sepolia-rpc.publicnode.com
        shapeSepolia: "",   // defaults to https://sepolia.shape.network
        baseSepolia: "",    // defaults to https://base-sepolia-rpc.publicnode.com
        arbitrumSepolia: "" // defaults to https://arbitrum-sepolia-rpc.publicnode.com
      }
    }
  </script>
  <script type="module" src="https://cdn.transientlabs.xyz/embeds/v1.9.0/index.js"></script>
  <link rel="stylesheet" href="https://cdn.transientlabs.xyz/embeds/v1.9.0/index.css">
</head>
```

#### 2. Add the elements you want (in the `<body>`)

Each element is configured with HTML attributes (`chain-id`, `contract-address`, etc.). Use only the elements you need — you don't have to include all of them.

```
<body>
  <style>
    /* add any style overrides here*/
  </style>
  <!-- Omit any of the components you don't need below -->
  <tl-connect-button variant="default"></tl-connect-button>

  <tl-siwe-button chain-id="1" site-name="My Site name" terms-url="https://my-site.com/terms"></tl-siwe-button>

  <tl-auction chain-id="1" contract-address="0x2b4b2d47c8db371b006e3df14245c12193a185dc" token-id="1"
    auction-house-address="0x6f66b95a0c512f3497fb46660e0bc3b94b989f8d" refresh-interval="10000"></tl-auction>

  <tl-mint-page-721 chain-id="1" contract-address="0xb38bd444399cd76c3f91aa2455052834e3451911"
    mint-contract-address="0x384092784cfaa91efaa77870c04d958e20840242"
    allowlist-url="https://dv0xp0uwyoh8r.cloudfront.net/stacks/c8aeee8f-7d14-4403-a8b2-fe06f97a79cc/allowlist"
    slug="shape-study" refresh-interval="10000"></tl-mint-page-721>

  <tl-mint-page-1155 chain-id="1" contract-address="0xb38bd444399cd76c3f91aa2455052834e3451911" token-id="1"
    mint-contract-address="0x32953d7ae37b05075b88c34e800ae80c1cb1b794"
    allowlist-url="https://dv0xp0uwyoh8r.cloudfront.net/stacks/c8aeee8f-7d14-4403-a8b2-fe06f97a79cc/allowlist"
    slug="shape-study" refresh-interval="10000"></tl-mint-page-1155>

  <tl-snr-erc1155tl-raffle chain-id="1" raffle-contract-address="0xE9D8123BF045158B2b7608Cc48A4562770246902"
    refresh-interval="5000"></tl-snr-erc1155tl-raffle>

  <tl-snr-erc1155tl chain-id="1" contract-address="0x98d90d88632fEB8b6fF509c5bE4c598174Cd2A14"
    input-contract-address="0xa9e448617188458ff7e2e9ef31596494f7a8ac68" input-token-id="1"
    refresh-interval="5000"></tl-snr-erc1155tl>

  <tl-snr-erc721tl chain-id="1" contract-address="0x98d90d88632fEB8b6fF509c5bE4c598174Cd2A14"
    input-contract-address="0xa9e448617188458ff7e2e9ef31596494f7a8ac68" input-token-id="1"
    refresh-interval="5000"></tl-snr-erc721tl>

  <tl-snr-currency chain-id="1" contract-address="0xe08B3174D495E04491f9Dd8Ae3d684564A95710C"
    refresh-interval="5000"></tl-snr-currency>
</body>
```

### Component Inputs

Use kebab-case attributes in HTML. For example, the React prop `chainId` is the HTML attribute `chain-id`, and `contractAddress` is `contract-address`.

Boolean attributes should be set explicitly, for example `view-on-transient="false"`. Number inputs are parsed from their attribute values.

#### `<tl-connect-button>`

| Attribute | Type   | Required | Default   | Description                                                                                 |
| --------- | ------ | -------- | --------- | ------------------------------------------------------------------------------------------- |
| `variant` | string | No       | `default` | Button style variant: `default`, `destructive`, `outline`, `secondary`, `ghost`, or `link`. |

#### `<tl-siwe-button>`

| Attribute      | Type   | Required | Default          | Description                                                                                                                                  |
| -------------- | ------ | -------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `chain-id`     | number | Yes      | -                | Chain ID to use for the SIWE message and signature flow.                                                                                     |
| `site-name`    | string | Yes      | -                | Site name shown in the SIWE message.                                                                                                         |
| `terms-url`    | string | Yes      | -                | Terms URL included in the SIWE message.                                                                                                      |
| `nonce-source` | string | No       | block hash nonce | Set to `transient` to fetch a nonce from the Transient API. Otherwise the nonce is derived locally from the latest block and wallet address. |

#### `<tl-auction>`

| Attribute               | Type    | Required | Default | Description                                   |
| ----------------------- | ------- | -------- | ------- | --------------------------------------------- |
| `chain-id`              | number  | Yes      | -       | Chain ID where the auction contracts live.    |
| `contract-address`      | address | Yes      | -       | NFT contract address.                         |
| `token-id`              | number  | Yes      | -       | Token ID being auctioned.                     |
| `auction-house-address` | address | Yes      | -       | Auction house contract address.               |
| `refresh-interval`      | number  | Yes      | -       | Polling interval in milliseconds.             |
| `view-on-transient`     | boolean | No       | `true`  | Whether to show the "View on Transient" link. |

#### `<tl-mint-page-721>`

| Attribute               | Type    | Required | Default | Description                                                |
| ----------------------- | ------- | -------- | ------- | ---------------------------------------------------------- |
| `chain-id`              | number  | Yes      | -       | Chain ID where the mint contracts live.                    |
| `contract-address`      | address | Yes      | -       | ERC-721 collection contract address.                       |
| `mint-contract-address` | address | Yes      | -       | Mint contract address.                                     |
| `allowlist-url`         | string  | Yes      | -       | URL for allowlist data used during presale checks.         |
| `slug`                  | string  | Yes      | -       | Transient collection or drop slug used for external links. |
| `refresh-interval`      | number  | Yes      | -       | Polling interval in milliseconds.                          |
| `view-on-transient`     | boolean | No       | `true`  | Whether to show the "View on Transient" link.              |

#### `<tl-mint-page-1155>`

| Attribute               | Type    | Required | Default | Description                                                |
| ----------------------- | ------- | -------- | ------- | ---------------------------------------------------------- |
| `chain-id`              | number  | Yes      | -       | Chain ID where the mint contracts live.                    |
| `contract-address`      | address | Yes      | -       | ERC-1155 collection contract address.                      |
| `token-id`              | number  | Yes      | -       | ERC-1155 token ID to mint.                                 |
| `mint-contract-address` | address | Yes      | -       | Mint contract address.                                     |
| `allowlist-url`         | string  | Yes      | -       | URL for allowlist data used during presale checks.         |
| `slug`                  | string  | Yes      | -       | Transient collection or drop slug used for external links. |
| `refresh-interval`      | number  | Yes      | -       | Polling interval in milliseconds.                          |
| `view-on-transient`     | boolean | No       | `true`  | Whether to show the "View on Transient" link.              |

#### `<tl-snr-erc1155tl-raffle>`

| Attribute                 | Type    | Required | Default | Description                               |
| ------------------------- | ------- | -------- | ------- | ----------------------------------------- |
| `chain-id`                | number  | Yes      | -       | Chain ID where the raffle contract lives. |
| `raffle-contract-address` | address | Yes      | -       | Send-and-receive raffle contract address. |
| `refresh-interval`        | number  | Yes      | -       | Polling interval in milliseconds.         |

#### `<tl-snr-erc1155tl>`

| Attribute                | Type    | Required | Default | Description                                   |
| ------------------------ | ------- | -------- | ------- | --------------------------------------------- |
| `chain-id`               | number  | Yes      | -       | Chain ID where the redemption contract lives. |
| `contract-address`       | address | Yes      | -       | Send-and-receive redemption contract address. |
| `input-contract-address` | address | Yes      | -       | ERC-1155 token contract users send in.        |
| `input-token-id`         | number  | Yes      | -       | ERC-1155 token ID users send in.              |
| `refresh-interval`       | number  | Yes      | -       | Polling interval in milliseconds.             |

#### `<tl-snr-erc721tl>`

| Attribute                | Type    | Required | Default | Description                                   |
| ------------------------ | ------- | -------- | ------- | --------------------------------------------- |
| `chain-id`               | number  | Yes      | -       | Chain ID where the redemption contract lives. |
| `contract-address`       | address | Yes      | -       | Send-and-receive redemption contract address. |
| `input-contract-address` | address | Yes      | -       | ERC-721 token contract users send in.         |
| `input-token-id`         | number  | Yes      | -       | ERC-721 token ID users send in.               |
| `refresh-interval`       | number  | Yes      | -       | Polling interval in milliseconds.             |

#### `<tl-snr-currency>`

| Attribute          | Type    | Required | Default | Description                                            |
| ------------------ | ------- | -------- | ------- | ------------------------------------------------------ |
| `chain-id`         | number  | Yes      | -       | Chain ID where the redemption contract lives.          |
| `contract-address` | address | Yes      | -       | Send-and-receive currency redemption contract address. |
| `refresh-interval` | number  | Yes      | -       | Polling interval in milliseconds.                      |

### Lazy Loading

Embeds lazy-mount by default. Each element first renders a lightweight placeholder, then mounts the full React/Web3 component when it enters the viewport. Blockchain reads and polling do not start until that mount happens.

After an embed mounts once, it stays mounted even if the user scrolls away. This keeps wallet state, open dialogs, form input, and cached query data stable. It also means polling continues for embeds that have already been viewed.

The bundled stylesheet sets all `<tl-...>` custom elements to `display: block` so they behave like normal page sections and reserve predictable layout space. Keep the stylesheet loaded, or add equivalent host-page CSS if you are replacing the default styles.

### Style Overrides

You need to add the style overrides in the body

The components are built with tailwindcss v4 and Shadcn/ui. You'll override css variables for main colors and style. There are also classes that you can override for more control (advanced).

CSS Variables:

```
:root {
  --radius: 0.5rem;
  --title-font: "Inter";
  --body-font: "Inter";
  --mono-font: "Roboto Mono";
  --border-width: 2px;
  --background: oklch(1 0 0);
  --foreground: oklch(0.141 0.005 285.823);
  --card: oklch(1 0 0);
  --card-foreground: oklch(0.141 0.005 285.823);
  --popover: oklch(1 0 0);
  --popover-foreground: oklch(0.141 0.005 285.823);
  --primary: oklch(0.21 0.006 285.885);
  --primary-foreground: oklch(0.985 0 0);
  --secondary: oklch(0.967 0.001 286.375);
  --secondary-foreground: oklch(0.21 0.006 285.885);
  --muted: oklch(0.967 0.001 286.375);
  --muted-foreground: oklch(0.552 0.016 285.938);
  --accent: oklch(0.967 0.001 286.375);
  --accent-foreground: oklch(0.21 0.006 285.885);
  --destructive: oklch(0.577 0.245 27.325);
  --border: oklch(0.21 0.006 285.885);
  --input: oklch(0.92 0.004 286.32);
  --dialog: oklch(0.21 0.006 285.885);
  --ring: oklch(0.705 0.015 286.067);
  --chart-1: oklch(0.646 0.222 41.116);
  --chart-2: oklch(0.6 0.118 184.704);
  --chart-3: oklch(0.398 0.07 227.392);
  --chart-4: oklch(0.828 0.189 84.429);
  --chart-5: oklch(0.769 0.188 70.08);
  --sidebar: oklch(0.985 0 0);
  --sidebar-foreground: oklch(0.141 0.005 285.823);
  --sidebar-primary: oklch(0.21 0.006 285.885);
  --sidebar-primary-foreground: oklch(0.985 0 0);
  --sidebar-accent: oklch(0.967 0.001 286.375);
  --sidebar-accent-foreground: oklch(0.21 0.006 285.885);
  --sidebar-border: oklch(0.92 0.004 286.32);
  --sidebar-ring: oklch(0.705 0.015 286.067);
}

.dark {
  --background: oklch(0.141 0.005 285.823);
  --foreground: oklch(0.985 0 0);
  --card: oklch(0.21 0.006 285.885);
  --card-foreground: oklch(0.985 0 0);
  --popover: oklch(0.21 0.006 285.885);
  --popover-foreground: oklch(0.985 0 0);
  --primary: oklch(0.92 0.004 286.32);
  --primary-foreground: oklch(0.21 0.006 285.885);
  --secondary: oklch(0.274 0.006 286.033);
  --secondary-foreground: oklch(0.985 0 0);
  --muted: oklch(0.274 0.006 286.033);
  --muted-foreground: oklch(0.705 0.015 286.067);
  --accent: oklch(0.274 0.006 286.033);
  --accent-foreground: oklch(0.985 0 0);
  --destructive: oklch(0.704 0.191 22.216);
  --border: oklch(0.985 0 0);
  --input: oklch(1 0 0 / 15%);
  --dialog: oklch(0.985 0 0);
  --ring: oklch(0.552 0.016 285.938);
  --chart-1: oklch(0.488 0.243 264.376);
  --chart-2: oklch(0.696 0.17 162.48);
  --chart-3: oklch(0.769 0.188 70.08);
  --chart-4: oklch(0.627 0.265 303.9);
  --chart-5: oklch(0.645 0.246 16.439);
  --sidebar: oklch(0.21 0.006 285.885);
  --sidebar-foreground: oklch(0.985 0 0);
  --sidebar-primary: oklch(0.488 0.243 264.376);
  --sidebar-primary-foreground: oklch(0.985 0 0);
  --sidebar-accent: oklch(0.274 0.006 286.033);
  --sidebar-accent-foreground: oklch(0.985 0 0);
  --sidebar-border: oklch(1 0 0 / 10%);
  --sidebar-ring: oklch(0.552 0.016 285.938);
}
```

Custom Class Overrides:

```
.tl-root
.tl-lazy-placeholder
.tl-address-display
.tl-dialog-overlay
.tl-dialog-content
.tl-dialog-header
.tl-dialog-footer
.tl-dialog-title
.tl-dialog-description
.tl-dialog-action
.tl-dialog-cancel
.tl-dialog-close
.tl-input
.tl-title-3
.tl-title-4
.tl-paragraph
.tl-caption
.tl-button-default
.tl-button-destructive
.tl-button-outline
.tl-button-secondary
.tl-button-ghost
.tl-button-link
.tl-button-size-default
.tl-button-size-sm
.tl-button-size-lg
.tl-button-size-icon
.tl-toaster
.tl-countdown-root
.tl-countdown-text-group
.tl-countdown-label
.tl-countdown-time
.tl-tx-dialog-title
.tl-tx-dialog-root
.tl-tx-dialog-spinner
.tl-tx-dialog-text
.tl-wrapper
.tl-connect-button
.tl-siwe-button
.tl-siwe-connect-button
.tl-auction-root
.tl-auction-top-section
.tl-auction-price-label
.tl-auction-price-display
.tl-auction-highest-bidder-section
.tl-auction-highest-bidder-display
.tl-auction-button-group
.tl-auction-submit-bid-button
.tl-auction-buy-now-button
.tl-auction-settle-button
.tl-auction-connect-button
.tl-auction-duration-caption
.tl-auction-bottom-text-section
.tl-auction-view-on-transient-text
.tl-auction-bids-caption
.tl-auction-history-title
.tl-auction-history-group
.tl-auction-history-bid
.tl-auction-history-list-entry
.tl-auction-history-cancel-entry
.tl-auction-history-bid-entry
.tl-auction-history-settle-entry
.tl-auction-history-buy-now-entry
.tl-auction-empty-state-container
.tl-auction-bid-title
.tl-auction-bid-root
.tl-auction-bid-input-group
.tl-auction-bid-input
.tl-auction-bid-button
.tl-auction-min-bid
.tl-mint-root
.tl-mint-top-section
.tl-mint-phase
.tl-mint-supply
.tl-mint-middle-section
.tl-mint-middle-left-section
.tl-mint-allowance-caption
.tl-mint-price-caption
.tl-mint-price
.tl-mint-protocol-fee-caption
.tl-mint-middle-right-section
.tl-mint-bottom-section
.tl-mint-button
.tl-mint-connect-button
.tl-mint-recipient-section
.tl-mint-recipient-display
.tl-mint-to-other-button
.tl-mint-disabled-text
.tl-mint-recipient-dialog
.tl-mint-recipient-input
.tl-mint-save-recipient
.tl-mint-success-dialog-root
.tl-mint-recipient-dialog
.tl-mint-success-token-root
.tl-mint-success-token-image
.tl-mint-success-token-placeholder
.tl-mint-success-token-text
.tl-mint-success-token-title
.tl-mint-success-view-on-opensea-text
.tl-mint-success-loading-text
.tl-mint-view-on-transient-text
.tl-snr-root
.tl-snr-redemption-data-container
.tl-snr-user-data-container
.tl-snr-connect-button
.tl-snr-section-title
.tl-snr-data-span
.tl-snr-link
.tl-snr-counter-container
.tl-snr-actions-container
.tl-snr-redemption-disabled-text
.tl-snr-action-button
.tl-snr-success-dialog-root
.tl-snr-success-dialog
.tl-snr-success-token-root
.tl-snr-success-token-image
.tl-snr-success-token-text
.tl-snr-success-token-title
.tl-snr-success-view-on-opensea-text
.tl-snr-success-loading-text
```

### Custom Events

The components dispatch events on `document` so you can hook in your own logic (analytics, confirmations, redirects, etc.). Each event carries its data on the standard `event.detail` field:

```
document.addEventListener("tl-mint-721", (event) => {
  console.log("Minted!", event.detail);
  // e.g. { sender, chainId, contractAddress, logs }
});
```

Wallet status is also exposed as a global snapshot for synchronous checks, including after page refresh/reconnect flows:

```
window.tlWallet?.isConnected;
window.tlWallet?.address;
window.tlWallet?.chainId;
window.tlWallet?.status;
```

`window.tlWallet` is updated from the shared Wagmi account state whenever an embed with Web3 support mounts and whenever the wallet status, address, or chain changes. It is a snapshot, so read it again when you need the latest value.

The snapshot shape is:

```
type TLWalletStatus = {
  status: "connected" | "connecting" | "reconnecting" | "disconnected";
  isConnected: boolean;
  address?: `0x${string}`;
  chainId?: number;
};
```

For refresh-safe integrations, read the current snapshot once and then listen for future changes:

```
function handleWalletStatus(wallet) {
  if (!wallet?.isConnected) {
    console.log("No wallet connected");
    return;
  }

  console.log("Connected wallet:", wallet.address);
  console.log("Connected chain:", wallet.chainId);
}

handleWalletStatus(window.tlWallet);

document.addEventListener("tl-wallet-status-change", (event) => {
  handleWalletStatus(event.detail);
});
```

The legacy `tl-wallet-connect` and `tl-wallet-disconnect` events are still emitted for compatibility. Prefer `window.tlWallet` plus `tl-wallet-status-change` when your page needs to know the current wallet state after a refresh, reconnect, account switch, or chain switch.

| Event                           | Fired when                               | `event.detail` contains                                  |
| ------------------------------- | ---------------------------------------- | -------------------------------------------------------- |
| `tl-wallet-connect`             | A wallet connects                        | `address`                                                |
| `tl-wallet-disconnect`          | A wallet disconnects                     | *(none)*                                                 |
| `tl-wallet-status-change`       | Wallet status, address, or chain changes | `status, isConnected, address?, chainId?`                |
| `tl-auction-bid`                | A bid is placed                          | `sender, chainId, contractAddress, tokenId, listing?`    |
| `tl-buy-now`                    | An item is bought now                    | `sender, chainId, contractAddress, tokenId, listing?`    |
| `tl-auction-settle`             | An auction is settled                    | `sender, chainId, contractAddress, tokenId, listing?`    |
| `tl-mint-721`                   | An ERC-721 is minted                     | `sender, chainId, contractAddress, logs`                 |
| `tl-mint-1155`                  | An ERC-1155 is minted                    | `sender, chainId, contractAddress, tokenId`              |
| `tl-siwe`                       | A user signs in with Ethereum            | `message, signature`                                     |
| `tl-snr-erc1155tl-raffle-entry` | A raffle entry is submitted              | `sender, chainId, raffleContractAddress`                 |
| `tl-snr-erc1155tl-raffle-claim` | A raffle prize is claimed                | `sender, chainId, raffleContractAddress, isWinner`       |
| `tl-snr-currency-redemption`    | A currency redemption succeeds           | `sender, chainId, contractAddress, numRedemptions`       |
| `tl-snr-erc1155tl-redemption`   | An ERC-1155 redemption succeeds          | `sender, chainId, contractAddress, numRedemptions`       |
| `tl-snr-erc721tl-redemption`    | An ERC-721 redemption succeeds           | `sender, chainId, contractAddress, numRedemptions, logs` |


# Supported Blockchains

The following blockchains are supported by Transient Labs.

* Ethereum
* Sepolia
* Shape
* Shape Sepolia
* Base
* Base Sepolia
* Arbitrum One
* Arbitrum Sepolia


# tl-sol-tools

A page about our solidity tools

Transient Labs has created a library of helpful Solidity tools called `tl-sol-tools`

### Source

<https://github.com/Transient-Labs/tl-sol-tools>

### Latest Docs (3.1.1)

<https://cdn.transientlabs.xyz/docs/tl-sol-tools/v3.1.1/>

### All Docs

<table><thead><tr><th width="124">Version</th><th>Link</th></tr></thead><tbody><tr><td>3.1.1</td><td><a href="https://cdn.transientlabs.xyz/docs/tl-sol-tools/v3.1.1/">https://cdn.transientlabs.xyz/docs/tl-sol-tools/v3.1.1/</a></td></tr><tr><td></td><td></td></tr><tr><td></td><td></td></tr></tbody></table>


# Licensing

All our open source code is copyright to Transient Labs, Inc and licensed under the [MIT](https://opensource.org/license/mit/) license. If you build based on anything we have developed, we require copyright attribution per the license.

We can't wait to see what you build!


# Batch Upload Secret JSON

Secret JSON for batch uploads in the lab

The Lab supports batch uploading tokens. On the surface, it's pretty simplistic as it let's you select files and write a universal description for each. This works for most people, however, for something more complex, we developed a secret JSON input to the description.

To get started, here is a video overview.

{% embed url="<https://www.loom.com/share/cc32f19d8c1446338a1ede0cb8ab4e3c?sid=32bb1ddc-5fce-4ccf-8d0a-92279be797f6>" %}

Use this [template google spreadsheet](https://docs.google.com/spreadsheets/d/19nUJrgXW6dGRslcJ187bvAg2PmUmfKtr3ZlFas_eeMU/edit?usp=sharing) that you can fork.

Use the codepen below to develop the JSON you need!

<https://codepen.io/mpeyfuss/full/PwopMjv>


# Bug Bounty Program

## Overview

Transient Labs is the premier innovation platform for web3 creators, projects, and ecosystems around the world. Our mission is to unlock the potential of blockchain and smart contract technology, and redefine what ownership means now and in the future.

For more information about Transient Labs, please visit<https://transientlabs.xyz>

This bug bounty program is focused on their smart contracts and is focused on preventing:

* Loss of funds or NFTs by freezing or theft
* Denial of service (smart contract is made unable to operate)
* Access control is bypassed, including privilege escalation
* Smart contract does not behave as intended

This is an overlay bug bounty program for Transient Labs smart contracts, websites, and applications.

## Reward By Threat Level

Rewards are distributed according to the impact of the vulnerability based on the [Immunefi Vulnerability Severity Classification System V2.3](https://immunefi.com/immunefi-vulnerability-severity-classification-system-v2-3/). This is a simplified 4-level scale, with separate scales for websites/apps and smart contracts/blockchains, encompassing everything from consequence of exploitation to privilege required to likelihood of a successful exploit.

The rewards stated here are additive to any existing bug bounty programs hosted by projects that are currently using Transient Labs technology.

Critical and high severity bug reports must come with a PoC in order to be considered for a reward.

Payouts are handled by the Transient Labs team directly and are denominated in USD. However, payouts are done in USDC.

#### Smart Contracts

| **Severity Level** | **Payout** | **PoC Required** |
| ------------------ | ---------- | ---------------- |
| ‼️ Critical        | $5,000     | Yes              |
| ❗️High             | $2,000     | Yes              |
| ⚠️ Medium          | $1,000     | No               |
| ❎ Low              | $100       | No               |

#### **Websites and Apps**

| **Severity Level** | **Payout** | **PoC Required** |
| ------------------ | ---------- | ---------------- |
| ‼️ Critical        | $2,000     | Yes              |
| ❗️High             | $1,000     | Yes              |
| ⚠️ Medium          | $500       | Yes              |
| ❎ Low              | $100       | Yes              |

## Assets in Scope

<https://github.com/Transient-Labs/tl-creator-contracts>

<https://github.com/Transient-Labs/tl-stacks>

<https://transient.xyz>

[https://transientlabs.xyz](https://transientlabs.xyz/)

## Out of Scope & Rules

#### General

The following vulnerabilities are excluded from the rewards for this bug bounty program:

* Impacts requiring attacks that the reporter has already exploited themselves, leading to damage
* Impacts caused by attacks requiring access to leaked keys/credentials
* Impacts caused by attacks requiring access to privileged addresses (governance, strategist) except in such cases where the contracts are intended to have no privileged access to functions that make the attack possible
* Impacts relying on attacks involving the depegging of an external stablecoin where the attacker does not directly cause the depegging due to a bug in code
* Mentions of secrets, access tokens, API keys, private keys, etc. in Github will be considered out of scope without proof that they are in-use in production
* Best practice recommendations
* Feature requests
* Impacts on test files and configuration files unless stated otherwise in the bug bounty program

#### Smart Contracts & Blockchain

* Incorrect data supplied by third party oracles
  * Not to exclude oracle manipulation/flash loan attacks
* Basic economic governance attacks (e.g. 51% attack)
* Susceptibility to block timestamp manipulation
* Lack of liquidity
* Best practice critiques
* Sybil attacks
* Impacts involving centralization risks

#### Websites & Apps

* Theoretical impacts without any proof or demonstration
* Sub-domain takeovers for non-production domains.
* Impacts involving attacks requiring physical access to the victim device
* Impacts involving attacks requiring access to the local network of the victim
* Reflected plain text injection (e.g. url parameters, path, etc.)
  * This does not exclude reflected HTML injection with or without JavaScript
  * This does not exclude persistent plain text injection
* Any impacts involving self-XSS
* Captcha bypass using OCR without impact demonstration
* CSRF with no state modifying security impact (e.g. logout CSRF)
* Impacts related to missing HTTP Security Headers (such as X-FRAME-OPTIONS) or cookie security flags (such as “httponly”) without demonstration of impact
* Server-side non-confidential information disclosure, such as IPs, server names, and most stack traces
* Impacts causing only the enumeration or confirmation of the existence of users or tenants
* Impacts caused by vulnerabilities requiring un-prompted, in-app user actions that are not part of the normal app workflows
* Lack of SSL/TLS best practices
* Impacts that only require DDoS
* UX and UI impacts that do not materially disrupt use of the platform
* Impacts primarily caused by browser/plugin defects
* Leakage of non sensitive API keys (e.g. Etherscan, Infura, Alchemy, etc.)
* Any vulnerability exploit requiring browser bugs for exploitation (e.g. CSP bypass)
* SPF/DMARC misconfigured records
* Missing HTTP Headers without demonstrated impact
* Automated scanner reports without demonstrated impact
* UI/UX best practice recommendations
* Non-future-proof NFT rendering
* General "bugs" that temporarily impact functionality

#### Prohibited Actions

The following activities are prohibited by this bug bounty program:

* Any testing on mainnet or public testnet deployed code; all testing should be done on local-forks of either public testnet or mainnet
* Any testing with pricing oracles or third-party smart contracts
* Attempting phishing or other social engineering attacks against our employees and/or customers
* Any testing with third-party systems and applications (e.g. browser extensions) as well as websites (e.g. SSO providers, advertising networks)
* Any denial of service attacks that are executed against project assets
* Automated testing of services that generates significant amounts of traffic
* Public disclosure of an unpatched vulnerability in an embargoed bounty

### Contact

You can contact [dev@transientlabs.xyz](https://www.notion.so/https-lab-transientlabs-xyz-invite_code-86509683a673288eafb13997-aa6dce8901754c929aa75a8d65d0aa57?pvs=21) to report of any findings. We’ll be in contact with you via email and may want to set up a call to discuss in detail after reviewing the report. We truly appreciate the reporting of any findings! 🚀


