Repository navigation
Expand file tree
/
Copy pathdeploy-v7.html
More file actions
194 lines (184 loc) · 11.6 KB
/
Copy pathdeploy-v7.html
File metadata and controls
194 lines (184 loc) · 11.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="robots" content="noindex">
<title>Deploy TBlock hook V7</title>
<style>
:root{--fond:#04090c;--carte:#0b1c22;--ligne:#16323c;--texte:#f2fbff;--doux:#9cc3cf;--accent:#35d3f0;--ok:#3ddc97;--ko:#ff6b6b}
body{margin:0;background:var(--fond);color:var(--texte);font:15px/1.5 system-ui,-apple-system,Segoe UI,sans-serif}
main{max-width:640px;margin:0 auto;padding:24px 16px}
h1{font-size:20px;margin:0 0 6px}
h2{font-size:15px;margin:0 0 6px}
.carte{background:var(--carte);border:1px solid var(--ligne);border-radius:14px;padding:16px;margin:14px 0}
.ligne{display:flex;gap:10px;align-items:baseline;margin:6px 0}
.ligne b{min-width:18px}
code{font-size:12.5px;word-break:break-all;color:var(--doux)}
button{font:inherit;font-weight:700;padding:12px 18px;border-radius:12px;border:0;cursor:pointer;background:var(--accent);color:#012}
button[disabled]{opacity:.45;cursor:not-allowed}
.ok{color:var(--ok)} .ko{color:var(--ko)} .doux{color:var(--doux)}
ul{margin:6px 0 0;padding-left:18px} li{margin:4px 0}
</style>
</head>
<body>
<main>
<h1>Deploy the TBlock hook V7</h1>
<p class="doux">One transaction, signed by <b>your</b> wallet. This page never sees a key. The contract has no owner and
lands at the same address whoever sends it — the address depends only on its code.</p>
<div class="carte">
<h2>What the V7 changes</h2>
<ul class="doux">
<li><b>The whole fee goes to the fee wallet.</b> Until now the creator of a market kept a
third of every fee on it. The V7 pays none of it.</li>
<li class="ko"><b>What that removes, said plainly.</b> That share was the only reason a
stranger would launch a block here rather than somewhere else. It is gone.</li>
<li><b>What the measurement says about it.</b> Fourteen days, 303 of 303 windows read, no
window missed: <b>two</b> launches, both from our own wallets. Over that window the
incentive brought in no outside creator at all. What it was costing is measured too —
the creator share was <b>0.001019868 ETH</b> over those fourteen days, so the wallet
takes 50% more at the same volume.</li>
<li class="ko"><b>What the measurement does NOT say.</b> What would happen with outside
creators. Fourteen days without them is not proof they would never come.</li>
<li><b>The creator is still named on chain.</b> The market still records who opened it,
and an event on every fee carries the creator who was not paid — so the change is
readable in the logs, not something you have to diff two contracts to find.</li>
<li><b>No access control is touched.</b> Both V4 locks are kept word for word, and the fee
wallet has no special right to register a market. Two tests hold that line.</li>
<li class="ko"><b>It repairs nothing that already exists.</b> A hook is part of a pool's
identity in Uniswap v4. Every pool already open keeps the hook it was born with.</li>
</ul>
</div>
<div class="carte">
<div class="ligne"><b id="c1">…</b><span>Base mainnet reachable, hook address still empty</span></div>
<div class="ligne"><b id="c2">…</b><span>Dry run on Base returns the expected hook address</span></div>
<div class="ligne"><b id="c3">…</b><span>Wallet connected on Base</span></div>
<p class="doux" style="margin:10px 0 0">Expected hook: <code id="attendu"></code></p>
<p class="doux">Fee wallet baked in: <code id="fee"></code> · life fee <code id="vie"></code> wei · label <code id="marq"></code>
· creator tithe <code id="dime"></code>%</p>
</div>
<div class="carte">
<button id="connecter" type="button">Connect wallet</button>
<button id="deployer" type="button" disabled>Deploy — sign in your wallet</button>
<p id="etat" class="doux" style="margin:12px 0 0"></p>
<p id="relecture" class="doux" style="margin:8px 0 0"></p>
</div>
</main>
<script type="module">
/* ⛔ PAGE DE DEPLOIEMENT DU HOOK V6 (2026-09-21), derivee de celle du V5 qui a servi. `cast` sur la machine de Phil n a
* pas le compte importe ; cette page laisse SON wallet signer.
* Le contrat part par le deployeur CREATE2 standard : l adresse ne depend QUE du code (aucun proprietaire), donc
* n importe quel wallet peut l envoyer. La page VERIFIE avant d autoriser la signature :
* 1. aucun code a l adresse attendue ; 2. un eth_call de la transaction rend exactement cette adresse ;
* 3. wallet sur Base.
* ⛔⛔ ET APRES : elle relit le contrat deploye, y compris `porteLeLabel(<un vrai block ne par notre app>)`. C est la
* seule verification qui ne peut PAS se faire avant — forge ne sait pas executer un B20 (code 0xEF, execute
* nativement par le noeud Base : l EVM locale rend OpcodeNotFound). Si elle rend `false`, le verrou du label
* refuserait nos propres createurs, et il ne faut surtout pas brancher l app dessus. */
import { envoyerDepuisWallet } from './envoi.js';
const $ = (s) => document.querySelector(s);
const RPC = 'https://mainnet.base.org';
const rpc = async (method, params) => {
const r = await fetch(RPC, { method: 'POST', headers: { 'content-type': 'application/json' },
body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }) }).then((x) => x.json());
if (r.error) throw new Error(r.error.message || 'rpc error');
return r.result;
};
const marque = (id, ok, texte) => { const e = $(id); e.textContent = ok ? '✓' : '✗'; e.className = ok ? 'ok' : 'ko'; if (texte) e.title = texte; };
let tx = null, compte = null, pret = { vide: false, simu: false };
async function verifier() {
tx = await fetch('./deploy-v7.json', { cache: 'no-store' }).then((r) => r.json());
$('#attendu').textContent = tx.hook;
$('#fee').textContent = tx.feeWallet;
$('#vie').textContent = tx.fraisVieWei;
$('#marq').textContent = tx.marqueur;
$('#dime').textContent = String(tx.dimeCreateurPourCent);
const code = await rpc('eth_getCode', [tx.hook, 'latest']);
pret.vide = code === '0x';
marque('#c1', pret.vide);
if (!pret.vide) {
$('#etat').innerHTML = '<span class="ok">The hook V7 is already deployed at this address. Nothing to do.</span>';
void relire();
return;
}
const r = await rpc('eth_call', [{ to: tx.deployeur, data: tx.data, gas: '0x4c4b40' }, 'latest']);
pret.simu = ('0x' + String(r).slice(-40)).toLowerCase() === tx.hook.toLowerCase();
marque('#c2', pret.simu);
majBouton();
}
function majBouton() { $('#deployer').disabled = !(pret.vide && pret.simu && compte); }
/** ⛔ Les trois lectures qui comptent, faites SUR LA CHAINE une fois le contrat vivant. */
async function relire() {
const appel = async (data) => rpc('eth_call', [{ to: tx.hook, data }, 'latest']);
const lignes = [];
try {
/* ⛔ Les trois selecteurs sont MESURES avec `cast sig` et ecrits dans deploy-v4.json, jamais devines ici. */
const fee = '0x' + String(await appel(tx.selecteurs.feeWallet)).slice(-40);
lignes.push((fee.toLowerCase() === tx.feeWallet.toLowerCase() ? '✓' : '✗') + ' fee wallet: ' + fee);
const taille = BigInt(await appel(tx.selecteurs.tailleMarqueur));
lignes.push((taille === BigInt(tx.marqueur.length) ? '✓' : '✗') + ' label length: ' + taille);
/* ⛔⛔ CE QUI A ETE CORRIGE LE 2026-09-21, APRES UNE FAUSSE ALERTE. Cette page affichait
* « ✗ creator tithe on chain: 20% — expected 0, DO NOT switch the app » sur un contrat
* PARFAITEMENT BON. Les deux constantes sont restees DECLAREES expres, pour qu on puisse
* diffuser le V6 et le V7 et voir ce qui change ; elles ne sont plus LUES dans la
* repartition. Tester une valeur decorative comme si c etait la logique, c est crier au
* loup — et on apprend a ignorer le rouge.
* ⛔ ET LE MESSAGE RECLAMAIT L IMPOSSIBLE : l app lit l etat du hook sur la chaine et bascule
* toute seule. « DO NOT switch the app » demandait une action qui n existe pas. */
const dime = BigInt(await appel(tx.selecteurs.dime));
const tiers = BigInt(await appel(tx.selecteurs.diviseur));
lignes.push('· creator tithe / divisor still declared: ' + dime + '% / ' + tiers
+ ' — informational, this hook no longer reads them');
/* ⛔ LA VRAIE PREUVE : l evenement qui n existe QUE dans ce hook doit etre GRAVE dans son
* bytecode. Une constante se lit ; un topic dans le code se verifie. */
const codeHook = String(await rpc('eth_getCode', [tx.hook, 'latest']) || '').toLowerCase();
const marque = String(tx.topicPreuve || '').toLowerCase().replace(/^0x/, '');
if (!marque) {
lignes.push('✗ no proof topic in the descriptor — cannot verify the payout logic');
} else {
const grave = codeHook.includes(marque);
lignes.push((grave ? '✓' : '✗') + ' the whole-fee-to-wallet event is engraved in the deployed code'
+ (grave ? '' : ' — this is NOT the expected hook, do not use it'));
}
const arg = tx.temoinLabel.replace(/^0x/, '').toLowerCase().padStart(64, '0');
const porte = BigInt(await appel(tx.selecteurs.porteLeLabel + arg)) === 1n;
/* ⛔ LE REMEDE EST NOMME, ET IL EST FAISABLE. « DO NOT switch the app » etait impossible a
* suivre : l app lit l etat du hook sur la chaine et bascule toute seule. Ce qui peut
* vraiment etre fait, c est epingler l app sur le hook precedent et en deployer un corrige —
* et ca se demande. */
lignes.push((porte ? '✓' : '✗') + ' a block born through this app passes the label check ('
+ tx.temoinLabel.slice(0, 10) + '…)'
+ (porte ? '' : ' — this hook is not usable. The app picks it up on its own, so say so and it '
+ 'will be pinned back to the previous hook while a corrected one is deployed.'));
} catch (e) {
lignes.push('✗ could not read the deployed hook: ' + (e.message || e));
}
$('#relecture').innerHTML = lignes.map((l) => '<div>' + l.replace(/&/g, '&').replace(/</g, '<') + '</div>').join('');
}
$('#connecter').addEventListener('click', async () => {
if (!window.ethereum) { $('#etat').textContent = 'No wallet found in this browser.'; return; }
try {
const comptes = await window.ethereum.request({ method: 'eth_requestAccounts' });
compte = comptes && comptes[0];
try { await window.ethereum.request({ method: 'wallet_switchEthereumChain', params: [{ chainId: '0x2105' }] }); } catch (_) {}
const chaine = await window.ethereum.request({ method: 'eth_chainId' });
marque('#c3', !!compte && Number(chaine) === 8453);
if (Number(chaine) !== 8453) compte = null;
} catch (e) { $('#etat').textContent = 'Connection refused: ' + (e.message || e); }
majBouton();
});
$('#deployer').addEventListener('click', async () => {
$('#deployer').disabled = true;
$('#etat').textContent = 'Opening your wallet — check it shows Base and a contract call, then sign.';
const r = await envoyerDepuisWallet({ eth: window.ethereum, rpc, chaineAttendue: 8453, compte, to: tx.deployeur, data: tx.data, value: '0x0' });
if (r.etat !== 'CONFIRME') { $('#etat').innerHTML = '<span class="ko">Not done: ' + (r.pourquoi || r.etat) + '</span>'; majBouton(); return; }
const code = await rpc('eth_getCode', [tx.hook, 'latest']);
$('#etat').innerHTML = code !== '0x'
? '<span class="ok">Deployed. Hook V7 is live at ' + tx.hook + '.</span> Transaction: <code>' + r.hash + '</code>'
: '<span class="ko">Transaction confirmed but no code at the address yet — send me the hash: </span><code>' + r.hash + '</code>';
void relire();
});
verifier().catch((e) => { $('#etat').textContent = 'Could not read Base right now: ' + (e.message || e); });
</script>
</body>
</html>