[EP5.3] [TempCheck] ENS On Solana

DESCRIPTION: ENS on Solana (EoS) for Solana by Solana

[EP5.3] [TempCheck] ENS On Solana

Status TempCheck
Discussion Thread
Discussion TempCheck


EIP-5559 and EIP-3668 in conjunction, known as CCIP-Write and CCIP-Read protocols respectively, are capable of securely writing to and reading from any blockchain or arbitrary storage. This in principle allows for a seamless native integration of ENS into any arbitrary on-chain or off-chain ecosystem. This draft outlines the proposal for a core ENS integration into Solana in particular, potential benefits to the ENS ecosystem and Solana ecosystems, and a substantial revenue stream for the ENS DAO.


Solana currently lacks a good native naming system due to the failure of Solana Naming Service (SNS). ENS in this case has an opportunity to develop horizontally across ecosystems, in particular into Solana ecosystem which currently ranks within top 5 in terms of market capitalisation and is beating Ethereum in DeFi TVL as well as numbers of total and daily active wallets. This proposal forsees ENS serving the users on the Solana blockchain through s.eth namespace on Ethereum mainnet which is currently forbidden by ENS registrar. A dedicated storage-oriented Solana program is foreseen to be deployed on Solana hosting the users’ ENS records, which can be written to via CCIP-Write. The CCIP-Read-enabled Solana Resolver on Ethereum mainnet is tasked with the job of fetching the records from the program on Solana blockchain, performing any state verifications if necessary, and finally resolving it in Solana wallets like Phantom. Needless to say, ENS must be supported by native Solana wallets including EIP-3668 in the aforementioned outline. This foreseen construction of ENS on Solana (EoS) is of the form ‘ENS on Solana (wallets) for Solana (users) by Solana (resolver)’ since the ENS records are hosted on Solana to be used by Solana users in their Solana wallets.


There are two ways of implementing the functionality described in the section above:

  1. Issue each domain.s.eth on Ethereum mainnet by wrapping s.eth with ENS Name Wrapper alongside necessary config that makes domain.s.eth an absolutely ownable ERC-1155 NFT with preset Solana resolver implementing CCIP-Read and CCIP-Write. These NFTs will be tradeable on Ethereum only.

  2. Use ENSIP-10 wildcard resolver on s.eth with CCIP-Read support, which delegates the task of determining ownership of domain.s.eth to a Solana NFT program. The resulting NFTs will be tradeable locally on Solana only.

The latter method appears more suitable and cost efficient for native Solana target audience.


This proposal requires the DAO to release s.eth from the registrar for registration by ENS DAO through an executable vote.

Pricing Modal

The following pricing mechanism is proposed:

Domain Price 1 Price 2
12345.s.eth 2$/year 1$/year
1234.s.eth 25$/year 5$/year
123.s.eth 75$/year 10$/year
12.s.eth 100$/year 25$/year
1.s.eth 200$/year 50$/year

This pricing model 1 adds roughly 66% to the DAO’s revenue per year; given the current annualised revenue of $18 million at the moment, ENS DAO can expect additional $12 million/year from *.s.eth registrations and renewals. The pricing model 2 adds roughly 20% to the DAO’s wallet amounting to annualised revenue of $4 million/year.

Registration Tapering

In order to ensure equitable domain ownership and prevent squatting, this proposal suggests that registrations for *.s.eth be tapered in time according the following method:

  1. Allow users to post commit for their desired registrations in 24 hour periods. Cap the commits at some value total for each period.

  2. At the end of each 24 hour period, randomly select N commits from total to continue with their registration, and let the remaining total - N commits pass on into the next 24 hour period.

  3. Allow the users to fill the slots up to value total for the next round and repeat.

This proposal suggests the following values for epochs, N as function of labels’ character lengths:

Epochs N(1) N(12) N(123) N(1234) N(12345) Revenue 1 Revenue 2
1st day all 400 800 1200 8000 $166,000/day $37,000/day
2-3 days 0 400 800 1200 8000 $146,000/day $32,000/day
4-60 days 0 0 800 1200 8000 $106,000/day $22,000/day
61-90 days 0 0 0 1200 8000 $46,000/day $14,000/day
91-365 days 0 0 0 0 8000 $16,000/day $8,000/day

where the N(*) values correspond to N as function of char length * and total is set such that total = N × 2. Using this tapering method, the DAO can expect an annualised revenue of nearly $12,000,000 for price plan 1 or $4,000,000 for price plan 2.

This tapering can be applied to both methods described above. Note that this is only an initial suggestion and the implementation is open to better ideas.


The following python script is useful if anyone wants to test their own custom price plans and suggest alternatives besides plan 1 and 2. Try it out in a simple IDE here: Script

# Example price plan as an array; [1, 2, 3, 4, 5+] chars in $
price_plan = [200, 100, 75, 25, 2]

def calculate_revenue(price_plan):
    # Initialize the revenue chart
    revenue_chart = []
    # Define the tapering epochs, days in each epoch and corresponding N values
    epochs = ["1st day", "2-3 days", "4-60 days", "61-90 days", "91-365 days"]
    days = [1, 2, 57, 30, 275]
    N_values = [
        [100, 400, 800, 1200, 8000],
          [0, 400, 800, 1200, 8000],
            [0, 0, 800, 1200, 8000],
              [0, 0, 0, 1200, 8000],
                 [0, 0, 0, 0, 8000],
    # Calculate daily revenue and revenue for each epoch
    for i in range(len(epochs)):
        daily_revenue = sum(x * y for x, y in zip(N_values[i], price_plan))
        epoch_revenue = daily_revenue * days[i]
        revenue_chart.append((epochs[i], epoch_revenue, daily_revenue))
    return revenue_chart

def print_revenue_chart(revenue_chart):
    # Print the revenue chart header
    print("Epoch         |  Epoch Rev   |  Daily Rev")
    yearly_revenue = sum(revenue for _, revenue, _ in revenue_chart)
    # Print revenue for each epoch
    for epoch, revenue, daily in revenue_chart:
        print(f"{epoch.ljust(13)} | ${revenue:,.0f}   | ${daily:,.0f}")
    print("Yearly Revenue:", f"${yearly_revenue:,.0f}")

# Calculate revenue chart
revenue_chart = calculate_revenue(price_plan)
# Print the revenue chart
print("Revenue Chart:")

Funding Request

SysStruct is requesting a funding of $500,000 for the duration of one year to work on this mission and make ENS truly multi-chain. The funding is divided into 5 tranches of $100,000 each released upon completion of pre-specified milestones at the end of each quarter. The funding encompasses the following tasks:

  1. Proposal introducing StorageHandledBySolana() revert to EIP-5559.
  2. Collaborating with Solana Wallet Provider(s) to integrate ENS.
  3. Collaborating with Solana Foundation, Solana’s biggest NFT marketplace tensor.hq and ENS Labs for a dedicated launch.
  4. The entire end-to-end codebase including contracts, clients and any infrastructrual packages.
Tranche Funds When? Milestones
0 $100,000 -Q1 EIP-X, Full Specs
1 $100,000 Q1-Q2 Prototype, Testnet
2 $100,000 Q2-Q3 Testing, Audit
3 $100,000 Q3-Q4 Mainnet, Launch
4 $100,000 Q4- End

Next Steps

Following this TempCheck, a social proposal will be floated finalising the price plan and tapering methodology/parameters. Following success of social proposal, an executable proposal will be floated with the necessary calls to release s.eth from ENS root to ENS DAO.


That’s incredible! Possibly the best DAO proposal in a long time.

ENS must be scalable, including in the space of other networks; SNS is truly Unusable and unpopular product.

1 Like

there is one problem though, Solana is off during the weekend :melting_face:

1 Like

I like this proposal.
My only gripe is the pricing.
I would suggest same price structure as in ethereum. And same 3 character minimum restriction as well.

I think there’s a few things here:

  • 1-letter .eth Names

    • I agree other chains are a good use-case but I’m sure other ideas exist.
  • Cross-chain registrations

    • This requires some kind of bridging / paymaster setup for .eth
    • As you say, a different basename like s.eth, can be ENSIP-10 and offchain and only needs trustless gateway infrastructure to be ENS-grade.
  • Standardization

    • If you store metadata on Solana, I think there should be some design consideration for the most modern-but-backwards compatible storage setup that supports current and potentially-future ENS protocol changes.
      • coinless addr() ? pubkey() ?
      • resolve() expects EVM ABI-encoded calls
      • what about native resolution and reverses?
      • is there a Solana provider ENS front-end
      • will it resolve addr(solana) of raffy.eth as expected (eg. Solana-based CCIP-Read)

Solana → EVM L2 is probably significantly easier than a native Solana implementation, but the ultimate value of ENS comes from the decentralized qualities of on-chain .eth registrations, which has encouraged wide-spread client and wallet support.

It’s unclear to me how much of “I can register a name on Solana and pay with Sol and it works in ENS” cares about native-storage vs ease-of-use.

Even a native Solana solution would have to bounce all non-native resolution to an Ethereum RPC or some kind of new cross-chain trustless gateway interconnect.

domain.s.eth and domain.eth cannot have the same price. Subdomains should at least be 80% discounted.

Why though? These are subdomains.

Indeed. The thought process was that 1L can be other blockchains and 2L can be ETH L2s. In principle, whatever base namespace DAO chooses, it must reflect in the pricing. We are open to suggestions.

Correct, trustless gateway infrastructure will need to be ENS-grade as well as DAO-grade.

Those are very specific implementation details that are perhaps best left for later stages (this is a TempCheck!) and these will be part of EIP-X which is proposed in Q1. But I will give my personal opinion since you asked.

Must be returned according to the base namespace; check whether .eth or .s.eth.

That’s what they will get. resolve() is agnostic to data storage and ABIs can be casted.

What about it?

Nope! This is a milestone in Q1-Q2.

If implemented correctly by the Solana wallets, then yes! raffy.eth and raffy.s.eth can be programmed to return your Solana address in Solana wallets.

These are also on-chain registrations; it’s just a different chain. The qualitative value of these subdomains lies in the restricted s.eth namespace and the quantitative value (pricing) is determined by the demand among target audience (Solana users).

Solana users would certainly want to pay in Solana wallets with $SOL since that’s where they’ll be using it. That is ease of use. What’s easier than paying in their native currency and wallets? They will never have to deal with the Ethereum blockchain since that is all backend infrastructure to them. A Solana user will simply interact with Solana contract and no more. They will claim it on Solana, they will set records on Solana and they will use it on Solana. In the background, Ethereum and Solana blockchains will work together to ensure that these users are well served.

Correct, that’s why you’ll need Solana wallets to support ETH infrastructure, which Phantom already does.

1 Like

Do you have any data backing your claim that SNS is failing?

How would you achieve this without relying on trusted gateway? The state verification done in other L2 resolver is using the rollup mechanism. Since Sonala is not l2, not sure how you can do that on Ethereum L1.

Also what is your experience on building on Solana smart contracts? Assuming you use CCIP-read by moving resolver to Solana itself , all the registration logic must be implemented in Solana smart contract and paying the gas and registration fee in $SOL, not using $ETH. Do you have any open source repo demonstrating your Solana development capability?

FYI, Ecosystem WG has given grant to Nethermind that created a prototype for Starknet CCIP-read integration in Cario (the native programming language for Starkenet) and Nethermind is known within Starknet ecosystem of their development contribution. I would like any team tackling on the Solana integration to be equally active participant on their ecosystem, otherwise it will be very difficult to get buy in on the wallet integration.

  • Current state of their SDK returns wrong records even for their parent domain bonfida.sol

  • Their flawed auction model led to most names getting squatted on very early which they later changed but it was too late. Now they have a fund which buys back squatted domains. Good luck with that!

    Weekly Roundup<!-- --> | Bonfida

  • It is based on lifetime ownership model (which is provably flawed) and not a renewal model like ENS (which is provably good)

  • Their eth.limo equivalent is sol-domain.org which returns 404

If it walks like a duck and talks like a duck, it is probably a duck.

That is correct. In the worst case scenario, it will have to be a DAO-managed trusted gateway (probably delegated to ENS Labs for management!). In the best case scenario, we can perform local state verification. This is partly an open question but the two scenarios I mentioned cover the entire range. Whenever ENS begins to offer services in other ecosystems, the same question will arise. So it’s good to answer it now when the opportunity has presented itself.

How about I give you a working resolver in Rust right now?

use solana_program::{
    account_info::{next_account_info, AccountInfo},
    program_pack::{Pack, Sealed},
    sysvar::{rent::Rent, Sysvar},
use std::str;

// Define the program ID
const PROGRAM_ID: [u8; 32] = [0; 32];

// Define the record struct
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Record {
    pub owner: Pubkey,
    pub value: String,

impl Sealed for Record {}

impl Pack for Record {
    const LEN: usize = 32 + 256; // Size of Pubkey + String (256 bytes)
    // Unpacks the data into the struct
    fn unpack_from_slice(src: &[u8]) -> Result<Self, ProgramError> {
        let owner = Pubkey::new(&src[..32]);
        let value = str::from_utf8(&src[32..]).map_err(|_| ProgramError::InvalidAccountData)?;
        Ok(Record { owner, value: value.to_string() })

    // Packs the struct into bytes
    fn pack_into_slice(&self, dst: &mut [u8]) {
        let owner_bytes = self.owner.to_bytes();
        let value_bytes = self.value.as_bytes();

// Main program entry point
pub fn store_record(
    ctx: Context,
    record_owner: Pubkey,
    record_value: String,
) -> ProgramResult {
    msg!("Storing record...");

    // Verify that the program ID is correct
    if ctx.program_id != PROGRAM_ID {
        return Err(ProgramError::InvalidAccountData);

    // Verify that the account is rent exempt
    let rent = &Rent::from_account_info(next_account_info(&mut ctx.accounts.iter())?)?;
    if !rent.is_exempt(ctx.accounts.records_account.lamports(), ctx.accounts.records_account.data_len()) {
        return Err(ProgramError::AccountNotRentExempt);

    // Deserialize the record account
    let mut record_account = Record::unpack(&ctx.accounts.records_account.data.borrow())?;
    // Update the record with the new owner and value
    record_account.owner = record_owner;
    record_account.value = record_value;

    // Serialize the updated record and store it back into the account
    Record::pack(record_account, &mut ctx.accounts.records_account.data.borrow_mut())?;

    msg!("Record stored successfully!");

// Solana program entry point
#[cfg(not(feature = "no-entrypoint"))]
pub fn entrypoint(program_id: &Pubkey, accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult {
    if let Ok(instruction) = <StoreRecordInstruction as BorshDeserialize>::try_from_slice(instruction_data) {
        match instruction {
            StoreRecordInstruction::StoreRecord { record_owner, record_value } => {
                    Context {
                        program_id: *program_id,
                        accounts: Accounts {
                            records_account: accounts[0].clone(),
    } else {

// Instruction enum for deserializing instruction data
#[derive(BorshDeserialize, BorshSerialize, Debug)]
pub enum StoreRecordInstruction {
    StoreRecord {
        record_owner: Pubkey,
        record_value: String,

// Context struct for passing around context data
pub struct Context<'a> {
    pub program_id: Pubkey,
    pub accounts: Accounts<'a>,

// Accounts struct for organizing account data
pub struct Accounts<'a> {
    pub records_account: &'a AccountInfo<'a>,

Or, a resolver reading from .sol registry?

Or, a gateway bridging .sol and .eth?

Before I started building on ENS, I was learning on Solana. Here is an old repo which was based on Metaplex’s NFT standard and implemented a simple NFT frontend: GitHub - sshmatrix/metaplex-custom: Custom Metaplex build

In this day and age of AI, programmers should be ecosystem- and language-agnostic. First principles remain the same wherever you go and failure to adapt to new environments is a skill issue.

That is correct. If you had read the draft, it mentions that Solana Foundation and Solana NFT marketplace tensor.hq would need to be on board for timely wallet integration. I am already in touch with Solana Foundation and I can assure you that this proposal will only go forward once it has the backing of both the Solana Foundation and TensorHQ as well as ENS DAO.

How is that working out? Any updates?

1 Like

Yes, they did deliver the working prototype

They asked if they can do fully implementation on Cairo 1.0 and we are the one asking them to hold for now as we haven’t fully finalised on the l2 architecture yet.

This seems highly speculative, to put it mildly. What assumptions underlie these figures?

This mechanism is trivial to bypass by bulk-committing with different secrets, ensuring you always have a commitment to reveal for your name of choice in an early slot. A dutch auction is a well established auction, simple to implement, and impossible to game.

As Makoto mentions, this cannot be done trustlessly because Solana is not an L2. How would this be implemented in a way that minimises the trust required?

What assurance do you have that you can achieve these integrations? Without them, the project is pointless regardless of technical sophistication.

Are you intending to use AI to write this integration?

1 Like

That 2.1 million names will be registered in the first year nearly uniformly (due to tapering), same as the ENS active name count as of today. Based on this assumption, the text and the script completely describes the method used to calculate revenues. You can adjust the numbers proportionally with your belief in the true name registration count.

It was an initial suggestion. We are open to more/better ideas.

Method 1: ENS Labs runs the gateway, same as other gateways that it runs on behalf of the DAO.

Method 2: Create a rollup-like setup on Ethereum mainnet/L2 that stores storage proofs of the Solana program at intermediate intervals and use this program for state verification. The idea is to create a rollup-like quasi-setup; this is theoretically possible but technically challenging for many reasons.

We can’t. We can bring people on board to talk and see if they can collectively push for an integration. Like I said, we are in touch with Solana participants and this project isn’t going anywhere without these potential players willing to collaborate. The first step in this process is checking with the ENS DAO whether they are willing to participate through this TempCheck.

What? :man_facepalming: It was a general statement. The codebase will go through audit as usual by independent auditors as well as thorough testing on testnet by community and hopefully your own team.

You are saying that you have held up a team since April 2023 while they have launched their token in between? Seems like ENS Labs missed a boat ship. What L2 architecture are you referring to; I am mildly curious? Who is working on advancing this “final architecture”?

What foundation do you have for the assumption that .s.ens on Solana will be as popular as .eth?

The only gateways we run at present are trustless - they rely on Ethereum or the DNS service as roots of trust. I’m not keen for us to depart from that.

How does this setup verify that the storage proofs (presumably, roots rather than proofs) are valid?

I’m not sure what the relevance of mentioning AI was, then?

None. If you believe that only 1/10th of the assumed number will be registered, simply scale down the revenue by 1/10. If done right, there is no reason why ENS can’t achieve significant success.

I’ll get back to you with details on this proposed method since it is work-in-progress on our end. Meanwhile, a third method exists:

Method 3: Read from N randomly-chosen CCIP-Read gateways from a total of M gateways. Enforce that all gateways return the same result each time or get slashed at very first mismatch. This is a method using random sampling to minimise trust on a single gateway. Values of N and M can be adjusted.

It was in response to Makoto about skill issue. We can have this interesting conversation elsewhere that the learning curve is so much shallower after AI advancement.

This is effectively a multisig. But you would need some way to implement slashing, in a manner that is objective - which brings you right back to needing to determine what the true state of the chain is.

Correct. We’ll come up with a solution though; it doesn’t seem like a trivially unsolvable problem. My intuition though is that it will end up looking a lot like a 4337/AA setup.

As I’ve said before I am in favor of proposals who try to extend the ENS global namespace beyond just Ethereum, preferably those who aren’t about us vs them, but rather how to in general improve UX and name ownership across all the ecosystem.


I don’t understand why do this. I believe we should have a situation in which a name or its owner resolves differently in one network or the other. Besides, it seems the worst of both worlds: Solana people don’t get their own TLD and ENS has break a rule and emit single letter domain.

If we were to have a functional ENS resolver on Solana (if that can be done trustlessly, as per Nicks comments) then it would make a lot more sense to have the default name suggested to Solana people some real DNS, like sol.domains or sol.link or whatever. In that case the pricing and squatting is up for the multiple domain owners.

1 Like

We already can have this ↓

No one will ever get their own TLD except .eth. But Solana users will at least get access to a restricted namespace s.eth at 80% discount; this is not a bad state. Plus, I think ENS is a lot more about its infrastructure than just the TLD.

… and make a lot of revenue in return. Isn’t that why those 1L and 2L domains have been saved?

These domain owners might as well be grifters with no association to ENS DAO. ENS DAO loses on revenue as well as loses face. It’s better if this is an ENS DAO endeavour.

I am much more interested in how we can more broad user adoption and to integrate the ENS infrastructure into Solana wallets in a trustless manner than in how to get more revenue to the DAO.

In fact I’d say that one of the main reasons that most Solana wallets don’t integrate ENS today aren’t technical, but rather the fact it says “.eth” right there.

It’s a good point that we could start issuing these one letter domains. I just don’t think it’s a good use of it, since, as I’ve mentioned, it has a strong connection with Ethereum.

And now, this next thing I’m about to say is just my personal opinion, but I’d even go as much and say that I’d be willing to emit .sol to be a CCIP reflection of Solana Name Service, if they did the same for .eth (essentially, running .sol on ENS infrastructure) and some other other conditions.


transitioning ENS from multichain to crosschain has an very significant amount of complexity to it. i don’t think this proposal as-is would be viable for the DAO to take on, given the lack of clarity around trust assumptions.

the question of data availability isn’t trivial, and this proposal seems to downplay it. trustlessness for an ENS integration this deep is effectively a requirement (or at least very trust minimised), and whatever solution is concluded will assumedly not be that. even a multisig with slashing would have it’s own set of complexities, all of which would be coming from an unproven codebase.

obviously, it’s very hard for something like this to be trustless from the start, especially when features and functionality need to be battle-tested. so i think it makes sense to significantly shrink the scope of this proposal to just the development of a trustless solana ENS resolver.

from there, the trust assumptions would be much more clear, and it would be easier to see the viability of the full scope of this proposal. alongside that, the output would also be a solana resolver that could be used for other subnames, which if your analysis is correct would entice a portion of the solana userbase anyway.


That is a partially populist/outdated/wrong opinion. It is probably true somewhat for general populace but certainly not for service providers. Phantom, the biggest Solana wallet, already supports ETH infrastructure and is also an ETH wallet. Solana Foundation was present at ETH Denver and had a booth there. I think there is room for collaboration at top level since Solana Foundation genuinely appreciates Ethereum and wants to work with Ethereum. If the top brass plays nice and collaborates on a meaningful level, people will also play nice and it is a chance to set a good precedent.

From what I understand, that is a hard NO from ENS Labs. Initial idea was to propose a TLD for Solana but I have been told that this is untenable.

This is fair assessment. In our mind, it didn’t seem like a stretch for ENS Labs to run the trusted gateway. But since such a solution is not desirable, it certainly makes sense to first develop a prototype Solana resolver and work on a practical trustless or trust-minimised setup.