@oracle-agent/oracle 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SETUP.md +13 -0
- package/package.json +12 -4
- package/protocols/templates/safe-erc20/SECURITY.md +16 -0
- package/protocols/templates/safe-erc20/foundry.toml +12 -0
- package/protocols/templates/safe-erc20/remappings.txt +2 -0
- package/protocols/templates/safe-erc20/src/SafeERC20.sol +53 -0
- package/protocols/templates/safe-erc20/test/SafeERC20.t.sol +72 -0
- package/public/oracle-splash/index.html +648 -598
- package/public/oracle-splash/mesh-graph.png +0 -0
- package/public/oracle-splash/mesh-graph.svg +216 -0
- package/scripts/protocol-template-gate.mjs +15 -0
- package/skills/oracle-protocol-builder/SKILL.md +45 -24
- package/src/data/catalog.mjs +9 -0
- package/src/data/desk-data.mjs +8 -0
- package/src/data/providers/poly-clob.mjs +18 -195
- package/src/protocol-templates/gate.mjs +179 -0
- package/src/protocol-templates/prepare-deploy.mjs +81 -0
|
Binary file
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1400 900" width="1400" height="900">
|
|
2
|
+
<defs>
|
|
3
|
+
<style>
|
|
4
|
+
@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;1,400;1,500&family=Outfit:wght@300;400;500&family=IBM+Plex+Mono:wght@400;500&display=swap');
|
|
5
|
+
</style>
|
|
6
|
+
<radialGradient id="bg" cx="50%" cy="35%" r="70%">
|
|
7
|
+
<stop offset="0%" stop-color="#111925"/>
|
|
8
|
+
<stop offset="45%" stop-color="#0B1018"/>
|
|
9
|
+
<stop offset="100%" stop-color="#070b10"/>
|
|
10
|
+
</radialGradient>
|
|
11
|
+
<radialGradient id="orb1" cx="50%" cy="50%" r="50%">
|
|
12
|
+
<stop offset="0%" stop-color="#7CC4FF" stop-opacity="0.18"/>
|
|
13
|
+
<stop offset="55%" stop-color="#7CC4FF" stop-opacity="0.04"/>
|
|
14
|
+
<stop offset="100%" stop-color="#7CC4FF" stop-opacity="0"/>
|
|
15
|
+
</radialGradient>
|
|
16
|
+
<radialGradient id="orb2" cx="50%" cy="50%" r="50%">
|
|
17
|
+
<stop offset="0%" stop-color="#50D2C1" stop-opacity="0.10"/>
|
|
18
|
+
<stop offset="100%" stop-color="#50D2C1" stop-opacity="0"/>
|
|
19
|
+
</radialGradient>
|
|
20
|
+
<pattern id="grid" width="48" height="48" patternUnits="userSpaceOnUse">
|
|
21
|
+
<path d="M 48 0 L 0 0 0 48" fill="none" stroke="rgba(124,196,255,0.06)" stroke-width="1"/>
|
|
22
|
+
</pattern>
|
|
23
|
+
<linearGradient id="panelStroke" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
24
|
+
<stop offset="0%" stop-color="rgba(124,196,255,0.28)"/>
|
|
25
|
+
<stop offset="100%" stop-color="rgba(124,196,255,0.08)"/>
|
|
26
|
+
</linearGradient>
|
|
27
|
+
<linearGradient id="cardFill" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
28
|
+
<stop offset="0%" stop-color="#152031"/>
|
|
29
|
+
<stop offset="100%" stop-color="#111925"/>
|
|
30
|
+
</linearGradient>
|
|
31
|
+
<filter id="softGlow" x="-50%" y="-50%" width="200%" height="200%">
|
|
32
|
+
<feGaussianBlur stdDeviation="8" result="b"/>
|
|
33
|
+
<feMerge>
|
|
34
|
+
<feMergeNode in="b"/>
|
|
35
|
+
<feMergeNode in="SourceGraphic"/>
|
|
36
|
+
</feMerge>
|
|
37
|
+
</filter>
|
|
38
|
+
<filter id="nodeGlow" x="-40%" y="-40%" width="180%" height="180%">
|
|
39
|
+
<feGaussianBlur stdDeviation="4" result="b"/>
|
|
40
|
+
<feMerge>
|
|
41
|
+
<feMergeNode in="b"/>
|
|
42
|
+
<feMergeNode in="SourceGraphic"/>
|
|
43
|
+
</feMerge>
|
|
44
|
+
</filter>
|
|
45
|
+
<marker id="ah-blue" markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto">
|
|
46
|
+
<path d="M0,0 L8,4 L0,8 Z" fill="#7CC4FF"/>
|
|
47
|
+
</marker>
|
|
48
|
+
<marker id="ah-poly" markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto">
|
|
49
|
+
<path d="M0,0 L8,4 L0,8 Z" fill="#3B82F6"/>
|
|
50
|
+
</marker>
|
|
51
|
+
<marker id="ah-hl" markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto">
|
|
52
|
+
<path d="M0,0 L8,4 L0,8 Z" fill="#50D2C1"/>
|
|
53
|
+
</marker>
|
|
54
|
+
<marker id="ah-rh" markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto">
|
|
55
|
+
<path d="M0,0 L8,4 L0,8 Z" fill="#d7ff4d"/>
|
|
56
|
+
</marker>
|
|
57
|
+
<marker id="ah-sol" markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto">
|
|
58
|
+
<path d="M0,0 L8,4 L0,8 Z" fill="#9945FF"/>
|
|
59
|
+
</marker>
|
|
60
|
+
<marker id="ah-btc" markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto">
|
|
61
|
+
<path d="M0,0 L8,4 L0,8 Z" fill="#F0B90B"/>
|
|
62
|
+
</marker>
|
|
63
|
+
<marker id="ah-mute" markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto">
|
|
64
|
+
<path d="M0,0 L8,4 L0,8 Z" fill="#5B738F"/>
|
|
65
|
+
</marker>
|
|
66
|
+
</defs>
|
|
67
|
+
|
|
68
|
+
<!-- page bg -->
|
|
69
|
+
<rect width="1400" height="900" fill="url(#bg)"/>
|
|
70
|
+
<rect width="1400" height="900" fill="url(#grid)"/>
|
|
71
|
+
<ellipse cx="700" cy="420" rx="520" ry="280" fill="url(#orb1)"/>
|
|
72
|
+
<ellipse cx="980" cy="620" rx="280" ry="180" fill="url(#orb2)"/>
|
|
73
|
+
|
|
74
|
+
<!-- ========== brand top-left (oracle) ========== -->
|
|
75
|
+
<g id="brand">
|
|
76
|
+
<circle cx="52" cy="48" r="7" fill="#7CC4FF" filter="url(#softGlow)"/>
|
|
77
|
+
<circle cx="52" cy="48" r="3.2" fill="#0B1018"/>
|
|
78
|
+
<text x="70" y="54" fill="#E8F1FA" font-family="Outfit, system-ui, sans-serif" font-size="26" font-weight="400" letter-spacing="-0.3">oracle</text>
|
|
79
|
+
<text x="52" y="78" fill="#5B738F" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="10" letter-spacing="1.8">MULTI-PROFILE MESH · POWERED BY HERMES</text>
|
|
80
|
+
</g>
|
|
81
|
+
|
|
82
|
+
<!-- right meta -->
|
|
83
|
+
<text x="1350" y="48" fill="#5B738F" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="10" text-anchor="end" letter-spacing="1.5">FOR USERS</text>
|
|
84
|
+
<text x="1350" y="68" fill="#9BB6D1" font-family="Outfit, system-ui, sans-serif" font-size="13" text-anchor="end">graph · customizable · add agents</text>
|
|
85
|
+
|
|
86
|
+
<!-- ========== main glass panel ========== -->
|
|
87
|
+
<rect x="48" y="110" width="1304" height="730" rx="22" fill="#111925" fill-opacity="0.72" stroke="url(#panelStroke)" stroke-width="1.2"/>
|
|
88
|
+
<!-- panel header bar -->
|
|
89
|
+
<rect x="48" y="110" width="1304" height="52" rx="22" fill="#152031" fill-opacity="0.9"/>
|
|
90
|
+
<rect x="48" y="140" width="1304" height="22" fill="#152031" fill-opacity="0.9"/>
|
|
91
|
+
<text x="72" y="142" fill="#7CC4FF" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="11" letter-spacing="1.6">FOR USERS</text>
|
|
92
|
+
<text x="700" y="142" fill="#9BB6D1" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="11" text-anchor="middle" letter-spacing="1.6">MULTI-PROFILE // CUSTOMIZABLE</text>
|
|
93
|
+
<text x="1328" y="142" fill="#5B738F" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="11" text-anchor="end" letter-spacing="1.4">POWERED BY HERMES</text>
|
|
94
|
+
|
|
95
|
+
<!-- pills -->
|
|
96
|
+
<g font-family="IBM Plex Mono, ui-monospace, monospace" font-size="10" letter-spacing="1.2">
|
|
97
|
+
<rect x="72" y="182" width="128" height="28" rx="14" fill="none" stroke="rgba(124,196,255,0.28)" stroke-width="1"/>
|
|
98
|
+
<text x="136" y="200" fill="#A7D8FF" text-anchor="middle">MULTI PROFILES</text>
|
|
99
|
+
<rect x="210" y="182" width="128" height="28" rx="14" fill="none" stroke="rgba(124,196,255,0.28)" stroke-width="1"/>
|
|
100
|
+
<text x="274" y="200" fill="#A7D8FF" text-anchor="middle">CUSTOMIZABLE</text>
|
|
101
|
+
<rect x="348" y="182" width="112" height="28" rx="14" fill="none" stroke="rgba(124,196,255,0.28)" stroke-width="1"/>
|
|
102
|
+
<text x="404" y="200" fill="#A7D8FF" text-anchor="middle">ADD AGENTS</text>
|
|
103
|
+
<rect x="470" y="182" width="118" height="28" rx="14" fill="none" stroke="rgba(124,196,255,0.28)" stroke-width="1"/>
|
|
104
|
+
<text x="529" y="200" fill="#A7D8FF" text-anchor="middle">MORE CHAINS</text>
|
|
105
|
+
<rect x="598" y="182" width="148" height="28" rx="14" fill="none" stroke="rgba(124,196,255,0.28)" stroke-width="1"/>
|
|
106
|
+
<text x="672" y="200" fill="#A7D8FF" text-anchor="middle">POWERED BY HERMES</text>
|
|
107
|
+
</g>
|
|
108
|
+
|
|
109
|
+
<!-- ========== connectors (behind nodes) ========== -->
|
|
110
|
+
<!-- input -> oracle -->
|
|
111
|
+
<line x1="700" y1="310" x2="700" y2="360" stroke="#7CC4FF" stroke-width="2.5" marker-end="url(#ah-blue)" filter="url(#nodeGlow)"/>
|
|
112
|
+
<line x1="700" y1="310" x2="700" y2="360" stroke="#7CC4FF" stroke-width="10" stroke-opacity="0.12"/>
|
|
113
|
+
|
|
114
|
+
<!-- oracle hub fan-out to profiles -->
|
|
115
|
+
<!-- poly left -->
|
|
116
|
+
<path d="M620 450 C560 450 420 450 280 520" fill="none" stroke="#3B82F6" stroke-width="2" marker-end="url(#ah-poly)"/>
|
|
117
|
+
<path d="M620 450 C560 450 420 450 280 520" fill="none" stroke="#3B82F6" stroke-width="8" stroke-opacity="0.10"/>
|
|
118
|
+
<!-- hl center-left -->
|
|
119
|
+
<path d="M660 470 C640 500 560 520 500 560" fill="none" stroke="#50D2C1" stroke-width="2" marker-end="url(#ah-hl)"/>
|
|
120
|
+
<path d="M660 470 C640 500 560 520 500 560" fill="none" stroke="#50D2C1" stroke-width="8" stroke-opacity="0.10"/>
|
|
121
|
+
<!-- rh center -->
|
|
122
|
+
<line x1="700" y1="470" x2="700" y2="560" stroke="#d7ff4d" stroke-width="2" marker-end="url(#ah-rh)"/>
|
|
123
|
+
<line x1="700" y1="470" x2="700" y2="560" stroke="#d7ff4d" stroke-width="8" stroke-opacity="0.10"/>
|
|
124
|
+
<!-- sol center-right -->
|
|
125
|
+
<path d="M740 470 C760 500 840 520 900 560" fill="none" stroke="#9945FF" stroke-width="2" marker-end="url(#ah-sol)"/>
|
|
126
|
+
<path d="M740 470 C760 500 840 520 900 560" fill="none" stroke="#9945FF" stroke-width="8" stroke-opacity="0.10"/>
|
|
127
|
+
<!-- btc right -->
|
|
128
|
+
<path d="M780 450 C860 450 1000 450 1120 520" fill="none" stroke="#F0B90B" stroke-width="2" marker-end="url(#ah-btc)"/>
|
|
129
|
+
<path d="M780 450 C860 450 1000 450 1120 520" fill="none" stroke="#F0B90B" stroke-width="8" stroke-opacity="0.10"/>
|
|
130
|
+
<!-- builder bottom -->
|
|
131
|
+
<path d="M700 470 C700 510 700 640 700 680" fill="none" stroke="#5B738F" stroke-width="1.5" stroke-dasharray="4 4" marker-end="url(#ah-mute)"/>
|
|
132
|
+
|
|
133
|
+
<!-- ========== 01 INPUT / COMMAND ========== -->
|
|
134
|
+
<g filter="url(#nodeGlow)">
|
|
135
|
+
<rect x="575" y="230" width="250" height="80" rx="14" fill="url(#cardFill)" stroke="rgba(124,196,255,0.35)" stroke-width="1.2"/>
|
|
136
|
+
<text x="700" y="258" fill="#5B738F" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="10" text-anchor="middle" letter-spacing="1.6">YOU</text>
|
|
137
|
+
<text x="700" y="282" fill="#E8F1FA" font-family="Outfit, system-ui, sans-serif" font-size="18" font-weight="500" text-anchor="middle">Input / Command</text>
|
|
138
|
+
<text x="700" y="300" fill="#9BB6D1" font-family="Outfit, system-ui, sans-serif" font-size="12" font-weight="300" text-anchor="middle">what you type or ask</text>
|
|
139
|
+
</g>
|
|
140
|
+
|
|
141
|
+
<!-- ========== 02 CONTROL PLANE · oracle ========== -->
|
|
142
|
+
<g filter="url(#nodeGlow)">
|
|
143
|
+
<rect x="520" y="360" width="360" height="110" rx="16" fill="url(#cardFill)" stroke="rgba(124,196,255,0.45)" stroke-width="1.4"/>
|
|
144
|
+
<rect x="520" y="360" width="360" height="110" rx="16" fill="rgba(124,196,255,0.04)"/>
|
|
145
|
+
<text x="700" y="392" fill="#7CC4FF" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="10" text-anchor="middle" letter-spacing="1.8">CONTROL PLANE</text>
|
|
146
|
+
<text x="700" y="424" fill="#E8F1FA" font-family="Cormorant Garamond, Georgia, serif" font-size="34" font-weight="500" font-style="italic" text-anchor="middle">oracle</text>
|
|
147
|
+
<text x="700" y="450" fill="#9BB6D1" font-family="Outfit, system-ui, sans-serif" font-size="12" font-weight="300" text-anchor="middle">route · bound · evolve</text>
|
|
148
|
+
</g>
|
|
149
|
+
|
|
150
|
+
<!-- ========== 03 PROFILE CARDS ========== -->
|
|
151
|
+
<!-- polymarket -->
|
|
152
|
+
<g>
|
|
153
|
+
<rect x="80" y="520" width="260" height="130" rx="16" fill="#111925" stroke="rgba(59,130,246,0.45)" stroke-width="1.2"/>
|
|
154
|
+
<rect x="80" y="520" width="260" height="130" rx="16" fill="rgba(59,130,246,0.06)"/>
|
|
155
|
+
<text x="100" y="548" fill="#3B82F6" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="10" letter-spacing="1.6">PROFILE</text>
|
|
156
|
+
<text x="100" y="578" fill="#A7D8FF" font-family="Outfit, system-ui, sans-serif" font-size="18" font-weight="500">polymarket agent</text>
|
|
157
|
+
<text x="100" y="600" fill="#9BB6D1" font-family="Outfit, system-ui, sans-serif" font-size="12" font-weight="300">events · arb · markets</text>
|
|
158
|
+
<rect x="100" y="618" width="100" height="20" rx="10" fill="none" stroke="rgba(59,130,246,0.35)"/>
|
|
159
|
+
<text x="150" y="632" fill="#7CC4FF" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="9" text-anchor="middle">Polymarket</text>
|
|
160
|
+
</g>
|
|
161
|
+
|
|
162
|
+
<!-- hyperliquid -->
|
|
163
|
+
<g>
|
|
164
|
+
<rect x="370" y="560" width="260" height="130" rx="16" fill="#111925" stroke="rgba(80,210,193,0.45)" stroke-width="1.2"/>
|
|
165
|
+
<rect x="370" y="560" width="260" height="130" rx="16" fill="rgba(80,210,193,0.06)"/>
|
|
166
|
+
<text x="390" y="588" fill="#50D2C1" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="10" letter-spacing="1.6">PROFILE</text>
|
|
167
|
+
<text x="390" y="618" fill="#A8F0E6" font-family="Outfit, system-ui, sans-serif" font-size="18" font-weight="500">hyperliquid agent</text>
|
|
168
|
+
<text x="390" y="640" fill="#9BB6D1" font-family="Outfit, system-ui, sans-serif" font-size="12" font-weight="300">perps · hip-3/4 · ta</text>
|
|
169
|
+
<rect x="390" y="658" width="170" height="20" rx="10" fill="none" stroke="rgba(80,210,193,0.35)"/>
|
|
170
|
+
<text x="475" y="672" fill="#50D2C1" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="9" text-anchor="middle">Hyperliquid · HyperEVM 999</text>
|
|
171
|
+
</g>
|
|
172
|
+
|
|
173
|
+
<!-- robinhood -->
|
|
174
|
+
<g>
|
|
175
|
+
<rect x="660" y="560" width="260" height="130" rx="16" fill="#111925" stroke="rgba(215,255,77,0.40)" stroke-width="1.2"/>
|
|
176
|
+
<rect x="660" y="560" width="260" height="130" rx="16" fill="rgba(215,255,77,0.05)"/>
|
|
177
|
+
<text x="680" y="588" fill="#d7ff4d" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="10" letter-spacing="1.6">PROFILE</text>
|
|
178
|
+
<text x="680" y="618" fill="#EAF7B0" font-family="Outfit, system-ui, sans-serif" font-size="18" font-weight="500">robinhood agent</text>
|
|
179
|
+
<text x="680" y="640" fill="#9BB6D1" font-family="Outfit, system-ui, sans-serif" font-size="12" font-weight="300">markets · nfts · names</text>
|
|
180
|
+
<rect x="680" y="658" width="150" height="20" rx="10" fill="none" stroke="rgba(215,255,77,0.35)"/>
|
|
181
|
+
<text x="755" y="672" fill="#d7ff4d" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="9" text-anchor="middle">Robinhood Chain 4663</text>
|
|
182
|
+
</g>
|
|
183
|
+
|
|
184
|
+
<!-- solana -->
|
|
185
|
+
<g>
|
|
186
|
+
<rect x="950" y="560" width="200" height="130" rx="16" fill="#111925" stroke="rgba(153,69,255,0.45)" stroke-width="1.2"/>
|
|
187
|
+
<rect x="950" y="560" width="200" height="130" rx="16" fill="rgba(153,69,255,0.06)"/>
|
|
188
|
+
<text x="970" y="588" fill="#9945FF" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="10" letter-spacing="1.6">PROFILE</text>
|
|
189
|
+
<text x="970" y="618" fill="#D4B3FF" font-family="Outfit, system-ui, sans-serif" font-size="18" font-weight="500">solana agent</text>
|
|
190
|
+
<text x="970" y="640" fill="#9BB6D1" font-family="Outfit, system-ui, sans-serif" font-size="12" font-weight="300">jup · nfts · dexs</text>
|
|
191
|
+
<rect x="970" y="658" width="70" height="20" rx="10" fill="none" stroke="rgba(153,69,255,0.35)"/>
|
|
192
|
+
<text x="1005" y="672" fill="#c4a0ff" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="9" text-anchor="middle">Solana</text>
|
|
193
|
+
</g>
|
|
194
|
+
|
|
195
|
+
<!-- bitcoin (top-right of profile row) -->
|
|
196
|
+
<g>
|
|
197
|
+
<rect x="1160" y="520" width="160" height="130" rx="16" fill="#111925" stroke="rgba(240,185,11,0.40)" stroke-width="1.2"/>
|
|
198
|
+
<rect x="1160" y="520" width="160" height="130" rx="16" fill="rgba(240,185,11,0.05)"/>
|
|
199
|
+
<text x="1180" y="548" fill="#F0B90B" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="10" letter-spacing="1.6">PROFILE</text>
|
|
200
|
+
<text x="1180" y="578" fill="#F8E29A" font-family="Outfit, system-ui, sans-serif" font-size="18" font-weight="500">bitcoin</text>
|
|
201
|
+
<text x="1180" y="600" fill="#9BB6D1" font-family="Outfit, system-ui, sans-serif" font-size="12" font-weight="300">ord · runes</text>
|
|
202
|
+
<rect x="1180" y="618" width="50" height="20" rx="10" fill="none" stroke="rgba(240,185,11,0.35)"/>
|
|
203
|
+
<text x="1205" y="632" fill="#F0B90B" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="9" text-anchor="middle">BTC</text>
|
|
204
|
+
</g>
|
|
205
|
+
|
|
206
|
+
<!-- protocol builder -->
|
|
207
|
+
<g>
|
|
208
|
+
<rect x="520" y="710" width="360" height="72" rx="14" fill="#111925" stroke="rgba(124,196,255,0.22)" stroke-width="1" stroke-dasharray="5 4"/>
|
|
209
|
+
<text x="700" y="738" fill="#5B738F" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="10" text-anchor="middle" letter-spacing="1.6">BUILDER</text>
|
|
210
|
+
<text x="700" y="762" fill="#E8F1FA" font-family="Outfit, system-ui, sans-serif" font-size="16" font-weight="400" text-anchor="middle">protocol builder · gated templates · user-signed deploy</text>
|
|
211
|
+
</g>
|
|
212
|
+
|
|
213
|
+
<!-- footer -->
|
|
214
|
+
<text x="72" y="870" fill="#5B738F" font-family="Outfit, system-ui, sans-serif" font-size="12" font-weight="300">oracle routes input/command across a live multi-profile desk. profiles evolve. chains get added. not one bot.</text>
|
|
215
|
+
<text x="1328" y="870" fill="#3a6f99" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="10" text-anchor="end">self-custody · prepare → local sign</text>
|
|
216
|
+
</svg>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { listProtocolTemplates, runProtocolTemplateGate } from "../src/protocol-templates/gate.mjs";
|
|
3
|
+
|
|
4
|
+
const id = process.argv[2];
|
|
5
|
+
if (!id || id === "list") {
|
|
6
|
+
console.log(JSON.stringify(listProtocolTemplates(), null, 2));
|
|
7
|
+
process.exit(0);
|
|
8
|
+
}
|
|
9
|
+
try {
|
|
10
|
+
const r = runProtocolTemplateGate(id, { allowSkipStatic: process.env.REQUIRE_SLITHER !== "1" });
|
|
11
|
+
console.log(JSON.stringify(r, null, 2));
|
|
12
|
+
} catch (e) {
|
|
13
|
+
console.error(String(e.message || e));
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
@@ -1,38 +1,59 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oracle-protocol-builder
|
|
3
|
-
description: Use when the user wants Oracle to
|
|
3
|
+
description: Use when the user wants Oracle to scaffold/deploy protocol templates. Gated Foundry templates; prepare-only deploy; not a firm audit.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Protocol builder
|
|
7
7
|
|
|
8
|
-
Oracle
|
|
9
|
-
it writes and prepares; the user signs and deploys.
|
|
8
|
+
Oracle scaffolds and **prepares unsigned deploys**. The user signs. Custody boundary unchanged.
|
|
10
9
|
|
|
11
|
-
##
|
|
10
|
+
## Security gate (v1)
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
- scaffold mint/gacha/claim pages
|
|
15
|
-
- build DEX/pool/router integrations
|
|
16
|
-
- write deploy and verify scripts
|
|
17
|
-
- produce unsigned deploy or admin transactions
|
|
18
|
-
- create launch runbooks and monitoring dashboards
|
|
19
|
-
- audit authority, upgradeability, fees, and emergency controls
|
|
12
|
+
Before any template deploy prepare:
|
|
20
13
|
|
|
21
|
-
|
|
14
|
+
1. `forge test` must pass on the template
|
|
15
|
+
2. Slither runs when installed (optional skip if missing; set `REQUIRE_SLITHER=1` to hard-require)
|
|
16
|
+
3. JS `runProtocolTemplateGate` / `prepareTemplateDeploy` refuse otherwise
|
|
22
17
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
18
|
+
```js
|
|
19
|
+
// list
|
|
20
|
+
data.call("protocol-templates", "list")
|
|
21
|
+
// gate
|
|
22
|
+
data.call("protocol-templates", "gate", { templateId: "safe-erc20" })
|
|
23
|
+
// unsigned deploy prepare (stamped)
|
|
24
|
+
data.call("protocol-templates", "prepareDeploy", {
|
|
25
|
+
templateId: "safe-erc20",
|
|
26
|
+
chainId: 8453,
|
|
27
|
+
args: [name, symbol, supply, initialHolder, initialOwner],
|
|
28
|
+
})
|
|
29
|
+
```
|
|
29
30
|
|
|
30
|
-
|
|
31
|
+
CLI: `npm run protocol:gate -- safe-erc20`
|
|
32
|
+
|
|
33
|
+
## Shipped template: `safe-erc20`
|
|
34
|
+
|
|
35
|
+
- Fixed supply, mint once in constructor (no hidden mint)
|
|
36
|
+
- Ownable2Step + pause
|
|
37
|
+
- No tax / blacklist / max-tx / upgrade proxy
|
|
38
|
+
- Foundry tests included
|
|
39
|
+
|
|
40
|
+
## Honesty
|
|
31
41
|
|
|
32
|
-
|
|
33
|
-
fake TVL, or any contract whose main purpose is deceiving buyers.
|
|
42
|
+
**Reviewed templates + automated tests ≠ paid Solidity audit.**
|
|
34
43
|
|
|
35
|
-
|
|
44
|
+
Docs and prepare envelopes always set `firmAudit: false` and carry the disclaimer.
|
|
45
|
+
Mainnet TVL → independent firm audit.
|
|
46
|
+
|
|
47
|
+
## Required order (custom work)
|
|
48
|
+
|
|
49
|
+
1. Authority model
|
|
50
|
+
2. Threat model
|
|
51
|
+
3. Tests (Foundry)
|
|
52
|
+
4. Static analysis when available
|
|
53
|
+
5. Gate green
|
|
54
|
+
6. Prepare unsigned only
|
|
55
|
+
7. User signs + verify source
|
|
56
|
+
|
|
57
|
+
## Refusal line
|
|
36
58
|
|
|
37
|
-
|
|
38
|
-
artifact. End with the exact tests/simulations run and what remains unverified.
|
|
59
|
+
Refuse hidden drains, honeypots, wash-trading systems, undisclosed tax switches, fake TVL, or any contract whose main purpose is deceiving buyers.
|
package/src/data/catalog.mjs
CHANGED
|
@@ -59,6 +59,15 @@ registerProvider({
|
|
|
59
59
|
description: "Hyperliquid public /info",
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
+
registerProvider({
|
|
63
|
+
id: "protocol-templates",
|
|
64
|
+
venue: "protocol-builder",
|
|
65
|
+
chainIds: [],
|
|
66
|
+
auth: "none",
|
|
67
|
+
ops: ["health", "list", "gate", "prepareDeploy"],
|
|
68
|
+
description: "Gated Safe* Solidity templates: forge test required before unsigned deploy prepare. NOT a firm audit.",
|
|
69
|
+
});
|
|
70
|
+
|
|
62
71
|
registerProvider({
|
|
63
72
|
id: "poly-public",
|
|
64
73
|
venue: "poly",
|
package/src/data/desk-data.mjs
CHANGED
|
@@ -29,6 +29,8 @@ import * as hlstake from "./providers/hl-staking.mjs";
|
|
|
29
29
|
import * as hlmarkets from "./providers/hl-markets.mjs";
|
|
30
30
|
import * as hloutcome from "./providers/hl-outcome.mjs";
|
|
31
31
|
import * as polyclob from "./providers/poly-clob.mjs";
|
|
32
|
+
import * as protoTpl from "../protocol-templates/prepare-deploy.mjs";
|
|
33
|
+
import { listProtocolTemplates, runProtocolTemplateGate } from "../protocol-templates/gate.mjs";
|
|
32
34
|
import * as hlperps from "./providers/hl-perps.mjs";
|
|
33
35
|
import * as gecko from "./providers/geckoterminal.mjs";
|
|
34
36
|
import * as curve from "./providers/curve.mjs";
|
|
@@ -218,6 +220,12 @@ const OPS = {
|
|
|
218
220
|
prepareOrder: (o, a = {}) => hloutcome.hlPrepareOutcomeOrder(a, o),
|
|
219
221
|
prepareCancel: (o, a = {}) => hloutcome.hlPrepareOutcomeCancel(a, o),
|
|
220
222
|
},
|
|
223
|
+
"protocol-templates": {
|
|
224
|
+
health: () => ({ ok: true, templates: listProtocolTemplates().map((t) => t.id), firmAudit: false }),
|
|
225
|
+
list: () => listProtocolTemplates(),
|
|
226
|
+
gate: (o, a = {}) => runProtocolTemplateGate(a.templateId || a.id, o),
|
|
227
|
+
prepareDeploy: (o, a = {}) => protoTpl.prepareTemplateDeploy(a, o),
|
|
228
|
+
},
|
|
221
229
|
"poly-clob": {
|
|
222
230
|
prepareOrder: (o, a = {}) => {
|
|
223
231
|
// prepare is sync; wrap for dataCall
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { stampPrepared } from "../../prepare-envelope.mjs";
|
|
2
|
-
// Polymarket CLOB — prepare
|
|
3
|
-
//
|
|
4
|
-
// Sign/post
|
|
2
|
+
// Polymarket CLOB — prepare-only for Oracle.
|
|
3
|
+
// Builds unsigned EIP-712 order envelopes (no keys).
|
|
4
|
+
// Sign/post live in @oracle-agent/operator poly-exec only.
|
|
5
|
+
// Deep-import sign/post helpers hard-refuse here.
|
|
5
6
|
|
|
6
7
|
import { createHmac, randomInt } from "node:crypto";
|
|
7
8
|
import {
|
|
8
|
-
Wallet,
|
|
9
9
|
keccak256,
|
|
10
10
|
concat,
|
|
11
|
-
hexlify,
|
|
12
|
-
toUtf8Bytes,
|
|
13
11
|
zeroPadValue,
|
|
14
12
|
getCreate2Address,
|
|
15
13
|
AbiCoder,
|
|
@@ -226,204 +224,29 @@ export function buildOrderV2Message(params = {}) {
|
|
|
226
224
|
};
|
|
227
225
|
}
|
|
228
226
|
|
|
229
|
-
/**
|
|
230
|
-
export async function signOrderV2_1271(
|
|
231
|
-
|
|
232
|
-
"
|
|
233
|
-
"uint256 makerAmount,uint256 takerAmount,uint8 side,uint8 signatureType," +
|
|
234
|
-
"uint256 timestamp,bytes32 metadata,bytes32 builder)";
|
|
235
|
-
const ORDER_TYPE_HASH = keccak256(toUtf8Bytes(ORDER_TYPE_STRING));
|
|
236
|
-
const DOMAIN_TYPE_HASH = keccak256(
|
|
237
|
-
toUtf8Bytes("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")
|
|
227
|
+
/** Deep-import refuse: signing lives in @oracle-agent/operator. */
|
|
228
|
+
export async function signOrderV2_1271() {
|
|
229
|
+
throw new Error(
|
|
230
|
+
"poly-clob.signOrderV2_1271 refused: @oracle-agent/oracle is prepare-only. Sign via @oracle-agent/operator poly-exec."
|
|
238
231
|
);
|
|
239
|
-
const NAME_HASH = keccak256(toUtf8Bytes(EIP712_DOMAIN_V2.name));
|
|
240
|
-
const VERSION_HASH = keccak256(toUtf8Bytes(EIP712_DOMAIN_V2.version));
|
|
241
|
-
|
|
242
|
-
const appDomainSep = keccak256(
|
|
243
|
-
AbiCoder.defaultAbiCoder().encode(
|
|
244
|
-
["bytes32", "bytes32", "bytes32", "uint256", "address"],
|
|
245
|
-
[DOMAIN_TYPE_HASH, NAME_HASH, VERSION_HASH, BigInt(POLY_CHAIN_ID), exchangeAddress]
|
|
246
|
-
)
|
|
247
|
-
);
|
|
248
|
-
|
|
249
|
-
const contentsHash = keccak256(
|
|
250
|
-
AbiCoder.defaultAbiCoder().encode(
|
|
251
|
-
[
|
|
252
|
-
"bytes32",
|
|
253
|
-
"uint256",
|
|
254
|
-
"address",
|
|
255
|
-
"address",
|
|
256
|
-
"uint256",
|
|
257
|
-
"uint256",
|
|
258
|
-
"uint256",
|
|
259
|
-
"uint8",
|
|
260
|
-
"uint8",
|
|
261
|
-
"uint256",
|
|
262
|
-
"bytes32",
|
|
263
|
-
"bytes32",
|
|
264
|
-
],
|
|
265
|
-
[
|
|
266
|
-
ORDER_TYPE_HASH,
|
|
267
|
-
BigInt(orderMessage.salt),
|
|
268
|
-
orderMessage.maker,
|
|
269
|
-
orderMessage.signer,
|
|
270
|
-
BigInt(orderMessage.tokenId),
|
|
271
|
-
BigInt(orderMessage.makerAmount),
|
|
272
|
-
BigInt(orderMessage.takerAmount),
|
|
273
|
-
orderMessage.side,
|
|
274
|
-
orderMessage.signatureType,
|
|
275
|
-
BigInt(orderMessage.timestamp),
|
|
276
|
-
orderMessage.metadata,
|
|
277
|
-
orderMessage.builder,
|
|
278
|
-
]
|
|
279
|
-
)
|
|
280
|
-
);
|
|
281
|
-
|
|
282
|
-
const innerSig = await wallet.signTypedData(
|
|
283
|
-
{ ...EIP712_DOMAIN_V2, verifyingContract: exchangeAddress },
|
|
284
|
-
{
|
|
285
|
-
TypedDataSign: [
|
|
286
|
-
{ name: "contents", type: "Order" },
|
|
287
|
-
{ name: "name", type: "string" },
|
|
288
|
-
{ name: "version", type: "string" },
|
|
289
|
-
{ name: "chainId", type: "uint256" },
|
|
290
|
-
{ name: "verifyingContract", type: "address" },
|
|
291
|
-
{ name: "salt", type: "bytes32" },
|
|
292
|
-
],
|
|
293
|
-
Order: ORDER_TYPES_V2.Order,
|
|
294
|
-
},
|
|
295
|
-
{
|
|
296
|
-
contents: orderMessage,
|
|
297
|
-
name: "DepositWallet",
|
|
298
|
-
version: "1",
|
|
299
|
-
chainId: POLY_CHAIN_ID,
|
|
300
|
-
verifyingContract: orderMessage.maker, // deposit wallet (ERC-1271)
|
|
301
|
-
salt: BYTES32_ZERO,
|
|
302
|
-
}
|
|
303
|
-
);
|
|
304
|
-
|
|
305
|
-
const orderTypeHex = hexlify(toUtf8Bytes(ORDER_TYPE_STRING));
|
|
306
|
-
const lenHex = "0x" + (186).toString(16).padStart(4, "0");
|
|
307
|
-
return concat([innerSig, appDomainSep, contentsHash, orderTypeHex, lenHex]);
|
|
308
232
|
}
|
|
309
233
|
|
|
310
234
|
/**
|
|
311
|
-
*
|
|
312
|
-
* mode:
|
|
313
|
-
* - eoa (0): maker=funder or wallet
|
|
314
|
-
* - deposit (3): maker=signer=deriveDepositWallet(eoa) [default auto for desk agent]
|
|
235
|
+
* Deep-import refuse: signed order build lives in @oracle-agent/operator.
|
|
315
236
|
*/
|
|
316
|
-
export async function buildSignedOrderV2(
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
// Auto deposit-wallet flow when requested or when env forces it
|
|
322
|
-
const preferDeposit =
|
|
323
|
-
params.useDepositWallet === true ||
|
|
324
|
-
process.env.MAD_POLY_USE_DEPOSIT_WALLET === "1" ||
|
|
325
|
-
signatureType === 3;
|
|
326
|
-
|
|
327
|
-
if (preferDeposit || signatureType === undefined) {
|
|
328
|
-
// default path for accounts that reject EOA maker: try deposit wallet
|
|
329
|
-
if (preferDeposit || process.env.MAD_POLY_USE_DEPOSIT_WALLET !== "0") {
|
|
330
|
-
const dw = deriveDepositWallet(eoa);
|
|
331
|
-
// if caller didn't force eoa-only, use deposit when useDepositWallet or auto
|
|
332
|
-
if (preferDeposit || params.autoDeposit !== false) {
|
|
333
|
-
// keep eoa as default unless deposit forced — placeLimitOrder sets useDepositWallet on retry
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
if (params.useDepositWallet || signatureType === 3) {
|
|
339
|
-
funder = deriveDepositWallet(eoa);
|
|
340
|
-
signatureType = 3;
|
|
341
|
-
} else {
|
|
342
|
-
signatureType = signatureType ?? 0;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// sigType 3: maker = deposit wallet; signer = EOA (must match API key address)
|
|
346
|
-
// (CLOB: "order signer address has to be the address of the API KEY")
|
|
347
|
-
const orderSigner = eoa;
|
|
348
|
-
const built = buildOrderV2Message({
|
|
349
|
-
...params,
|
|
350
|
-
maker: funder,
|
|
351
|
-
signer: orderSigner,
|
|
352
|
-
signatureType,
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
const signature =
|
|
356
|
-
signatureType === 3
|
|
357
|
-
? await signOrderV2_1271(wallet, built.value, built.exchange)
|
|
358
|
-
: await wallet.signTypedData(built.domain, built.types, built.value);
|
|
359
|
-
|
|
360
|
-
return {
|
|
361
|
-
order: {
|
|
362
|
-
salt: parseInt(built.value.salt, 10),
|
|
363
|
-
maker: built.value.maker,
|
|
364
|
-
signer: built.value.signer,
|
|
365
|
-
tokenId: built.value.tokenId,
|
|
366
|
-
makerAmount: built.value.makerAmount,
|
|
367
|
-
takerAmount: built.value.takerAmount,
|
|
368
|
-
side: built.side,
|
|
369
|
-
signatureType: built.value.signatureType,
|
|
370
|
-
timestamp: built.value.timestamp,
|
|
371
|
-
metadata: built.value.metadata,
|
|
372
|
-
builder: built.value.builder,
|
|
373
|
-
expiration: "0",
|
|
374
|
-
signature,
|
|
375
|
-
},
|
|
376
|
-
owner: null,
|
|
377
|
-
orderType: built.orderType,
|
|
378
|
-
_meta: {
|
|
379
|
-
exchange: built.exchange,
|
|
380
|
-
notionalUsdc: built.notionalUsdc,
|
|
381
|
-
domain: built.domain,
|
|
382
|
-
types: built.types,
|
|
383
|
-
value: built.value,
|
|
384
|
-
depositWallet: signatureType === 3 ? funder : null,
|
|
385
|
-
eoa,
|
|
386
|
-
},
|
|
387
|
-
};
|
|
237
|
+
export async function buildSignedOrderV2() {
|
|
238
|
+
throw new Error(
|
|
239
|
+
"poly-clob.buildSignedOrderV2 refused: @oracle-agent/oracle is prepare-only. Sign via @oracle-agent/operator poly-exec."
|
|
240
|
+
);
|
|
388
241
|
}
|
|
389
242
|
|
|
390
243
|
/**
|
|
391
|
-
*
|
|
244
|
+
* Deep-import refuse: CLOB submit lives in @oracle-agent/operator.
|
|
392
245
|
*/
|
|
393
|
-
export async function postClobOrder({
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
clobRest = POLY_CLOB_REST,
|
|
398
|
-
fetchImpl = globalThis.fetch,
|
|
399
|
-
} = {}) {
|
|
400
|
-
if (!creds?.key || !creds?.secret || !creds?.passphrase) {
|
|
401
|
-
throw new Error("L2 creds required (key/secret/passphrase)");
|
|
402
|
-
}
|
|
403
|
-
const body = JSON.stringify(payload);
|
|
404
|
-
const path = "/order";
|
|
405
|
-
const headers = buildL2Headers(creds, address, "POST", path, body);
|
|
406
|
-
const res = await fetchImpl(`${clobRest.replace(/\/$/, "")}${path}`, {
|
|
407
|
-
method: "POST",
|
|
408
|
-
headers,
|
|
409
|
-
body,
|
|
410
|
-
});
|
|
411
|
-
const text = await res.text();
|
|
412
|
-
let data;
|
|
413
|
-
try {
|
|
414
|
-
data = JSON.parse(text);
|
|
415
|
-
} catch {
|
|
416
|
-
data = { raw: text };
|
|
417
|
-
}
|
|
418
|
-
if (!res.ok) {
|
|
419
|
-
const err = new Error(
|
|
420
|
-
`CLOB POST /order failed (${res.status}): ${text.slice(0, 300)}`
|
|
421
|
-
);
|
|
422
|
-
err.status = res.status;
|
|
423
|
-
err.body = data;
|
|
424
|
-
throw err;
|
|
425
|
-
}
|
|
426
|
-
return data;
|
|
246
|
+
export async function postClobOrder() {
|
|
247
|
+
throw new Error(
|
|
248
|
+
"poly-clob.postClobOrder refused: @oracle-agent/oracle is prepare-only. Submit via @oracle-agent/operator poly-exec."
|
|
249
|
+
);
|
|
427
250
|
}
|
|
428
251
|
|
|
429
252
|
/** Max notional USDC for a single desk order (env MAD_POLY_MAX_NOTIONAL, default 25). */
|