@arkade-os/skill 0.1.2 → 0.1.4

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/SKILL.md CHANGED
@@ -27,6 +27,21 @@ Swap between BTC and stablecoins (USDC/USDT) via LendaSwap.
27
27
 
28
28
  **Default Server:** https://arkade.computer
29
29
 
30
+ ## Agent Safety Rules
31
+
32
+ **IMPORTANT: The following commands move real funds. The agent MUST always ask the user for explicit confirmation before executing them, displaying the amount and destination:**
33
+
34
+ - `send` — sends sats to an Ark address
35
+ - `offboard` — moves offchain BTC to an onchain Bitcoin address
36
+ - `onboard` — moves onchain BTC into Arkade
37
+ - `ln-pay` — pays a Lightning invoice
38
+ - `swap-to-stable` / `swap-to-btc` — executes a stablecoin swap
39
+ - `swap-claim` / `swap-refund` — claims or refunds a swap
40
+
41
+ Read-only commands (`address`, `balance`, `history`, `ln-invoice`, `ln-fees`, `ln-limits`, `ln-pending`, `swap-quote`, `swap-pairs`, `swap-status`, `swap-pending`, `boarding-address`) are safe to run without confirmation.
42
+
43
+ **Wallet initialization:** `init` creates a new private key stored at `~/.arkade-wallet/config.json` (permissions `0600`). The agent should inform the user before first initialization.
44
+
30
45
  ## Installation
31
46
 
32
47
  ### Quick Start (no install required)
package/cli/arkade.mjs CHANGED
@@ -171,6 +171,8 @@ COMMANDS:
171
171
  Swap BTC to stablecoin
172
172
  swap-to-btc <amt> <token> <chain> <evm-addr>
173
173
  Swap stablecoin to BTC
174
+ swap-claim <swap-id> Claim a completed swap
175
+ swap-refund <swap-id> [addr] Refund an expired/failed swap
174
176
  swap-status <swap-id> Check swap status
175
177
  swap-pending Show pending stablecoin swaps
176
178
  swap-pairs Show available stablecoin pairs
@@ -613,6 +615,44 @@ async function cmdLnPending() {
613
615
  }
614
616
  }
615
617
 
618
+ /**
619
+ * Create a LendaSwapSkill with mnemonic persistence.
620
+ * Loads mnemonic from config, and saves it back after first initialization.
621
+ */
622
+ async function createLendaSwap() {
623
+ const wallet = await createWallet();
624
+ const { skill } = await getSDK();
625
+ const { LendaSwapSkill } = skill;
626
+
627
+ const config = loadConfig();
628
+ const options = {};
629
+
630
+ if (config.lendaswapMnemonic) {
631
+ options.mnemonic = config.lendaswapMnemonic;
632
+ }
633
+ if (process.env.LENDASWAP_API_KEY) {
634
+ options.apiKey = process.env.LENDASWAP_API_KEY;
635
+ }
636
+ if (process.env.LENDASWAP_API_URL) {
637
+ options.apiUrl = process.env.LENDASWAP_API_URL;
638
+ }
639
+
640
+ const lendaswap = new LendaSwapSkill({ wallet, ...options });
641
+
642
+ // Persist mnemonic after first SDK client initialization
643
+ if (!config.lendaswapMnemonic) {
644
+ try {
645
+ const mnemonic = await lendaswap.getMnemonic();
646
+ config.lendaswapMnemonic = mnemonic;
647
+ saveConfig(config);
648
+ } catch {
649
+ // Non-fatal: mnemonic save failed, will generate a new one next time
650
+ }
651
+ }
652
+
653
+ return lendaswap;
654
+ }
655
+
616
656
  /**
617
657
  * Get stablecoin quote command.
618
658
  */
@@ -624,11 +664,7 @@ async function cmdSwapQuote(amount, from, to) {
624
664
  process.exit(1);
625
665
  }
626
666
 
627
- const wallet = await createWallet();
628
- const { skill } = await getSDK();
629
- const { LendaSwapSkill } = skill;
630
-
631
- const lendaswap = new LendaSwapSkill({ wallet });
667
+ const lendaswap = await createLendaSwap();
632
668
 
633
669
  try {
634
670
  let quote;
@@ -680,26 +716,13 @@ async function cmdSwapToStable(
680
716
  process.exit(1);
681
717
  }
682
718
 
683
- const apiKey = process.env.LENDASWAP_API_KEY;
684
- if (!apiKey) {
685
- console.error("Error: LENDASWAP_API_KEY environment variable required.");
686
- process.exit(1);
687
- }
688
-
689
719
  const sats = parseInt(amount, 10);
690
720
  if (isNaN(sats) || sats <= 0) {
691
721
  console.error("Error: Invalid amount.");
692
722
  process.exit(1);
693
723
  }
694
724
 
695
- const wallet = await createWallet();
696
- const { skill } = await getSDK();
697
- const { LendaSwapSkill } = skill;
698
-
699
- const lendaswap = new LendaSwapSkill({
700
- wallet,
701
- apiKey,
702
- });
725
+ const lendaswap = await createLendaSwap();
703
726
 
704
727
  console.log(`Swapping ${formatSats(sats)} sats to ${targetToken}...`);
705
728
 
@@ -715,10 +738,10 @@ async function cmdSwapToStable(
715
738
  console.log(`Swap ID: ${result.swapId}`);
716
739
  console.log(`Status: ${result.status}`);
717
740
  console.log(`Expected: ${result.targetAmount} ${targetToken}`);
718
- console.log(`Rate: ${result.exchangeRate}`);
719
741
  if (result.paymentDetails?.address) {
720
742
  console.log(`Payment Address: ${result.paymentDetails.address}`);
721
743
  }
744
+ console.log(`Fee: ${result.fee.amount} sats`);
722
745
  console.log(`Expires: ${result.expiresAt.toLocaleString()}`);
723
746
  } catch (e) {
724
747
  console.error(`Error: ${e.message}`);
@@ -739,27 +762,14 @@ async function cmdSwapToBtc(amount, sourceToken, sourceChain, evmAddress) {
739
762
  process.exit(1);
740
763
  }
741
764
 
742
- const apiKey = process.env.LENDASWAP_API_KEY;
743
- if (!apiKey) {
744
- console.error("Error: LENDASWAP_API_KEY environment variable required.");
745
- process.exit(1);
746
- }
747
-
748
765
  const tokenAmount = parseFloat(amount);
749
766
  if (isNaN(tokenAmount) || tokenAmount <= 0) {
750
767
  console.error("Error: Invalid amount.");
751
768
  process.exit(1);
752
769
  }
753
770
 
754
- const wallet = await createWallet();
755
- const { skill } = await getSDK();
756
- const { LendaSwapSkill } = skill;
757
-
758
- const lendaswap = new LendaSwapSkill({
759
- wallet,
760
- apiKey,
761
- });
762
-
771
+ const lendaswap = await createLendaSwap();
772
+ const wallet = lendaswap.getWallet();
763
773
  const arkAddress = await wallet.getAddress();
764
774
 
765
775
  console.log(`Swapping ${tokenAmount} ${sourceToken} to BTC...`);
@@ -777,13 +787,13 @@ async function cmdSwapToBtc(amount, sourceToken, sourceChain, evmAddress) {
777
787
  console.log(`Swap ID: ${result.swapId}`);
778
788
  console.log(`Status: ${result.status}`);
779
789
  console.log(`Expected: ${result.targetAmount} sats`);
780
- console.log(`Rate: ${result.exchangeRate}`);
781
790
  if (result.paymentDetails?.address) {
782
791
  console.log(`HTLC Address: ${result.paymentDetails.address}`);
783
792
  }
784
793
  if (result.paymentDetails?.callData) {
785
- console.log(`Call Data: ${result.paymentDetails.callData}`);
794
+ console.log(`Token Address: ${result.paymentDetails.callData}`);
786
795
  }
796
+ console.log(`Fee: ${result.fee.amount} sats`);
787
797
  console.log(`Expires: ${result.expiresAt.toLocaleString()}`);
788
798
  } catch (e) {
789
799
  console.error(`Error: ${e.message}`);
@@ -801,11 +811,7 @@ async function cmdSwapStatus(swapId) {
801
811
  process.exit(1);
802
812
  }
803
813
 
804
- const wallet = await createWallet();
805
- const { skill } = await getSDK();
806
- const { LendaSwapSkill } = skill;
807
-
808
- const lendaswap = new LendaSwapSkill({ wallet });
814
+ const lendaswap = await createLendaSwap();
809
815
 
810
816
  try {
811
817
  const status = await lendaswap.getSwapStatus(swapId);
@@ -817,7 +823,6 @@ async function cmdSwapStatus(swapId) {
817
823
  console.log(`Status: ${status.status}`);
818
824
  console.log(`From: ${status.sourceAmount} ${status.sourceToken}`);
819
825
  console.log(`To: ${status.targetAmount} ${status.targetToken}`);
820
- console.log(`Rate: ${status.exchangeRate}`);
821
826
  console.log(`Created: ${status.createdAt.toLocaleString()}`);
822
827
  if (status.completedAt) {
823
828
  console.log(`Completed: ${status.completedAt.toLocaleString()}`);
@@ -835,11 +840,7 @@ async function cmdSwapStatus(swapId) {
835
840
  * Show pending stablecoin swaps command.
836
841
  */
837
842
  async function cmdSwapPending() {
838
- const wallet = await createWallet();
839
- const { skill } = await getSDK();
840
- const { LendaSwapSkill } = skill;
841
-
842
- const lendaswap = new LendaSwapSkill({ wallet });
843
+ const lendaswap = await createLendaSwap();
843
844
 
844
845
  try {
845
846
  const pending = await lendaswap.getPendingSwaps();
@@ -869,11 +870,7 @@ async function cmdSwapPending() {
869
870
  * Show available stablecoin pairs command.
870
871
  */
871
872
  async function cmdSwapPairs() {
872
- const wallet = await createWallet();
873
- const { skill } = await getSDK();
874
- const { LendaSwapSkill } = skill;
875
-
876
- const lendaswap = new LendaSwapSkill({ wallet });
873
+ const lendaswap = await createLendaSwap();
877
874
 
878
875
  try {
879
876
  const pairs = await lendaswap.getAvailablePairs();
@@ -893,6 +890,71 @@ async function cmdSwapPairs() {
893
890
  }
894
891
  }
895
892
 
893
+ /**
894
+ * Claim a swap command.
895
+ */
896
+ async function cmdSwapClaim(swapId) {
897
+ if (!swapId) {
898
+ console.error("Error: Swap ID required.");
899
+ console.error("Usage: arkade swap-claim <swap-id>");
900
+ process.exit(1);
901
+ }
902
+
903
+ const lendaswap = await createLendaSwap();
904
+
905
+ try {
906
+ const result = await lendaswap.claimSwap(swapId);
907
+
908
+ if (result.success) {
909
+ console.log("Swap claimed successfully!");
910
+ if (result.chain) {
911
+ console.log(`Chain: ${result.chain}`);
912
+ }
913
+ if (result.txHash) {
914
+ console.log(`TX Hash: ${result.txHash}`);
915
+ }
916
+ } else {
917
+ console.log(`Claim status: ${result.message}`);
918
+ }
919
+ } catch (e) {
920
+ console.error(`Error: ${e.message}`);
921
+ process.exit(1);
922
+ }
923
+ }
924
+
925
+ /**
926
+ * Refund a swap command.
927
+ */
928
+ async function cmdSwapRefund(swapId, destinationAddress) {
929
+ if (!swapId) {
930
+ console.error("Error: Swap ID required.");
931
+ console.error("Usage: arkade swap-refund <swap-id> [destination-address]");
932
+ process.exit(1);
933
+ }
934
+
935
+ const lendaswap = await createLendaSwap();
936
+
937
+ try {
938
+ const options = destinationAddress ? { destinationAddress } : undefined;
939
+ const result = await lendaswap.refundSwap(swapId, options);
940
+
941
+ if (result.success) {
942
+ console.log("Swap refunded successfully!");
943
+ if (result.txId) {
944
+ console.log(`TX ID: ${result.txId}`);
945
+ }
946
+ if (result.refundAmount != null) {
947
+ console.log(`Refund Amount: ${formatSats(result.refundAmount)} sats`);
948
+ }
949
+ } else {
950
+ console.log(`Refund status: ${result.message}`);
951
+ }
952
+ } catch (e) {
953
+ console.error(`Error: ${e.message}`);
954
+ process.exit(1);
955
+ }
956
+ }
957
+
896
958
  /**
897
959
  * Main entry point.
898
960
  */
@@ -949,6 +1011,12 @@ async function main() {
949
1011
  case "swap-to-btc":
950
1012
  await cmdSwapToBtc(args[1], args[2], args[3], args[4]);
951
1013
  break;
1014
+ case "swap-claim":
1015
+ await cmdSwapClaim(args[1]);
1016
+ break;
1017
+ case "swap-refund":
1018
+ await cmdSwapRefund(args[1], args[2]);
1019
+ break;
952
1020
  case "swap-status":
953
1021
  await cmdSwapStatus(args[1]);
954
1022
  break;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/skills/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;;;AAqCH,gBAAgB;AAChB,iDAA+E;AAAtE,mHAAA,kBAAkB,OAAA;AAAE,yHAAA,wBAAwB,OAAA;AAErD,kBAAkB;AAClB,yCAIqB;AAHnB,+GAAA,kBAAkB,OAAA;AAClB,iHAAA,oBAAoB,OAAA;AAItB,kBAAkB;AAClB,yCAIqB;AAHnB,2GAAA,cAAc,OAAA;AACd,iHAAA,oBAAoB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/skills/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;;;AAyCH,gBAAgB;AAChB,iDAA+E;AAAtE,mHAAA,kBAAkB,OAAA;AAAE,yHAAA,wBAAwB,OAAA;AAErD,kBAAkB;AAClB,yCAIqB;AAHnB,+GAAA,kBAAkB,OAAA;AAClB,iHAAA,oBAAoB,OAAA;AAItB,kBAAkB;AAClB,yCAIqB;AAHnB,2GAAA,cAAc,OAAA;AACd,iHAAA,oBAAoB,OAAA"}