@ixo/asks-mcp 2.0.0-dev.5 → 2.0.0

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.
Files changed (2) hide show
  1. package/dist/asks-mcp.mjs +55 -40
  2. package/package.json +1 -1
package/dist/asks-mcp.mjs CHANGED
@@ -38786,9 +38786,9 @@ function nLength(n, nBitLength) {
38786
38786
  const nByteLength = Math.ceil(_nBitLength / 8);
38787
38787
  return { nBitLength: _nBitLength, nByteLength };
38788
38788
  }
38789
- function Field(ORDER2, opts = {}) {
38789
+ function Field(ORDER3, opts = {}) {
38790
38790
  Object.freeze(_Field.prototype);
38791
- return new _Field(ORDER2, opts);
38791
+ return new _Field(ORDER3, opts);
38792
38792
  }
38793
38793
  function FpSqrtEven(Fp2, elm) {
38794
38794
  validateField(Fp2);
@@ -38867,9 +38867,9 @@ var init_modular = __esm({
38867
38867
  ONE = _1n3;
38868
38868
  _lengths;
38869
38869
  _mod;
38870
- constructor(ORDER2, opts = {}) {
38871
- if (ORDER2 <= _1n3)
38872
- throw new Error("invalid field: expected ORDER > 1, got " + ORDER2);
38870
+ constructor(ORDER3, opts = {}) {
38871
+ if (ORDER3 <= _1n3)
38872
+ throw new Error("invalid field: expected ORDER > 1, got " + ORDER3);
38873
38873
  let _nbitLength = void 0;
38874
38874
  this.isLE = false;
38875
38875
  if (opts != null && typeof opts === "object") {
@@ -38884,10 +38884,10 @@ var init_modular = __esm({
38884
38884
  if (typeof opts.modFromBytes === "boolean")
38885
38885
  this._mod = opts.modFromBytes;
38886
38886
  }
38887
- const { nBitLength, nByteLength } = nLength(ORDER2, _nbitLength);
38887
+ const { nBitLength, nByteLength } = nLength(ORDER3, _nbitLength);
38888
38888
  if (nByteLength > 2048)
38889
38889
  throw new Error("invalid field: expected ORDER of <= 2048 bytes");
38890
- this.ORDER = ORDER2;
38890
+ this.ORDER = ORDER3;
38891
38891
  this.BITS = nBitLength;
38892
38892
  this.BYTES = nByteLength;
38893
38893
  Object.freeze(this);
@@ -38961,7 +38961,7 @@ var init_modular = __esm({
38961
38961
  }
38962
38962
  fromBytes(bytes3, skipValidation = false) {
38963
38963
  abytes5(bytes3);
38964
- const { _lengths: allowedLengths, BYTES, isLE: isLE3, ORDER: ORDER2, _mod: modFromBytes } = this;
38964
+ const { _lengths: allowedLengths, BYTES, isLE: isLE3, ORDER: ORDER3, _mod: modFromBytes } = this;
38965
38965
  if (allowedLengths) {
38966
38966
  if (bytes3.length < 1 || !allowedLengths.includes(bytes3.length) || bytes3.length > BYTES) {
38967
38967
  throw new Error("Field.fromBytes: expected " + allowedLengths + " bytes, got " + bytes3.length);
@@ -38974,7 +38974,7 @@ var init_modular = __esm({
38974
38974
  throw new Error("Field.fromBytes: expected " + BYTES + " bytes, got " + bytes3.length);
38975
38975
  let scalar = isLE3 ? bytesToNumberLE2(bytes3) : bytesToNumberBE(bytes3);
38976
38976
  if (modFromBytes)
38977
- scalar = mod2(scalar, ORDER2);
38977
+ scalar = mod2(scalar, ORDER3);
38978
38978
  if (!skipValidation) {
38979
38979
  if (!this.isValid(scalar))
38980
38980
  throw new Error("invalid field element: outside of range 0..ORDER");
@@ -264720,7 +264720,7 @@ var init_inviteMessages = __esm({
264720
264720
  return rest;
264721
264721
  };
264722
264722
  linkedinMessage = (act, signer2, now3 = Date.now(), digest2 = "") => `linkedin:${act}:${signer2}:${now3}:${digest2}`;
264723
- CASHOUT_ACTS = ["quote", "draft", "status"];
264723
+ CASHOUT_ACTS = ["quote", "draft", "status", "kyc"];
264724
264724
  cashoutMessage = (act, signer2, now3 = Date.now(), digest2 = "") => `cashout:${act}:${signer2}:${now3}:${digest2}`;
264725
264725
  ROOM_ACTS = ["mine", "read", "send", "bring", "export"];
264726
264726
  roomBody = (body) => {
@@ -266883,8 +266883,14 @@ var init_takeBack = __esm({
266883
266883
  var cashout_exports = {};
266884
266884
  __export(cashout_exports, {
266885
266885
  cashOut: () => cashOut,
266886
- cashOutStatus: () => cashOutStatus
266886
+ cashOutStatus: () => cashOutStatus,
266887
+ identityLine: () => identityLine
266887
266888
  });
266889
+ function whyOff(one) {
266890
+ if (one.enabled === false) return one.reason === "not_in_country" ? "not offered in your country yet" : one.reason === "coming_soon" ? "coming soon" : "busy right now, try later";
266891
+ if (one.provider === "yellowcard-worker" || one.method.startsWith("yellowcard")) return "coming soon";
266892
+ return null;
266893
+ }
266888
266894
  async function call2(deps, path, body) {
266889
266895
  try {
266890
266896
  const response = await deps.fetch(`${deps.site.replace(/\/+$/, "")}${path}`, {
@@ -266903,52 +266909,60 @@ async function signedCall(deps, act, fields) {
266903
266909
  const message = await cashoutWords(act, deps.signer.address, full);
266904
266910
  return call2(deps, `/api/cashout/${act}`, { address: deps.signer.address, ...full, proof: { kind: "adr36", message, ...await signWords(deps.signer.mnemonic, message) } });
266905
266911
  }
266912
+ async function identityLine(deps) {
266913
+ const answer = await signedCall(deps, "kyc", {});
266914
+ const status = answer.status === 200 ? answer.body.status : "unknown";
266915
+ if (status === "verified") return "Your identity check is done.";
266916
+ if (status === "in_review") return "Your identity check is being reviewed.";
266917
+ const info = await call2(deps, "/api/cashout/info");
266918
+ const kycUrl = typeof info.body.kycUrl === "string" ? info.body.kycUrl : `${deps.site.replace(/\/+$/, "")}/me/identity`;
266919
+ return `Do your identity check first: ${kycUrl}`;
266920
+ }
266906
266921
  async function cashOut(deps, input) {
266907
266922
  const person = deps.signer.principal ?? deps.signer.address;
266908
- const [ready, payBase] = await Promise.all([signedCall(deps, "status", {}), deps.payBase(person)]);
266923
+ const [ready, payBase, kycLine] = await Promise.all([signedCall(deps, "status", {}), deps.payBase(person), identityLine(deps)]);
266909
266924
  if (ready.status !== 200) return said3(ready);
266910
266925
  const kyc = ready.body.kyc;
266911
266926
  if (!ready.body.linkedin) return "Cash-out needs your LinkedIn connected first. Next: connect_linkedin (about a minute), then cash_out again.";
266912
266927
  const available = payBase / 1e6;
266913
266928
  if (available <= 0) return "You have nothing to cash out yet.";
266914
- const kycLine = kyc?.status === "verified" ? "" : kyc?.status === "expired" ? `Your identity check has expired. Renew it first: ${deps.site.replace(/\/+$/, "")}/me/identity` : `Cash-out needs an identity check. If you haven't done it yet, do it first: ${deps.site.replace(/\/+$/, "")}/me/identity`;
266915
- if (kyc?.status === "expired") return kycLine;
266929
+ if (kyc?.status === "expired") return `Your identity check has expired. Renew it first: ${deps.site.replace(/\/+$/, "")}/me/identity`;
266916
266930
  const country = input.country?.trim().toUpperCase();
266917
266931
  if (!country || !/^[A-Z]{2}$/.test(country)) return [`You have $${available.toFixed(2)} to cash out.`, kycLine, 'Which country are you in? (Ask the person; then call cash_out with country, like "NG" or "DE".)'].filter(Boolean).join("\n");
266918
266932
  const info = await call2(deps, `/api/cashout/info?country=${country}`);
266919
266933
  if (info.status !== 200) return said3(info);
266920
- const methods = info.body.methods ?? [];
266934
+ const methods = (info.body.methods ?? []).filter((one) => WAYS[one.method]).sort((a, b) => ORDER2.indexOf(a.method) - ORDER2.indexOf(b.method));
266921
266935
  const fee = info.body.fee;
266922
- if (!methods.length) return `There's no way to cash out in ${country} yet.`;
266923
- const chosen2 = methods.find((one) => one.method === input.method);
266936
+ if (!methods.some((one) => !whyOff(one))) return `We can't send money to ${country} yet.`;
266937
+ const chosen2 = methods.find((one) => one.method === input.method && !whyOff(one));
266924
266938
  if (!chosen2)
266925
266939
  return [
266926
266940
  `You have $${available.toFixed(2)} to cash out. Ways to get paid in ${country}:`,
266927
- ...methods.map((one) => `- ${WAYS[one.method] ?? one.method} (method "${one.method}"): $${one.minUsd} to $${one.maxUsd}`),
266941
+ ...methods.map((one) => `- ${WAYS[one.method]} (method "${one.method}"): ${whyOff(one) ?? `$${one.minUsd ?? "0.00"}${one.maxUsd ? ` to $${one.maxUsd}` : ""}`}`),
266928
266942
  `Fee: ${fee?.bps ? `${fee.bps / 100}%` : "none"}${fee?.minUsd && Number(fee.minUsd) > 0 ? `, at least $${fee.minUsd}` : ""}.`,
266929
266943
  kycLine,
266930
266944
  "(Ask which way and how much; then call cash_out with method and amount_usd.)"
266931
266945
  ].filter(Boolean).join("\n");
266932
266946
  const amount3 = input.amount_usd?.trim().replace(/^\$/, "");
266933
- if (!amount3 || !/^\d+(\.\d{1,2})?$/.test(amount3)) return `How much do you want to cash out? You have $${available.toFixed(2)}; this way takes $${chosen2.minUsd} to $${chosen2.maxUsd}. (Then call cash_out with amount_usd, like "25".)`;
266947
+ if (!amount3 || !/^\d+(\.\d{1,2})?$/.test(amount3)) return `How much do you want to cash out? You have $${available.toFixed(2)}; this way takes $${chosen2.minUsd ?? "0.00"}${chosen2.maxUsd ? ` to $${chosen2.maxUsd}` : ""}. (Then call cash_out with amount_usd, like "25".)`;
266934
266948
  if (Number(amount3) > available) return `You have $${available.toFixed(2)} to cash out, less than $${amount3}. Pick a smaller amount.`;
266935
- if (Number(amount3) < Number(chosen2.minUsd)) return `The smallest you can cash out this way is $${chosen2.minUsd}.`;
266936
- if (Number(amount3) > Number(chosen2.maxUsd)) return `The largest you can cash out this way is $${chosen2.maxUsd}.`;
266949
+ if (chosen2.minUsd && Number(amount3) < Number(chosen2.minUsd)) return `The smallest you can cash out this way is $${chosen2.minUsd}.`;
266950
+ if (chosen2.maxUsd && Number(amount3) > Number(chosen2.maxUsd)) return `The largest you can cash out this way is $${chosen2.maxUsd}.`;
266937
266951
  const to = input.to?.trim();
266938
266952
  if (chosen2.fields.includes("address") && !(to && BASE_ADDRESS.test(to))) return "Which Base account should receive it? (Its address starts with 0x; then call cash_out with to.)";
266939
266953
  const quote = await signedCall(deps, "quote", { method: chosen2.method, country, amountUsd: amount3 });
266940
266954
  if (quote.status !== 201) return said3(quote);
266941
266955
  const q = quote.body;
266942
- const receive = `You'll receive $${q.receive?.amount ?? q.amountUsd}${q.receive?.currency && q.receive.currency !== "USD" ? ` in ${q.receive.currency}` : ""} (fee $${q.feeUsd ?? "0.00"}).`;
266956
+ const receive = `You'll receive $${q.receive?.amount ?? q.amountUsd} (fee $${q.feeUsd ?? "0.00"}).`;
266943
266957
  const named = chosen2.fields.includes("accountHolder") ? NAME_LINE : "";
266944
- if (!input.confirm) return [`Cash out $${q.amountUsd} by ${WAYS[chosen2.method] ?? chosen2.method}${to ? ` to ${to}` : ""}.`, receive, named, kycLine, "Nothing is sent yet. To go ahead, call cash_out again with the same answers and confirm: true."].filter(Boolean).join("\n");
266958
+ if (!input.confirm) return [`Cash out $${q.amountUsd}: ${WAYS[chosen2.method]}${to ? `, to ${to}` : ""}.`, receive, named, kycLine, "Nothing is sent yet. To go ahead, call cash_out again with the same answers and confirm: true."].filter(Boolean).join("\n");
266945
266959
  const link5 = new URL(`${deps.site.replace(/\/+$/, "")}/me/cash-out`);
266946
266960
  link5.searchParams.set("quote", String(q.quoteId));
266947
266961
  link5.searchParams.set("method", chosen2.method);
266948
266962
  link5.searchParams.set("amount", amount3);
266949
266963
  link5.searchParams.set("country", country);
266950
266964
  if (to) link5.searchParams.set("to", to);
266951
- return [receive, named, `Open this and confirm with one tap: ${link5.toString()}`, "Your money leaves only when you confirm there. I signed nothing. (Later, cash_out_status with the id that page shows says where it stands.)"].filter(Boolean).join("\n");
266965
+ return [receive, named, `Open this and tap Confirm: ${link5.toString()}`, "Your money leaves only when you confirm there. I sent nothing. (Later, cash_out_status with the id that page shows says where it stands.)"].filter(Boolean).join("\n");
266952
266966
  }
266953
266967
  async function cashOutStatus(deps, id) {
266954
266968
  const answer = await signedCall(deps, "status", { id });
@@ -266960,12 +266974,12 @@ async function cashOutStatus(deps, id) {
266960
266974
  switch (lapsed ? "expired" : v.state) {
266961
266975
  case "open":
266962
266976
  case "signing":
266963
- return `Not confirmed yet: open the confirm link and tap confirm (${money2}).`;
266977
+ return `Not confirmed yet: open the link and tap Confirm (${money2}).`;
266964
266978
  case "sent":
266965
- return "Confirmed. The payout is starting.";
266979
+ return "Confirmed. It's on its way.";
266966
266980
  case "expired":
266967
266981
  case "failed":
266968
- return "This cash-out expired before it was confirmed. Nothing was taken. Start a new one with cash_out.";
266982
+ return "This took too long, so it was stopped. Nothing was taken. Start a new one with cash_out.";
266969
266983
  case "converting":
266970
266984
  case "taking":
266971
266985
  case "paying":
@@ -266973,31 +266987,32 @@ async function cashOutStatus(deps, id) {
266973
266987
  case "paid":
266974
266988
  return `Paid: ${money2}.`;
266975
266989
  case "needs_attention":
266976
- return `Your payout didn't go through: ${v.reason ?? "the payout failed"}. Check your details or pick another way: ${v.fixUrl ?? ""}
266977
- ${NAME_LINE}`;
266990
+ return v.fixUrl ? `Something needs fixing: the money didn't reach you. Check your details or pick another way here: ${v.fixUrl}
266991
+ ${NAME_LINE}` : "Something needs fixing, and we're looking into it. Nothing to do on your side.";
266978
266992
  case "not_converted":
266979
266993
  case "cancelled":
266980
- return "This cash-out didn't go through, and nothing was taken.";
266994
+ return "It didn't go through, and nothing was taken.";
266981
266995
  case "refunded":
266982
- return "Your money was sent back to you.";
266996
+ return "Your money is back in your account.";
266983
266997
  default:
266984
- return `State: ${v.state ?? "unknown"}.`;
266998
+ return "We're still checking where it stands. Ask again in a minute.";
266985
266999
  }
266986
267000
  }
266987
- var WAYS, BASE_ADDRESS, NAME_LINE, said3;
267001
+ var WAYS, ORDER2, BASE_ADDRESS, NAME_LINE, said3;
266988
267002
  var init_cashout = __esm({
266989
267003
  "src/cashout.ts"() {
266990
267004
  "use strict";
266991
267005
  init_accountProof();
266992
267006
  init_inviteProof();
266993
267007
  WAYS = {
266994
- usdc_base: "Digital dollars to your own Base account (any country)",
266995
- stripe_bank: "Bank account, through Stripe",
266996
- yellowcard_bank: "Bank account, through Yellow Card",
266997
- yellowcard_momo: "Mobile money, through Yellow Card"
267008
+ stripe_bank: "To your bank account (through Stripe)",
267009
+ yellowcard_bank: "To your bank account (through Yellow Card)",
267010
+ yellowcard_momo: "To your mobile money (M-PESA, MTN and others)",
267011
+ usdc_base: "Digital dollars (USDC), to your own Base account (its address starts with 0x)"
266998
267012
  };
267013
+ ORDER2 = Object.keys(WAYS);
266999
267014
  BASE_ADDRESS = /^0x[0-9a-fA-F]{40}$/;
267000
- NAME_LINE = "The payout account name must match the name on your ID.";
267015
+ NAME_LINE = "The name on the account must match the name on your ID.";
267001
267016
  said3 = (answer) => answer.status === 503 && answer.body.code === "not-open" ? "Cash-out isn't open on this network yet." : String(answer.body.error ?? `Cash-out refused this (${answer.status}).`);
267002
267017
  }
267003
267018
  });
@@ -292365,7 +292380,7 @@ import { randomBytes as randomBytes7 } from "node:crypto";
292365
292380
  // package.json
292366
292381
  var package_default = {
292367
292382
  name: "@ixo/asks-mcp",
292368
- version: "2.0.0-dev.5",
292383
+ version: "2.0.0",
292369
292384
  description: "The Openhands Network MCP server: read the board, answer asks, post work and get paid on the ixo chain, with a key of its own on your machine.",
292370
292385
  license: "Apache-2.0",
292371
292386
  repository: {
@@ -292589,7 +292604,7 @@ var TOOLS = {
292589
292604
  },
292590
292605
  cash_out: {
292591
292606
  title: "Cash out your earnings",
292592
- description: `Turn what the person earned into money: digital dollars to your own Base account, or a bank account where offered. One step per call: it reads what they have available, their LinkedIn and identity check, then asks the country, the way to get paid, the amount and (for a Base account) the address, and shows the quote in plain words ("You'll receive $X (fee $0)"). With confirm: true it gives ONE link: the person opens it and confirms with one tap; that page checks their identity and they sign there. Limits and fees come from IXO's cash-out service, never from here. No LinkedIn: say connect_linkedin first. Signs no money and holds no key of theirs.`,
292607
+ description: `Turn what the person earned into money: to their bank account, their mobile money, or "Digital dollars (USDC)" to their own Base account, where offered. Speak plainly to the person: no technical words. One step per call: it reads what they have available, their LinkedIn and identity check, then asks the country, the way to get paid (every way is listed; the ones they can't pick say why), the amount and (for digital dollars) the 0x address, and shows "You'll receive $X (fee $0)". With confirm: true it gives ONE link: the person opens it and taps Confirm there, where their identity is checked and they confirm in their sign-in app. Limits and fees come from IXO's cash-out service, never from here. No LinkedIn: say connect_linkedin first. Signs no money and holds no key of theirs.`,
292593
292608
  spends: false,
292594
292609
  hosted: false,
292595
292610
  annotations: acts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ixo/asks-mcp",
3
- "version": "2.0.0-dev.5",
3
+ "version": "2.0.0",
4
4
  "description": "The Openhands Network MCP server: read the board, answer asks, post work and get paid on the ixo chain, with a key of its own on your machine.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {