@panal/sdk 0.18.1 → 0.18.3
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/dist/client.d.ts +41 -9
- package/dist/client.js +74 -15
- package/dist/tablon.d.ts +5 -1
- package/dist/tablon.js +5 -1
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -145,6 +145,17 @@ export declare class PanalClient {
|
|
|
145
145
|
* por otro motivo— no se bloquea nada: que hable el error de verdad.
|
|
146
146
|
*/
|
|
147
147
|
private comprobarReserva;
|
|
148
|
+
/**
|
|
149
|
+
* El gas con el que se firma: `eth_estimateGas` + 10 %, y nunca por encima
|
|
150
|
+
* de `TOPE_GAS_RETIRADA`.
|
|
151
|
+
*
|
|
152
|
+
* Hace falta porque viem no estima: le pide al nodo que rellene la
|
|
153
|
+
* transacción (`eth_fillTransaction`), el de Monad a veces infla el límite, y
|
|
154
|
+
* Monad cobra el límite ENTERO. Cinco retiradas de MON perdieron lo retirado
|
|
155
|
+
* así entre julio y septiembre. Se pasa explícito a todo lo que firma una
|
|
156
|
+
* cuenta local en nombre de un programa que nadie está mirando.
|
|
157
|
+
*/
|
|
158
|
+
private gasFijo;
|
|
148
159
|
/**
|
|
149
160
|
* Espera el recibo y comprueba que la transacción SALIÓ BIEN.
|
|
150
161
|
*
|
|
@@ -337,14 +348,24 @@ export declare class PanalClient {
|
|
|
337
348
|
*/
|
|
338
349
|
readBoardBrief(taskId: bigint): Promise<string>;
|
|
339
350
|
/**
|
|
340
|
-
* Entrega una tarea del tablón
|
|
341
|
-
*
|
|
342
|
-
*
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
*
|
|
351
|
+
* Entrega una tarea del tablón hecha por una cuenta SIN servidor propio:
|
|
352
|
+
* deja el texto en su buzón y ancla su hash.
|
|
353
|
+
*
|
|
354
|
+
* DÓNDE, Y POR QUÉ ESTO SE CORRIGIÓ. El cliente recoge una entrega del
|
|
355
|
+
* endpoint que el TRABAJADOR tiene publicado en el registro (`bot:`), igual
|
|
356
|
+
* que en cualquier encargo: es lo que hace la web, y así entregan en ella las
|
|
357
|
+
* personas que cogen del tablón. La primera versión la dejaba en el buzón del
|
|
358
|
+
* tablón (la dirección cero), donde el cliente no mira nunca: habría anclado
|
|
359
|
+
* el hash de una entrega que nadie podía descargar.
|
|
360
|
+
*
|
|
361
|
+
* Así que va al buzón de quien entrega. Y si su `bot:` es un servidor propio
|
|
362
|
+
* —la plantilla de create-panal-agent—, esto se niega: ahí la entrega la sirve
|
|
363
|
+
* ese servidor, y lo que toca es guardarla donde él la sirve y anclarla con
|
|
364
|
+
* `deliverResult`. Dejarla en un buzón no la haría visible.
|
|
365
|
+
*
|
|
366
|
+
* EN ESTE ORDEN, buzón y después cadena: si el buzón falla no se ancla nada y
|
|
367
|
+
* se puede reintentar; al revés, el cliente vería una entrega en la cadena que
|
|
368
|
+
* no puede descargar. El buzón acepta repetir la misma entrega.
|
|
348
369
|
*/
|
|
349
370
|
deliverBoardResult(taskId: bigint, resultText: string): Promise<{
|
|
350
371
|
txHash: Hex;
|
|
@@ -436,7 +457,18 @@ export declare class PanalClient {
|
|
|
436
457
|
* ya están desplegados sin obligarles a actualizarse.
|
|
437
458
|
*/
|
|
438
459
|
private x402Endpoint;
|
|
439
|
-
/**
|
|
460
|
+
/**
|
|
461
|
+
* Retira lo acreditado en una moneda (patrón pull payment).
|
|
462
|
+
*
|
|
463
|
+
* EL GAS VA FIJADO A MANO, y no es un detalle. viem no estima: le pide al nodo
|
|
464
|
+
* que rellene la transacción (`eth_fillTransaction`), y el de Monad devuelve
|
|
465
|
+
* un gas disparatado para retirar MON —1,05 M para una wallet, 10,7 M para
|
|
466
|
+
* otra— cuando lo necesario son 55.157. Monad cobra el LÍMITE entero, no lo
|
|
467
|
+
* usado: una retirada de 1,092 MON pagó 1,096 MON de gas (2026-09-14, tx
|
|
468
|
+
* 0xa960cb7e…). El gas sale de `eth_estimateGas`, que da el número bueno, con
|
|
469
|
+
* un 10 % de margen; y si la estimación vuelve por encima de `TOPE_GAS_RETIRADA`
|
|
470
|
+
* no se firma nada.
|
|
471
|
+
*/
|
|
440
472
|
withdraw(currency?: Address): Promise<Hex>;
|
|
441
473
|
/** Comprueba el saldo antes de firmar, para fallar con un mensaje legible. */
|
|
442
474
|
private assertFunds;
|
package/dist/client.js
CHANGED
|
@@ -24,6 +24,11 @@ import { descend, newEnvelope, remainingBudget } from './envelope.js';
|
|
|
24
24
|
import { NATIVE_CURRENCY, addressesFor, chainFor } from './chains.js';
|
|
25
25
|
import { BUZON_URL, TABLON, VENTANA_FIRMA_S, encargoSignMessage, entregaSignMessage, ofertaSignMessage, } from './tablon.js';
|
|
26
26
|
import { TaskStatus, formatAgentMetadata, parseAgentMetadata, } from './types.js';
|
|
27
|
+
/**
|
|
28
|
+
* Por encima de esto una retirada no se firma: retirar MON son 55.157 de gas y
|
|
29
|
+
* $PANAL 103.511. Ver `withdraw()` para lo que pasó sin este tope.
|
|
30
|
+
*/
|
|
31
|
+
const TOPE_GAS_RETIRADA = 300000n;
|
|
27
32
|
/** Cuántos agentes se leen por llamada al registry. */
|
|
28
33
|
const REGISTRY_PAGE = 50n;
|
|
29
34
|
/** Tope duro de agentes recorridos, por si el registro crece mucho. */
|
|
@@ -162,6 +167,25 @@ export class PanalClient {
|
|
|
162
167
|
`faltan ${formatEther(reserva - saldo)} MON. No se ha enviado nada.`);
|
|
163
168
|
}
|
|
164
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* El gas con el que se firma: `eth_estimateGas` + 10 %, y nunca por encima
|
|
172
|
+
* de `TOPE_GAS_RETIRADA`.
|
|
173
|
+
*
|
|
174
|
+
* Hace falta porque viem no estima: le pide al nodo que rellene la
|
|
175
|
+
* transacción (`eth_fillTransaction`), el de Monad a veces infla el límite, y
|
|
176
|
+
* Monad cobra el límite ENTERO. Cinco retiradas de MON perdieron lo retirado
|
|
177
|
+
* así entre julio y septiembre. Se pasa explícito a todo lo que firma una
|
|
178
|
+
* cuenta local en nombre de un programa que nadie está mirando.
|
|
179
|
+
*/
|
|
180
|
+
async gasFijo(que, llamada) {
|
|
181
|
+
const estimado = await this.publicClient.estimateContractGas({ ...llamada, account: this.account });
|
|
182
|
+
const gas = (estimado * 11n + 9n) / 10n;
|
|
183
|
+
if (gas > TOPE_GAS_RETIRADA) {
|
|
184
|
+
throw new Error(`${que}: la estimación de gas salió en ${estimado}, muy por encima de lo normal. ` +
|
|
185
|
+
'Monad cobra el límite entero: no se ha enviado nada.');
|
|
186
|
+
}
|
|
187
|
+
return gas;
|
|
188
|
+
}
|
|
165
189
|
/**
|
|
166
190
|
* Espera el recibo y comprueba que la transacción SALIÓ BIEN.
|
|
167
191
|
*
|
|
@@ -794,11 +818,11 @@ export class PanalClient {
|
|
|
794
818
|
throw new Error(`${yo} no es un agente activo en el registro, y claimTask solo acepta agentes activos. ` +
|
|
795
819
|
'Regístrate (o reactívate) antes de coger trabajo.');
|
|
796
820
|
}
|
|
821
|
+
const llamada = { address: this.addresses.escrow, abi: escrowAbi, functionName: 'claimTask', args: [taskId] };
|
|
822
|
+
const gas = await this.gasFijo(`Coger la tarea #${taskId}`, llamada);
|
|
797
823
|
const txHash = await wallet.writeContract({
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
functionName: 'claimTask',
|
|
801
|
-
args: [taskId],
|
|
824
|
+
...llamada,
|
|
825
|
+
gas,
|
|
802
826
|
chain: chainFor(this.network),
|
|
803
827
|
account: this.account,
|
|
804
828
|
});
|
|
@@ -844,14 +868,24 @@ export class PanalClient {
|
|
|
844
868
|
return brief;
|
|
845
869
|
}
|
|
846
870
|
/**
|
|
847
|
-
* Entrega una tarea del tablón
|
|
871
|
+
* Entrega una tarea del tablón hecha por una cuenta SIN servidor propio:
|
|
872
|
+
* deja el texto en su buzón y ancla su hash.
|
|
873
|
+
*
|
|
874
|
+
* DÓNDE, Y POR QUÉ ESTO SE CORRIGIÓ. El cliente recoge una entrega del
|
|
875
|
+
* endpoint que el TRABAJADOR tiene publicado en el registro (`bot:`), igual
|
|
876
|
+
* que en cualquier encargo: es lo que hace la web, y así entregan en ella las
|
|
877
|
+
* personas que cogen del tablón. La primera versión la dejaba en el buzón del
|
|
878
|
+
* tablón (la dirección cero), donde el cliente no mira nunca: habría anclado
|
|
879
|
+
* el hash de una entrega que nadie podía descargar.
|
|
880
|
+
*
|
|
881
|
+
* Así que va al buzón de quien entrega. Y si su `bot:` es un servidor propio
|
|
882
|
+
* —la plantilla de create-panal-agent—, esto se niega: ahí la entrega la sirve
|
|
883
|
+
* ese servidor, y lo que toca es guardarla donde él la sirve y anclarla con
|
|
884
|
+
* `deliverResult`. Dejarla en un buzón no la haría visible.
|
|
848
885
|
*
|
|
849
|
-
* EN
|
|
850
|
-
*
|
|
851
|
-
*
|
|
852
|
-
* vería una entrega en la cadena que no puede descargar. Dejándola primero,
|
|
853
|
-
* un fallo del buzón no ancla nada y se puede reintentar; y el buzón acepta
|
|
854
|
-
* repetir la misma entrega, porque da el mismo hash.
|
|
886
|
+
* EN ESTE ORDEN, buzón y después cadena: si el buzón falla no se ancla nada y
|
|
887
|
+
* se puede reintentar; al revés, el cliente vería una entrega en la cadena que
|
|
888
|
+
* no puede descargar. El buzón acepta repetir la misma entrega.
|
|
855
889
|
*/
|
|
856
890
|
async deliverBoardResult(taskId, resultText) {
|
|
857
891
|
const wallet = this.wallet();
|
|
@@ -863,9 +897,18 @@ export class PanalClient {
|
|
|
863
897
|
if (task.status !== TaskStatus.Open) {
|
|
864
898
|
throw new Error(`La tarea #${taskId} está "${TaskStatus[task.status]}": solo se entrega lo que sigue abierto.`);
|
|
865
899
|
}
|
|
900
|
+
const ficha = await this.leerAgente(yo);
|
|
901
|
+
const canal = ficha.metadata.botUrl?.replace(/\/+$/, '') ?? '';
|
|
902
|
+
if (!canal) {
|
|
903
|
+
throw new Error(`${yo} no publica ningún canal (\`bot:\`): el cliente no tendría de dónde recoger la entrega.`);
|
|
904
|
+
}
|
|
905
|
+
if (!canal.toLowerCase().startsWith(this.buzonUrl.toLowerCase() + '/')) {
|
|
906
|
+
throw new Error(`${yo} recibe en ${canal}, su propio servidor: el cliente recoge la entrega de ahí. ` +
|
|
907
|
+
'Guárdala donde tu servidor sirve /result/:taskId y ánclala con deliverResult(). No se ha enviado nada.');
|
|
908
|
+
}
|
|
866
909
|
const expira = Math.floor(Date.now() / 1000) + VENTANA_FIRMA_S;
|
|
867
910
|
const firma = await wallet.signMessage({ account: this.account, message: entregaSignMessage(taskId, expira) });
|
|
868
|
-
const { status, text } = await fetchLimited(`${
|
|
911
|
+
const { status, text } = await fetchLimited(`${canal}/entrega/${taskId}`, {
|
|
869
912
|
method: 'POST',
|
|
870
913
|
headers: { 'content-type': 'application/json' },
|
|
871
914
|
body: JSON.stringify({ entrega: resultText, address: yo, signature: firma, expira }),
|
|
@@ -1045,18 +1088,34 @@ export class PanalClient {
|
|
|
1045
1088
|
}
|
|
1046
1089
|
return rutaDeAgente(base, 'x402/ask');
|
|
1047
1090
|
}
|
|
1048
|
-
/**
|
|
1091
|
+
/**
|
|
1092
|
+
* Retira lo acreditado en una moneda (patrón pull payment).
|
|
1093
|
+
*
|
|
1094
|
+
* EL GAS VA FIJADO A MANO, y no es un detalle. viem no estima: le pide al nodo
|
|
1095
|
+
* que rellene la transacción (`eth_fillTransaction`), y el de Monad devuelve
|
|
1096
|
+
* un gas disparatado para retirar MON —1,05 M para una wallet, 10,7 M para
|
|
1097
|
+
* otra— cuando lo necesario son 55.157. Monad cobra el LÍMITE entero, no lo
|
|
1098
|
+
* usado: una retirada de 1,092 MON pagó 1,096 MON de gas (2026-09-14, tx
|
|
1099
|
+
* 0xa960cb7e…). El gas sale de `eth_estimateGas`, que da el número bueno, con
|
|
1100
|
+
* un 10 % de margen; y si la estimación vuelve por encima de `TOPE_GAS_RETIRADA`
|
|
1101
|
+
* no se firma nada.
|
|
1102
|
+
*/
|
|
1049
1103
|
async withdraw(currency = NATIVE_CURRENCY) {
|
|
1050
1104
|
const wallet = this.wallet();
|
|
1051
|
-
const
|
|
1105
|
+
const llamada = {
|
|
1052
1106
|
address: this.addresses.escrow,
|
|
1053
1107
|
abi: escrowAbi,
|
|
1054
1108
|
functionName: 'withdraw',
|
|
1055
1109
|
args: [currency],
|
|
1110
|
+
};
|
|
1111
|
+
const gas = await this.gasFijo('La retirada', llamada);
|
|
1112
|
+
const hash = await wallet.writeContract({
|
|
1113
|
+
...llamada,
|
|
1114
|
+
gas,
|
|
1056
1115
|
chain: chainFor(this.network),
|
|
1057
1116
|
account: this.account,
|
|
1058
1117
|
});
|
|
1059
|
-
await this.
|
|
1118
|
+
await this.esperarExito(hash, 'La retirada');
|
|
1060
1119
|
return hash;
|
|
1061
1120
|
}
|
|
1062
1121
|
/** Comprueba el saldo antes de firmar, para fallar con un mensaje legible. */
|
package/dist/tablon.d.ts
CHANGED
|
@@ -15,7 +15,11 @@
|
|
|
15
15
|
*
|
|
16
16
|
* GET <buzón>/0x000…000/lista los anuncios, sin firma
|
|
17
17
|
* GET <buzón>/0x000…000/encargo/:taskId el encargo, solo para quien lo cogió
|
|
18
|
-
*
|
|
18
|
+
*
|
|
19
|
+
* La ENTREGA no va al tablón. El cliente la recoge del endpoint que el
|
|
20
|
+
* trabajador publica en el registro, como en cualquier encargo: quien entrega
|
|
21
|
+
* sin servidor propio la deja en SU buzón (`<buzón>/<su dirección>/entrega`), y
|
|
22
|
+
* un agente con servidor la sirve él. Ver `deliverBoardResult`.
|
|
19
23
|
*
|
|
20
24
|
* DOS TEXTOS, Y NO ES REDUNDANCIA. El ANUNCIO se lee sin coger nada y lo firma
|
|
21
25
|
* el cliente, así que el buzón no lo puede cambiar. El ENCARGO solo lo ve quien
|
package/dist/tablon.js
CHANGED
|
@@ -15,7 +15,11 @@
|
|
|
15
15
|
*
|
|
16
16
|
* GET <buzón>/0x000…000/lista los anuncios, sin firma
|
|
17
17
|
* GET <buzón>/0x000…000/encargo/:taskId el encargo, solo para quien lo cogió
|
|
18
|
-
*
|
|
18
|
+
*
|
|
19
|
+
* La ENTREGA no va al tablón. El cliente la recoge del endpoint que el
|
|
20
|
+
* trabajador publica en el registro, como en cualquier encargo: quien entrega
|
|
21
|
+
* sin servidor propio la deja en SU buzón (`<buzón>/<su dirección>/entrega`), y
|
|
22
|
+
* un agente con servidor la sirve él. Ver `deliverBoardResult`.
|
|
19
23
|
*
|
|
20
24
|
* DOS TEXTOS, Y NO ES REDUNDANCIA. El ANUNCIO se lee sin coger nada y lo firma
|
|
21
25
|
* el cliente, así que el buzón no lo puede cambiar. El ENCARGO solo lo ve quien
|