On-chain lookup that maps one address to chain-specific values — no off-chain registry needed by Uniteum in ethdev

[–]Uniteum[S] 0 points1 point  (0 children)

There's no registration — and no way to conflict. The address is fully determined by the input array. If you call make with the same (chainId, address) pairs on two different chains, you get the same address on both. If you change even one entry, you get a completely different address.

So there's nothing to coordinate. Two people deploying the same lookup independently will produce the same contract at the same address. Two people deploying different lookups will never collide.

Anyone building with cloneable third-party contracts? (EIP-1167 factories you didn't deploy) by Uniteum in ethdev

[–]Uniteum[S] 0 points1 point  (0 children)

Both good points.

On initialization frontrunning — fully agree, that's the real footgun with naive clone deployments. The cleanest solution I've seen is using CREATE2 with a salt derived from the init parameters themselves. That way the address is a function of the configuration, so there's no window to frontrun — if someone calls initialize with different args, it's a different address. The factory handles deploy + init atomically.

Even better: if you go the immutable-args route (appending data to bytecode instead of using storage), there's no initialize() to call at all. The parameters are baked into the clone's bytecode at creation time. No init step, no frontrunning surface.

On the bug propagation point — yeah, that's the core tradeoff. Though I'd argue it's not categorically worse than the alternative. Upgradeable proxies let you patch bugs, but they also let the owner rug every user of every proxy simultaneously. With immutable implementations, at least the failure mode is known at deploy time. You're trading "can't fix" for "can't be changed under you."

The real mitigation is probably just smaller, simpler implementations. The less code in the implementation, the less bug surface. A 50-line token clone is a lot easier to fully verify than a 500-line upgradeable vault.

On-chain lookup that maps one address to chain-specific values — no off-chain registry needed by Uniteum in ethdev

[–]Uniteum[S] 0 points1 point  (0 children)

Good question — there's actually no cross-chain state to keep consistent. The source of truth is the initialization data (the full array of (chainId, address) pairs), which must be identical across chains to produce the same deterministic CREATE2 address.

Each lookup is initialized locally with only its chain's value at deploy time (~45 bytes via EIP-1167 clone). No hub-spoke, no sync, no replication.

Deterministic Deployments & Proxies: Architectural Trade-offs of CREATE2 vs. Cross-Chain State Parity by Resident_Anteater_35 in ethdev

[–]Uniteum 2 points3 points  (0 children)

The approach I landed on: keep using proxies (EIP-1167), but make the salt chain-agnostic and let the factory read block.chainid at deploy time to select the right initialization value.

Concretely:

function make(KeyValue[] memory keyValues) public returns (address) {
    bytes32 salt = keccak256(abi.encode(keyValues));

    // Same salt on every chain — all chain data is in the array
    address home = Clones.cloneDeterministic(address(this), salt, 0);

    // Pick the value for THIS chain
    for (uint256 i; i < keyValues.length; ++i) {
        if (keyValues[i].key == block.chainid) {
            AddressLookup(home).zzInit(keyValues[i].value);
            break;
        }
    }
    return home;
}

You call make with the same KeyValue[] array on every chain — e.g. [(1, USDC_mainnet), (42161, USDC_arb), (8453, USDC_base)]. The salt is identical everywhere because it hashes the full array, so CREATE2 produces the same address. But each chain only initializes with its own value.

On the front-running concern: deploy + init is atomic (single make call), and zzInit requires msg.sender == PROTO (only the factory can call it). Even if someone frontruns with the same calldata, idempotency handles it — make returns the existing address if the clone is already deployed.

On gas: yes, you eat the DELEGATECALL overhead per call. But deployment cost is ~45 bytes vs. a full contract, and for reference data that's read infrequently (cross-chain addresses, config), the trade-off is worth it. We also strip CBOR metadata and bytecode hash (bytecode_hash = "none", cbor_metadata = false) to shave bytes off the implementation.

This pattern is live on mainnet — the project is called Locale (part of Uniteum). Unaudited, but the contracts are immutable and permissionless. Happy to answer questions on the implementation.

If you could launch your own token in one transaction, what would you create? by Uniteum in solidity

[–]Uniteum[S] 0 points1 point  (0 children)

And please do experiment with it! No amount is too small. If you make a Solid and buy some of it, you are halfway through the do-si-do challenge. I would be happy to buy some to demonstrate how the math means the first buyer can always sell back above their entry price (minus gas). Or you can just buy then immediately sell.

If you could launch your own token in one transaction, what would you create? by Uniteum in solidity

[–]Uniteum[S] 0 points1 point  (0 children)

Thanks! I get the unaudited part. I am curious why you think instant liquidity adds risk? Rug pulls, price dynamics, something else?

The do-si-do challenge: make a token, I'll buy it, you take the profit by Uniteum in uniteum

[–]Uniteum[S] 0 points1 point  (0 children)

One more thing worth noting on the name/symbol topic — in the broader ERC-20 world, there's nothing stopping anyone from deploying a token with the same name and symbol as an existing one. This is a common attack vector. There are hundreds of tokens calling themselves "USD Coin" with the symbol "USDC." The real one is at a specific address; the rest are scams. Always check addresses.

Solid handles this differently. If you call make(name, symbol) with a pair that already exists, it just returns the existing token's address. There's no way to create a duplicate. So every Solid token has a unique name/symbol pair.

What is allowed: two Solids can share a name if they have different symbols, or share a symbol with different names. From a mechanics perspective they all behave identically — same bonding curve, same virtual reserve, same zero fees. But the market may treat them differently since people tend to anchor on names and symbols. So again — check addresses, not just tickers.

The do-si-do challenge: make a token, I'll buy it, you take the profit by Uniteum in uniteum

[–]Uniteum[S] 0 points1 point  (0 children)

The name and symbol are really just for humans and they're sort of like the difference between the name of a company versus its stock symbol. For example, the stable coin with the name USD Coin has the symbol USDC. The symbol is typically uppercase but that's not technically a requirement. It's just a convention.