-
Notifications
You must be signed in to change notification settings - Fork 3
Description
That's a set of two ESIPs to enable trading of Ethscriptions on Facet, trustlessly without bridges, signers, signatures, admins or keys.
First ESIP: Enable transferring through Facet transaction payload
The idea is to allow "basic transfers" (single hash transfers) and ESIP-5 (bulk transfers) compliant transfers through Facet transaction payload. It would be exactly the same, but instead of bare calldata, it would be in the data field of the Facet payload. Each Facet transaction is RLP formatted data in specific way.
One way to look at that is to consider such transfers as "burning", because you can't really transfer to someone else using that method. It may seem dumb, because you can "burn" ethscriptions by sending to any burn address, but this ESIP is just an additional mechanism helping the bigger picture of enabling trading on Facet, without bridges or priviledge. It's a protocol-native, official, way of burning through which others can integrate with the whole protocol and do different things. It's a way to guarantee no one owns or controls the ethscription once burned. The Ethscriptions Indexer would detect that RLP facet-formatted transaction, extract the ethscription ids and set their current_owner to the 0x0000...000face7 inbox burn address, because in reality all facet-formatted L1 transactions are having 0x000..face7 as to.
With this ESIP, we make a non dataURI-based Ethscription transaction to interact/signal/talk with the Ethscriptions Protocol, effectively making it "regular transfer" in the eyes of Ethscriptions protocol.
How?
To burn ethscriptions you would send facet transactions, using the Facet SDK for example.
This is an example code to construct such transactions without the SDK.
The to usually is a Facet-deployed contract address or Facet EOA.
The data would be ESIP-5 compliant list of ethscription ids to burn/transfer.
This would trigger the fallback function on the to facet deployed contract. This contract would be an ERC721 NFT compliant contract.
function sendTx({ chainId, to, value, gasLimit, data, mineBoost }: any) {
const transactionData = [
// 1_027_303 is `0xface7` for mainnet, 16_436_858 is `0xface7a` for sepolia
toHex(chainId === 1 ? 1_027_303 : 16_436_858),
to ?? '0x',
value ? toHex(value) : '0x',
gasLimit ? toHex(gasLimit) : '0x',
data ?? '0x',
mineBoost ?? '0x',
];
const encodedTransaction = concatHex([toHex(70), toRlp(transactionData)]);
return encodedTransaction;
}
const encodedTx = sendTx({
to: '0x1111000000000000000000000000000000001111',
// "bridging" these ethscriptions
// 0x01eee5be1b69d05322456d2664116422e8e04faf8e45f5ad6a054a5723c04c7e
// 0xa992926edc1f701adc4ab9f5d035d35d6399948c75e16d3895204aa08b5cd643
data: '0x01eee5be1b69d05322456d2664116422e8e04faf8e45f5ad6a054a5723c04c7ea992926edc1f701adc4ab9f5d035d35d6399948c75e16d3895204aa08b5cd643',
});
console.log(encodedTx);
// => 0x46f85e83face7a9411110000000000000000000000000000000011118080b84001eee5be1b69d05322456d2664116422e8e04faf8e45f5ad6a054a5723c04c7ea992926edc1f701adc4ab9f5d035d35d6399948c75e16d3895204aa08b5cd64380
// separated for readability:
// 0x46f85e83face7a94
// 1111000000000000000000000000000000001111
// 8080b840
// 01eee5be1b69d05322456d2664116422e8e04faf8e45f5ad6a054a5723c04c7e
// a992926edc1f701adc4ab9f5d035d35d6399948c75e16d3895204aa08b5cd643The Ethscriptions Indexer detects that, and extracts the two Ethscription IDs, and set their current_owner as 0x0000...000face7.
That's all. From now on, they are burned. But here's the twist, once we have the second ESIP, which allows Facet contracts to emit ESIP-1 and ESIP-2 events (ESIP-2 specifically because it verifies with previous_owner), the Ethscriptions indexer detects that and effectively "revive" them and switches the current_owner to be the one passed to the event.
One thing i just noticed is that maybe this ESIP-2-like event should support passing multiple ethscriptions to be transferred at once.
All that is trustless. It's just a transfer to uncontrolled EOA. The trust is not more or less than trusting the Ethscriptions Indexer with ESIP-2 as it is currently.
Note on Ethscriptions as Facet NFTs
When Facet L2 NFT contract "receives" Ethscriptions in that way, it would convert each ethscription id (transaction hash) to Uint Big number and store this link in that same contract, just like it is currently with non-sequential tokenIds, like in ENS where each domain/name is stored as big number representation of the hash of the name.
Like 42967269751179439155718323597133023707647870299425984815486867264501114208048 is the tokenId of 5964.eth ENS name.
Similar with ethscriptions-based Facet L2 NFTs, this 3305568362307615822298477236865643378946845502932415825777752632693561433502 token id would be a big number (uint) representation of the 0x074ee2a9028840b3aa8962a2eec5560f5b0a5dbfe10e67c9685057d419371d9e ethscription (transaction hash).
In the tokenURI of that NFT contract, there would be special esc:// protocol, similar to IPFS or HTTPs, but effectively storing assets data on L1 Ethscriptions. Once a Facet NFT platform detects that it should try to resolve from ANY/multiple Ethscriptions APIs/Indexers. The final returned value should look like esc://content/tokenId_or_ethscriptionId. The resolved ethscription content could be either a raw image/data or an ERC721 JSON. If it's an ERC721 Metadata json, it should also support esc:// in its image field, or directly a data URI.
There is an ESIP-9 #18 endpoints RFC that aims to standardize and soft-require all sites in the Ethscriptions ecosystem to have at least these endpoints /ethscriptions/:id/content, /ethscriptions/:id/metadata and /content/:id on their root domains, not just in APIs and subdomains. The last one /content/:id follows the Ordinals example. And allows having esc://content/ set on Facet ERC721 NFT contracts through setBaseURI and then concat baseURI() + tokenId, simplifying UX and UI. All of these are already implemented on calldata.space root and its API subdomains too.
https://calldata.space/ethscriptions/123/content - cached forever
https://calldata.space/ethscriptions/123/metadata - cached forever, alias of API's /ethscriptions/123 -
https://calldata.space/ethscriptions/123/owners - current owner, previous owner, and other moving parts
https://calldata.space/ethscriptions/123/numbers - last transfer, ethscription number, creation block and time, and etc
https://calldata.space/ethscriptions/123/transfers - all transfers
https://mainnet.api.calldata.space/ethscriptions/123/content
https://sepolia.api.calldata.space/ethscriptions/123/content
where 123 can be ethscription number, transaction hash, or BigInt representation of the transaction hash. Will add support for /content/:id on the root in a bit.
That's why i'm pushing "standardization" and ESIP-9 for half a year. It unlocks a lot, plus the side-effect of unbreakable "recursive" ethscriptions.
Second ESIP: Respect ESIP-1/2 events (or similar) emitted by Facet-deployed contracts
That's a second ESIP. Allowing Facet contracts to emit ESIP-1 and ESIP-2 compliant events, which in turn would be detected by Ethscriptions indexer and treated just like regular L1 ESIP-1/2 (but with bulk/batch support), nothing new.
Once a Facet deployed contract (ERC721 / NFT in most cases) triggered by a user "withdrawal" request, it burns the NFT and emit an ESIP2-like event that the Ethscription Indexer detects, and rewrites/switches the current_owner from 0x0000...000face7 to the new owner passed through the event. I call that "revive" from "burned state".
FAQ
- What happens if a user pass hashes through facet transactions that are not valid ethscriptions? - Nothing. It's their fault and cost, and no security issue. They could do it, but there's no sense in doing so, so they would stop. At best, it would be broken data/image on the L2 side on the Facet NFT platforms.
- (above rephrased) What if the ethscriptions are invalid? - Nothing. The Facet L2 contract just assumes it's correct. If it's not valid ethscription, it's not a problem from L1/ethscriptions protocol perspective, it's like transferring non-ethscription transaction hash currently - nothing happens at protocol level. And it's not a problem except a UI bug in the L2/nft platform perspective.
- Is it trustless and without privilege? - Yes. In the eyes of the Ethscriptions Protocol, such ethscriptions would effectively be "burned" and inaccessible by no oen, until someone trigger a "withdrawal"/unwrap from the L2, eg. someone just bought the NFT token from NFT platform and decided to have it on Ethscriptions L1 land again.
- How the Facet L2 contract knows if you are really the owner of the Ethscritpions you passed? - Well, that's a tricky thing. It would require an update to Facet node, to make a basic check about that and not consider such transactions a valid facet transactions if the owner of these ethscriptions is not correct. And no, that's not a trust risk or privilege, it would be part of every Facet node. It's not more or less trust than trusting the Facet nodes and its different folks/parties that runs that software.
- From above comes the following: What happens if a user send a facet transaction with ethscriptions he don't own? - Nothing, Why? Assuming above is implemented in Facet, it will be an ignored/reject/failed Facet transaction, so from L2 perspective nothing happens. From L1 Ethscriptions Protocol perspective also nothing, because you're not the owner of these ethscriptions, so the indexer just ignore that transaction as invalid, like it does currently with every basic transfer, L1 contract-initiated ESIP-1/2, or ESIP-5.
- If (4) is not implemented in Facet, at worst we would need a signature only on "deposit/bridge", but not on withdrawals. Which would kinda sucks, because the
confirmDepositis the most expensive thing, because it happens on L1 Bridge contract. - Is that a "dependence" on Facet? - For the first ESIP (burn transfers), no. Because Ethscription Indexers can detect and extract that easily from the transaction input calldata. For the second ESIP, yes / kind of, the Ethscription Indexers would need to listen on Facet RPC for contract-emitted ESIP2-like events, but it's not a big deal from technical and implementation point of view, because it's the same code as for L1, just with different RPC url.