timefi-sdk 0.1.4 → 0.2.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.
package/README.md CHANGED
@@ -10,7 +10,8 @@ The official JavaScript SDK for interacting with the **TimeFi Protocol** on the
10
10
 
11
11
  - Protocol Client: Easy-to-use `TimeFiClient` for read and write interactions.
12
12
  - On-chain Data: Fetch TVL, vault status, and lock durations directly from smart contracts.
13
- - Formatting Utilities: Standardized formatting for STX (microSTX to STX), addresses, and dates.
13
+ - Formatting Utilities: Standardized formatting for STX (microSTX to STX), addresses, dates, and timestamps.
14
+ - Shared Helpers: Utility helpers and protocol models from the old `timefi-utils` and `timefi-types` packages are now included directly in `timefi-sdk`.
14
15
  - Mainnet/Testnet Support: Unified interface for both networks.
15
16
 
16
17
  ## Installation
@@ -51,6 +52,20 @@ const shortAddress = formatAddress('SP3F1234567890ABCDEFG1234567890XYZ123');
51
52
  console.log(shortAddress);
52
53
  ```
53
54
 
55
+ ### Use Integrated Utilities and Protocol Helpers
56
+
57
+ ```javascript
58
+ import {
59
+ calculateTimeRemaining,
60
+ getProtocolConfig,
61
+ validateAddress,
62
+ } from 'timefi-sdk';
63
+
64
+ const config = getProtocolConfig();
65
+ const remaining = calculateTimeRemaining(Date.now() + 60_000);
66
+ const isValid = validateAddress('SP3FKNEZ86RG5RT7SZ5FBRGH85FZNG94ZH1MCGG6N');
67
+ ```
68
+
54
69
  ## Running Tests
55
70
 
56
71
  ```bash
@@ -64,6 +79,20 @@ The SDK exports:
64
79
  - `TimeFiClient`
65
80
  - `formatSTX(microStx)`
66
81
  - `formatAddress(address)`
82
+ - `formatTimestamp(timestamp)`
83
+ - `calculateTimeRemaining(endTime)`
84
+ - `validateAddress(address)`
85
+ - `validateAddressResult(address)`
86
+ - `formatAmount(amount, decimals?)`
87
+ - `parseAmount(amount)`
88
+ - `generateId()`
89
+ - `sleep(ms)`
90
+ - `retry(fn, maxRetries?, delay?)`
91
+ - `initializeProtocol(options?)`
92
+ - `getProtocolVersion()`
93
+ - `getProtocolConfig()`
94
+ - `normalizeVault(vault)`
95
+ - `normalizeTransaction(transaction)`
67
96
  - `formatNumber(value)`
68
97
  - `formatPercent(value)`
69
98
  - `formatDate(value)`
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n=require("@stacks/transactions"),c=require("@stacks/network"),u="SP3FKNEZ86RG5RT7SZ5FBRGH85FZNG94ZH1MCGG6N",s={VAULT:"timefi-vault-v-A2",REWARDS:"timefi-rewards-v-A2",GOVERNANCE:"timefi-governance-v-A2",EMERGENCY:"timefi-emergency-v-A2"},f={MONTH_1:{label:"1 Month",blocks:4320,apy:1},MONTH_3:{label:"3 Months",blocks:12960,apy:3},MONTH_6:{label:"6 Months",blocks:25920,apy:6},MONTH_9:{label:"9 Months",blocks:38880,apy:9},YEAR_1:{label:"1 Year",blocks:52560,apy:12}},d=.01,m=1e6,g=t=>{if(t==null)return"0.000000";try{const e=typeof t=="object"&&t!==null&&"value"in t?t.value:t,r=Number(e);return isNaN(r)?"0.000000":(r/1e6).toLocaleString(void 0,{minimumFractionDigits:0,maximumFractionDigits:6})}catch(e){return console.error("Error formatting STX:",e),"0.000000"}},h=(t,e=4,r=4)=>t?t.length<=e+r?t:`${t.slice(0,e+2)}...${t.slice(-r)}`:"",b=t=>{if(t==null)return"0";const e=Number(t);return isNaN(e)?"0":e.toLocaleString()},C=(t,e=2)=>{if(t==null)return"0%";const r=Number(t);return isNaN(r)?"0%":(r*100).toFixed(e)+"%"},l=t=>{if(!t)return"--";const e=new Date(t);return isNaN(e.getTime())?"--":e.toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"})},A=t=>{if(!t)return"--";const e=new Date,r=new Date(t),o=Math.floor((e-r)/1e3);if(o<-1){const i=Math.abs(o);return i<60?"in a few seconds":i<3600?`in ${Math.floor(i/60)}m`:i<86400?`in ${Math.floor(i/3600)}h`:`in ${Math.floor(i/86400)}d`}return o<5?"just now":o<60?`${o}s ago`:o<3600?`${Math.floor(o/60)}m ago`:o<86400?`${Math.floor(o/3600)}h ago`:o<604800?`${Math.floor(o/86400)}d ago`:l(t)};function a(t,e){if(!Number.isInteger(t)||t<=0)throw new Error(`${e} must be a positive integer.`)}function w(t){if(t==null)throw new Error("amountSTX is required");const e=String(t).trim();if(!/^\d+(\.\d+)?$/.test(e))throw new Error("amountSTX must be a valid positive number.");const[r,o=""]=e.split(".");if(o.length>6)throw new Error("amountSTX supports at most 6 decimal places.");const i=BigInt(r)*1000000n+BigInt((o+"000000").slice(0,6));if(i<=0n)throw new Error("amountSTX must be greater than 0.");return i}class M{constructor(e="mainnet"){if(!["mainnet","testnet"].includes(e))throw new Error(`Invalid networkType "${e}". Use "mainnet" or "testnet".`);this.networkType=e,this.network=e==="mainnet"?new c.StacksMainnet:new c.StacksTestnet,this.contractAddress=u}async callReadOnly(e,r=[],o){const i=await n.callReadOnlyFunction({contractAddress:this.contractAddress,contractName:s.VAULT,functionName:e,functionArgs:r,network:this.network,senderAddress:o||this.contractAddress});return i.type===7||i.type===8?n.cvToValue(i.value):n.cvToValue(i)}async getVault(e){return a(e,"vaultId"),this.callReadOnly("get-vault",[n.uintCV(e)])}async getTimeRemaining(e){return a(e,"vaultId"),this.callReadOnly("get-time-remaining",[n.uintCV(e)])}async canWithdraw(e){return a(e,"vaultId"),this.callReadOnly("can-withdraw",[n.uintCV(e)])}async getTVL(){return this.callReadOnly("get-tvl",[])}getCreateVaultOptions(e,r){return a(r,"lockDurationBlocks"),{contractAddress:this.contractAddress,contractName:s.VAULT,functionName:"create-vault",functionArgs:[n.uintCV(w(e)),n.uintCV(r)],network:this.network,anchorMode:n.AnchorMode.Any,postConditionMode:n.PostConditionMode.Allow}}getWithdrawOptions(e){return a(e,"vaultId"),{contractAddress:this.contractAddress,contractName:s.VAULT,functionName:"request-withdraw",functionArgs:[n.uintCV(e)],network:this.network,anchorMode:n.AnchorMode.Any,postConditionMode:n.PostConditionMode.Allow}}}Object.defineProperty(exports,"AnchorMode",{enumerable:!0,get:()=>n.AnchorMode});Object.defineProperty(exports,"PostConditionMode",{enumerable:!0,get:()=>n.PostConditionMode});Object.defineProperty(exports,"bufferCV",{enumerable:!0,get:()=>n.bufferCV});Object.defineProperty(exports,"noneCV",{enumerable:!0,get:()=>n.noneCV});Object.defineProperty(exports,"principalCV",{enumerable:!0,get:()=>n.principalCV});Object.defineProperty(exports,"responseErrorCV",{enumerable:!0,get:()=>n.responseErrorCV});Object.defineProperty(exports,"responseOkCV",{enumerable:!0,get:()=>n.responseOkCV});Object.defineProperty(exports,"someCV",{enumerable:!0,get:()=>n.someCV});Object.defineProperty(exports,"stringAsciiCV",{enumerable:!0,get:()=>n.stringAsciiCV});Object.defineProperty(exports,"stringUtf8CV",{enumerable:!0,get:()=>n.stringUtf8CV});Object.defineProperty(exports,"uintCV",{enumerable:!0,get:()=>n.uintCV});exports.CONTRACT_ADDRESS=u;exports.CONTRACT_NAMES=s;exports.LOCK_PERIODS=f;exports.MAX_DEPOSIT=m;exports.MIN_DEPOSIT=d;exports.TimeFiClient=M;exports.formatAddress=h;exports.formatDate=l;exports.formatNumber=b;exports.formatPercent=C;exports.formatRelativeTime=A;exports.formatSTX=g;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("@stacks/transactions"),f=require("@stacks/network"),d="SP3FKNEZ86RG5RT7SZ5FBRGH85FZNG94ZH1MCGG6N",u={VAULT:"timefi-vault-v-A2",REWARDS:"timefi-rewards-v-A2",GOVERNANCE:"timefi-governance-v-A2",EMERGENCY:"timefi-emergency-v-A2"},p={MONTH_1:{label:"1 Month",blocks:4320,apy:1},MONTH_3:{label:"3 Months",blocks:12960,apy:3},MONTH_6:{label:"6 Months",blocks:25920,apy:6},MONTH_9:{label:"9 Months",blocks:38880,apy:9},YEAR_1:{label:"1 Year",blocks:52560,apy:12}},y=.01,M=1e6,V=e=>{if(e==null)return"0.000000";try{const t=typeof e=="object"&&e!==null&&"value"in e?e.value:e,r=Number(t);return isNaN(r)?"0.000000":(r/1e6).toLocaleString(void 0,{minimumFractionDigits:0,maximumFractionDigits:6})}catch(t){return console.error("Error formatting STX:",t),"0.000000"}},E=(e,t=4,r=4)=>e?e.length<=t+r?e:`${e.slice(0,t+2)}...${e.slice(-r)}`:"",P=e=>{if(e==null)return"0";const t=Number(e);return isNaN(t)?"0":t.toLocaleString()},R=(e,t=2)=>{if(e==null)return"0%";const r=Number(e);return isNaN(r)?"0%":(r*100).toFixed(t)+"%"},m=e=>{if(!e)return"--";const t=new Date(e);return isNaN(t.getTime())?"--":t.toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"})},_=e=>{if(!e)return"--";const t=new Date,r=new Date(e),n=Math.floor((t-r)/1e3);if(n<-1){const i=Math.abs(n);return i<60?"in a few seconds":i<3600?`in ${Math.floor(i/60)}m`:i<86400?`in ${Math.floor(i/3600)}h`:`in ${Math.floor(i/86400)}d`}return n<5?"just now":n<60?`${n}s ago`:n<3600?`${Math.floor(n/60)}m ago`:n<86400?`${Math.floor(n/3600)}h ago`:n<604800?`${Math.floor(n/86400)}d ago`:m(e)},D=/^S[PTMN][A-Z0-9]{38,40}$/i;function v(e){const t=Number(e);return!Number.isInteger(t)||t<0?6:t}function k(e){const t=e instanceof Date?e:new Date(e);return Number.isNaN(t.getTime())?"Invalid Date":t.toLocaleString()}function I(e){const t=e instanceof Date?e.getTime():Number(e),r=Number.isFinite(t)?t-Date.now():0;if(r<=0)return{days:0,hours:0,minutes:0,seconds:0,total:0};const n=Math.floor(r/(1e3*60*60*24)),i=Math.floor(r%(1e3*60*60*24)/(1e3*60*60)),l=Math.floor(r%(1e3*60*60)/(1e3*60)),C=Math.floor(r%(1e3*60)/1e3);return{days:n,hours:i,minutes:l,seconds:C,total:r}}function g(e){if(typeof e!="string")return{valid:!1,error:"Address must be a string."};const t=e.trim().toUpperCase();return t?D.test(t)?{valid:!0,address:t}:{valid:!1,address:t,error:"Address must be a valid Stacks address."}:{valid:!1,error:"Address is required."}}function F(e){return g(e).valid}function L(e,t=6){const r=Number(e),n=v(t);return Number.isFinite(r)?r.toFixed(n):0 .toFixed(n)}function j(e){const t=Number.parseFloat(String(e).replace(/,/g,"").trim());return Number.isFinite(t)?t:0}function U(){return`${Date.now()}-${Math.random().toString(36).slice(2,11)}`}function T(e){const t=Number.isFinite(e)&&e>0?e:0;return new Promise(r=>setTimeout(r,t))}async function z(e,t=3,r=1e3){const n=Number.isInteger(t)&&t>0?t:1;for(let i=0;i<n;i+=1)try{return await e()}catch(l){if(i===n-1)throw l;await T(r)}throw new Error("Retry exhausted without executing the operation.")}const A="1.0.0",h=Object.freeze({timeLock:!0,vaults:!0,governance:!1,rewards:!1}),b=Object.freeze(["active","locked","withdrawn","failed"]),N=Object.freeze(["deposit","withdraw","create","fee"]),S=Object.freeze(["pending","confirmed","failed"]);function s(e,t=0){const r=Number(e);return Number.isFinite(r)?r:t}function $(e){return b.includes(e)?e:"active"}function G(e){return N.includes(e)?e:"deposit"}function X(e){return S.includes(e)?e:"pending"}function O(e={}){const t={...h,...e.features||{}};return{network:e.network||"mainnet",version:e.version||A,features:t,initialized:e.initialized??!0}}let c=O();function H(e={}){return c=O(e),w()}function q(){return c.version}function w(){return{...c,features:{...c.features}}}function Y(e={}){return{id:e.id?String(e.id):"",owner:e.owner?String(e.owner):"",amount:s(e.amount),lockTime:s(e.lockTime),unlockTime:s(e.unlockTime),status:$(e.status),fees:s(e.fees)}}function Z(e={}){return{hash:e.hash?String(e.hash):"",type:G(e.type),amount:s(e.amount),from:e.from?String(e.from):"",to:e.to?String(e.to):"",timestamp:s(e.timestamp),status:X(e.status)}}function a(e,t){if(!Number.isInteger(e)||e<=0)throw new Error(`${t} must be a positive integer.`)}function K(e){if(e==null)throw new Error("amountSTX is required");const t=String(e).trim();if(!/^\d+(\.\d+)?$/.test(t))throw new Error("amountSTX must be a valid positive number.");const[r,n=""]=t.split(".");if(n.length>6)throw new Error("amountSTX supports at most 6 decimal places.");const i=BigInt(r)*1000000n+BigInt((n+"000000").slice(0,6));if(i<=0n)throw new Error("amountSTX must be greater than 0.");return i}class B{constructor(t="mainnet"){if(!["mainnet","testnet"].includes(t))throw new Error(`Invalid networkType "${t}". Use "mainnet" or "testnet".`);this.networkType=t,this.network=t==="mainnet"?new f.StacksMainnet:new f.StacksTestnet,this.contractAddress=d}async callReadOnly(t,r=[],n){const i=await o.callReadOnlyFunction({contractAddress:this.contractAddress,contractName:u.VAULT,functionName:t,functionArgs:r,network:this.network,senderAddress:n||this.contractAddress});return i.type===7||i.type===8?o.cvToValue(i.value):o.cvToValue(i)}async getVault(t){return a(t,"vaultId"),this.callReadOnly("get-vault",[o.uintCV(t)])}async getTimeRemaining(t){return a(t,"vaultId"),this.callReadOnly("get-time-remaining",[o.uintCV(t)])}async canWithdraw(t){return a(t,"vaultId"),this.callReadOnly("can-withdraw",[o.uintCV(t)])}async getTVL(){return this.callReadOnly("get-tvl",[])}getCreateVaultOptions(t,r){return a(r,"lockDurationBlocks"),{contractAddress:this.contractAddress,contractName:u.VAULT,functionName:"create-vault",functionArgs:[o.uintCV(K(t)),o.uintCV(r)],network:this.network,anchorMode:o.AnchorMode.Any,postConditionMode:o.PostConditionMode.Allow}}getWithdrawOptions(t){return a(t,"vaultId"),{contractAddress:this.contractAddress,contractName:u.VAULT,functionName:"request-withdraw",functionArgs:[o.uintCV(t)],network:this.network,anchorMode:o.AnchorMode.Any,postConditionMode:o.PostConditionMode.Allow}}}Object.defineProperty(exports,"AnchorMode",{enumerable:!0,get:()=>o.AnchorMode});Object.defineProperty(exports,"PostConditionMode",{enumerable:!0,get:()=>o.PostConditionMode});Object.defineProperty(exports,"bufferCV",{enumerable:!0,get:()=>o.bufferCV});Object.defineProperty(exports,"noneCV",{enumerable:!0,get:()=>o.noneCV});Object.defineProperty(exports,"principalCV",{enumerable:!0,get:()=>o.principalCV});Object.defineProperty(exports,"responseErrorCV",{enumerable:!0,get:()=>o.responseErrorCV});Object.defineProperty(exports,"responseOkCV",{enumerable:!0,get:()=>o.responseOkCV});Object.defineProperty(exports,"someCV",{enumerable:!0,get:()=>o.someCV});Object.defineProperty(exports,"stringAsciiCV",{enumerable:!0,get:()=>o.stringAsciiCV});Object.defineProperty(exports,"stringUtf8CV",{enumerable:!0,get:()=>o.stringUtf8CV});Object.defineProperty(exports,"uintCV",{enumerable:!0,get:()=>o.uintCV});exports.CONTRACT_ADDRESS=d;exports.CONTRACT_NAMES=u;exports.DEFAULT_PROTOCOL_FEATURES=h;exports.LOCK_PERIODS=p;exports.MAX_DEPOSIT=M;exports.MIN_DEPOSIT=y;exports.PROTOCOL_VERSION=A;exports.TRANSACTION_STATUSES=S;exports.TRANSACTION_TYPES=N;exports.TimeFiClient=B;exports.VAULT_STATUSES=b;exports.calculateTimeRemaining=I;exports.formatAddress=E;exports.formatAmount=L;exports.formatDate=m;exports.formatNumber=P;exports.formatPercent=R;exports.formatRelativeTime=_;exports.formatSTX=V;exports.formatTimestamp=k;exports.generateId=U;exports.getProtocolConfig=w;exports.getProtocolVersion=q;exports.initializeProtocol=H;exports.normalizeTransaction=Z;exports.normalizeVault=Y;exports.parseAmount=j;exports.retry=z;exports.sleep=T;exports.validateAddress=F;exports.validateAddressResult=g;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export * from "./constants.js";
2
2
  export * from "./format.js";
3
+ export * from "./utils.js";
4
+ export * from "./protocol.js";
3
5
  export * from "./client.js";
4
6
  export { uintCV, principalCV, bufferCV, stringAsciiCV, stringUtf8CV, noneCV, someCV, responseOkCV, responseErrorCV, AnchorMode, PostConditionMode } from "@stacks/transactions";
package/dist/index.mjs CHANGED
@@ -1,147 +1,283 @@
1
- import { callReadOnlyFunction as f, cvToValue as c, uintCV as i, PostConditionMode as u, AnchorMode as l } from "@stacks/transactions";
2
- import { AnchorMode as S, PostConditionMode as k, bufferCV as D, noneCV as _, principalCV as $, responseErrorCV as I, responseOkCV as L, someCV as F, stringAsciiCV as P, stringUtf8CV as G, uintCV as H } from "@stacks/transactions";
3
- import { StacksMainnet as d, StacksTestnet as m } from "@stacks/network";
4
- const h = "SP3FKNEZ86RG5RT7SZ5FBRGH85FZNG94ZH1MCGG6N", a = {
1
+ import { callReadOnlyFunction as w, cvToValue as f, uintCV as i, PostConditionMode as d, AnchorMode as m } from "@stacks/transactions";
2
+ import { AnchorMode as it, PostConditionMode as st, bufferCV as at, noneCV as ut, principalCV as ct, responseErrorCV as lt, responseOkCV as ft, someCV as dt, stringAsciiCV as mt, stringUtf8CV as ht, uintCV as gt } from "@stacks/transactions";
3
+ import { StacksMainnet as A, StacksTestnet as N } from "@stacks/network";
4
+ const T = "SP3FKNEZ86RG5RT7SZ5FBRGH85FZNG94ZH1MCGG6N", l = {
5
5
  VAULT: "timefi-vault-v-A2",
6
6
  REWARDS: "timefi-rewards-v-A2",
7
7
  GOVERNANCE: "timefi-governance-v-A2",
8
8
  EMERGENCY: "timefi-emergency-v-A2"
9
- }, M = {
9
+ }, L = {
10
10
  MONTH_1: { label: "1 Month", blocks: 4320, apy: 1 },
11
11
  MONTH_3: { label: "3 Months", blocks: 12960, apy: 3 },
12
12
  MONTH_6: { label: "6 Months", blocks: 25920, apy: 6 },
13
13
  MONTH_9: { label: "9 Months", blocks: 38880, apy: 9 },
14
14
  YEAR_1: { label: "1 Year", blocks: 52560, apy: 12 }
15
- }, p = 0.01, T = 1e6, y = (n) => {
16
- if (n == null) return "0.000000";
15
+ }, $ = 0.01, z = 1e6, U = (t) => {
16
+ if (t == null) return "0.000000";
17
17
  try {
18
- const t = typeof n == "object" && n !== null && "value" in n ? n.value : n, e = Number(t);
19
- return isNaN(e) ? "0.000000" : (e / 1e6).toLocaleString(void 0, {
18
+ const e = typeof t == "object" && t !== null && "value" in t ? t.value : t, n = Number(e);
19
+ return isNaN(n) ? "0.000000" : (n / 1e6).toLocaleString(void 0, {
20
20
  minimumFractionDigits: 0,
21
21
  maximumFractionDigits: 6
22
22
  });
23
- } catch (t) {
24
- return console.error("Error formatting STX:", t), "0.000000";
23
+ } catch (e) {
24
+ return console.error("Error formatting STX:", e), "0.000000";
25
25
  }
26
- }, C = (n, t = 4, e = 4) => n ? n.length <= t + e ? n : `${n.slice(0, t + 2)}...${n.slice(-e)}` : "", b = (n) => {
27
- if (n == null) return "0";
28
- const t = Number(n);
29
- return isNaN(t) ? "0" : t.toLocaleString();
30
- }, E = (n, t = 2) => {
31
- if (n == null) return "0%";
32
- const e = Number(n);
33
- return isNaN(e) ? "0%" : (e * 100).toFixed(t) + "%";
34
- }, w = (n) => {
35
- if (!n) return "--";
36
- const t = new Date(n);
37
- return isNaN(t.getTime()) ? "--" : t.toLocaleDateString(void 0, {
26
+ }, G = (t, e = 4, n = 4) => t ? t.length <= e + n ? t : `${t.slice(0, e + 2)}...${t.slice(-n)}` : "", j = (t) => {
27
+ if (t == null) return "0";
28
+ const e = Number(t);
29
+ return isNaN(e) ? "0" : e.toLocaleString();
30
+ }, H = (t, e = 2) => {
31
+ if (t == null) return "0%";
32
+ const n = Number(t);
33
+ return isNaN(n) ? "0%" : (n * 100).toFixed(e) + "%";
34
+ }, b = (t) => {
35
+ if (!t) return "--";
36
+ const e = new Date(t);
37
+ return isNaN(e.getTime()) ? "--" : e.toLocaleDateString(void 0, {
38
38
  year: "numeric",
39
39
  month: "short",
40
40
  day: "numeric"
41
41
  });
42
- }, O = (n) => {
43
- if (!n) return "--";
44
- const t = /* @__PURE__ */ new Date(), e = new Date(n), r = Math.floor((t - e) / 1e3);
42
+ }, X = (t) => {
43
+ if (!t) return "--";
44
+ const e = /* @__PURE__ */ new Date(), n = new Date(t), r = Math.floor((e - n) / 1e3);
45
45
  if (r < -1) {
46
46
  const o = Math.abs(r);
47
47
  return o < 60 ? "in a few seconds" : o < 3600 ? `in ${Math.floor(o / 60)}m` : o < 86400 ? `in ${Math.floor(o / 3600)}h` : `in ${Math.floor(o / 86400)}d`;
48
48
  }
49
- return r < 5 ? "just now" : r < 60 ? `${r}s ago` : r < 3600 ? `${Math.floor(r / 60)}m ago` : r < 86400 ? `${Math.floor(r / 3600)}h ago` : r < 604800 ? `${Math.floor(r / 86400)}d ago` : w(n);
50
- };
51
- function s(n, t) {
52
- if (!Number.isInteger(n) || n <= 0)
53
- throw new Error(`${t} must be a positive integer.`);
49
+ return r < 5 ? "just now" : r < 60 ? `${r}s ago` : r < 3600 ? `${Math.floor(r / 60)}m ago` : r < 86400 ? `${Math.floor(r / 3600)}h ago` : r < 604800 ? `${Math.floor(r / 86400)}d ago` : b(t);
50
+ }, S = /^S[PTMN][A-Z0-9]{38,40}$/i;
51
+ function p(t) {
52
+ const e = Number(t);
53
+ return !Number.isInteger(e) || e < 0 ? 6 : e;
54
+ }
55
+ function Z(t) {
56
+ const e = t instanceof Date ? t : new Date(t);
57
+ return Number.isNaN(e.getTime()) ? "Invalid Date" : e.toLocaleString();
58
+ }
59
+ function Y(t) {
60
+ const e = t instanceof Date ? t.getTime() : Number(t), n = Number.isFinite(e) ? e - Date.now() : 0;
61
+ if (n <= 0)
62
+ return { days: 0, hours: 0, minutes: 0, seconds: 0, total: 0 };
63
+ const r = Math.floor(n / (1e3 * 60 * 60 * 24)), o = Math.floor(n % (1e3 * 60 * 60 * 24) / (1e3 * 60 * 60)), c = Math.floor(n % (1e3 * 60 * 60) / (1e3 * 60)), g = Math.floor(n % (1e3 * 60) / 1e3);
64
+ return { days: r, hours: o, minutes: c, seconds: g, total: n };
65
+ }
66
+ function M(t) {
67
+ if (typeof t != "string")
68
+ return { valid: !1, error: "Address must be a string." };
69
+ const e = t.trim().toUpperCase();
70
+ return e ? S.test(e) ? { valid: !0, address: e } : { valid: !1, address: e, error: "Address must be a valid Stacks address." } : { valid: !1, error: "Address is required." };
71
+ }
72
+ function q(t) {
73
+ return M(t).valid;
74
+ }
75
+ function B(t, e = 6) {
76
+ const n = Number(t), r = p(e);
77
+ return Number.isFinite(n) ? n.toFixed(r) : 0 .toFixed(r);
78
+ }
79
+ function K(t) {
80
+ const e = Number.parseFloat(String(t).replace(/,/g, "").trim());
81
+ return Number.isFinite(e) ? e : 0;
82
+ }
83
+ function W() {
84
+ return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
85
+ }
86
+ function y(t) {
87
+ const e = Number.isFinite(t) && t > 0 ? t : 0;
88
+ return new Promise((n) => setTimeout(n, e));
89
+ }
90
+ async function x(t, e = 3, n = 1e3) {
91
+ const r = Number.isInteger(e) && e > 0 ? e : 1;
92
+ for (let o = 0; o < r; o += 1)
93
+ try {
94
+ return await t();
95
+ } catch (c) {
96
+ if (o === r - 1)
97
+ throw c;
98
+ await y(n);
99
+ }
100
+ throw new Error("Retry exhausted without executing the operation.");
101
+ }
102
+ const C = "1.0.0", O = Object.freeze({
103
+ timeLock: !0,
104
+ vaults: !0,
105
+ governance: !1,
106
+ rewards: !1
107
+ }), E = Object.freeze(["active", "locked", "withdrawn", "failed"]), R = Object.freeze(["deposit", "withdraw", "create", "fee"]), V = Object.freeze(["pending", "confirmed", "failed"]);
108
+ function s(t, e = 0) {
109
+ const n = Number(t);
110
+ return Number.isFinite(n) ? n : e;
111
+ }
112
+ function D(t) {
113
+ return E.includes(t) ? t : "active";
114
+ }
115
+ function k(t) {
116
+ return R.includes(t) ? t : "deposit";
117
+ }
118
+ function v(t) {
119
+ return V.includes(t) ? t : "pending";
120
+ }
121
+ function h(t = {}) {
122
+ const e = {
123
+ ...O,
124
+ ...t.features || {}
125
+ };
126
+ return {
127
+ network: t.network || "mainnet",
128
+ version: t.version || C,
129
+ features: e,
130
+ initialized: t.initialized ?? !0
131
+ };
132
+ }
133
+ let u = h();
134
+ function J(t = {}) {
135
+ return u = h(t), _();
136
+ }
137
+ function Q() {
138
+ return u.version;
139
+ }
140
+ function _() {
141
+ return {
142
+ ...u,
143
+ features: { ...u.features }
144
+ };
145
+ }
146
+ function tt(t = {}) {
147
+ return {
148
+ id: t.id ? String(t.id) : "",
149
+ owner: t.owner ? String(t.owner) : "",
150
+ amount: s(t.amount),
151
+ lockTime: s(t.lockTime),
152
+ unlockTime: s(t.unlockTime),
153
+ status: D(t.status),
154
+ fees: s(t.fees)
155
+ };
156
+ }
157
+ function et(t = {}) {
158
+ return {
159
+ hash: t.hash ? String(t.hash) : "",
160
+ type: k(t.type),
161
+ amount: s(t.amount),
162
+ from: t.from ? String(t.from) : "",
163
+ to: t.to ? String(t.to) : "",
164
+ timestamp: s(t.timestamp),
165
+ status: v(t.status)
166
+ };
167
+ }
168
+ function a(t, e) {
169
+ if (!Number.isInteger(t) || t <= 0)
170
+ throw new Error(`${e} must be a positive integer.`);
54
171
  }
55
- function g(n) {
56
- if (n == null)
172
+ function F(t) {
173
+ if (t == null)
57
174
  throw new Error("amountSTX is required");
58
- const t = String(n).trim();
59
- if (!/^\d+(\.\d+)?$/.test(t))
175
+ const e = String(t).trim();
176
+ if (!/^\d+(\.\d+)?$/.test(e))
60
177
  throw new Error("amountSTX must be a valid positive number.");
61
- const [e, r = ""] = t.split(".");
178
+ const [n, r = ""] = e.split(".");
62
179
  if (r.length > 6)
63
180
  throw new Error("amountSTX supports at most 6 decimal places.");
64
- const o = BigInt(e) * 1000000n + BigInt((r + "000000").slice(0, 6));
181
+ const o = BigInt(n) * 1000000n + BigInt((r + "000000").slice(0, 6));
65
182
  if (o <= 0n)
66
183
  throw new Error("amountSTX must be greater than 0.");
67
184
  return o;
68
185
  }
69
- class R {
70
- constructor(t = "mainnet") {
71
- if (!["mainnet", "testnet"].includes(t))
72
- throw new Error(`Invalid networkType "${t}". Use "mainnet" or "testnet".`);
73
- this.networkType = t, this.network = t === "mainnet" ? new d() : new m(), this.contractAddress = h;
186
+ class nt {
187
+ constructor(e = "mainnet") {
188
+ if (!["mainnet", "testnet"].includes(e))
189
+ throw new Error(`Invalid networkType "${e}". Use "mainnet" or "testnet".`);
190
+ this.networkType = e, this.network = e === "mainnet" ? new A() : new N(), this.contractAddress = T;
74
191
  }
75
192
  // --- Read-only Methods ---
76
- async callReadOnly(t, e = [], r) {
77
- const o = await f({
193
+ async callReadOnly(e, n = [], r) {
194
+ const o = await w({
78
195
  contractAddress: this.contractAddress,
79
- contractName: a.VAULT,
80
- functionName: t,
81
- functionArgs: e,
196
+ contractName: l.VAULT,
197
+ functionName: e,
198
+ functionArgs: n,
82
199
  network: this.network,
83
200
  senderAddress: r || this.contractAddress
84
201
  });
85
- return o.type === 7 || o.type === 8 ? c(o.value) : c(o);
202
+ return o.type === 7 || o.type === 8 ? f(o.value) : f(o);
86
203
  }
87
- async getVault(t) {
88
- return s(t, "vaultId"), this.callReadOnly("get-vault", [i(t)]);
204
+ async getVault(e) {
205
+ return a(e, "vaultId"), this.callReadOnly("get-vault", [i(e)]);
89
206
  }
90
- async getTimeRemaining(t) {
91
- return s(t, "vaultId"), this.callReadOnly("get-time-remaining", [i(t)]);
207
+ async getTimeRemaining(e) {
208
+ return a(e, "vaultId"), this.callReadOnly("get-time-remaining", [i(e)]);
92
209
  }
93
- async canWithdraw(t) {
94
- return s(t, "vaultId"), this.callReadOnly("can-withdraw", [i(t)]);
210
+ async canWithdraw(e) {
211
+ return a(e, "vaultId"), this.callReadOnly("can-withdraw", [i(e)]);
95
212
  }
96
213
  async getTVL() {
97
214
  return this.callReadOnly("get-tvl", []);
98
215
  }
99
216
  // --- Transaction Signing Options Helpers ---
100
- getCreateVaultOptions(t, e) {
101
- return s(e, "lockDurationBlocks"), {
217
+ getCreateVaultOptions(e, n) {
218
+ return a(n, "lockDurationBlocks"), {
102
219
  contractAddress: this.contractAddress,
103
- contractName: a.VAULT,
220
+ contractName: l.VAULT,
104
221
  functionName: "create-vault",
105
- functionArgs: [i(g(t)), i(e)],
222
+ functionArgs: [i(F(e)), i(n)],
106
223
  network: this.network,
107
- anchorMode: l.Any,
108
- postConditionMode: u.Allow
224
+ anchorMode: m.Any,
225
+ postConditionMode: d.Allow
109
226
  };
110
227
  }
111
- getWithdrawOptions(t) {
112
- return s(t, "vaultId"), {
228
+ getWithdrawOptions(e) {
229
+ return a(e, "vaultId"), {
113
230
  contractAddress: this.contractAddress,
114
- contractName: a.VAULT,
231
+ contractName: l.VAULT,
115
232
  functionName: "request-withdraw",
116
- functionArgs: [i(t)],
233
+ functionArgs: [i(e)],
117
234
  network: this.network,
118
- anchorMode: l.Any,
119
- postConditionMode: u.Allow
235
+ anchorMode: m.Any,
236
+ postConditionMode: d.Allow
120
237
  };
121
238
  }
122
239
  }
123
240
  export {
124
- S as AnchorMode,
125
- h as CONTRACT_ADDRESS,
126
- a as CONTRACT_NAMES,
127
- M as LOCK_PERIODS,
128
- T as MAX_DEPOSIT,
129
- p as MIN_DEPOSIT,
130
- k as PostConditionMode,
131
- R as TimeFiClient,
132
- D as bufferCV,
133
- C as formatAddress,
134
- w as formatDate,
135
- b as formatNumber,
136
- E as formatPercent,
137
- O as formatRelativeTime,
138
- y as formatSTX,
139
- _ as noneCV,
140
- $ as principalCV,
141
- I as responseErrorCV,
142
- L as responseOkCV,
143
- F as someCV,
144
- P as stringAsciiCV,
145
- G as stringUtf8CV,
146
- H as uintCV
241
+ it as AnchorMode,
242
+ T as CONTRACT_ADDRESS,
243
+ l as CONTRACT_NAMES,
244
+ O as DEFAULT_PROTOCOL_FEATURES,
245
+ L as LOCK_PERIODS,
246
+ z as MAX_DEPOSIT,
247
+ $ as MIN_DEPOSIT,
248
+ C as PROTOCOL_VERSION,
249
+ st as PostConditionMode,
250
+ V as TRANSACTION_STATUSES,
251
+ R as TRANSACTION_TYPES,
252
+ nt as TimeFiClient,
253
+ E as VAULT_STATUSES,
254
+ at as bufferCV,
255
+ Y as calculateTimeRemaining,
256
+ G as formatAddress,
257
+ B as formatAmount,
258
+ b as formatDate,
259
+ j as formatNumber,
260
+ H as formatPercent,
261
+ X as formatRelativeTime,
262
+ U as formatSTX,
263
+ Z as formatTimestamp,
264
+ W as generateId,
265
+ _ as getProtocolConfig,
266
+ Q as getProtocolVersion,
267
+ J as initializeProtocol,
268
+ ut as noneCV,
269
+ et as normalizeTransaction,
270
+ tt as normalizeVault,
271
+ K as parseAmount,
272
+ ct as principalCV,
273
+ lt as responseErrorCV,
274
+ ft as responseOkCV,
275
+ x as retry,
276
+ y as sleep,
277
+ dt as someCV,
278
+ mt as stringAsciiCV,
279
+ ht as stringUtf8CV,
280
+ gt as uintCV,
281
+ q as validateAddress,
282
+ M as validateAddressResult
147
283
  };
@@ -0,0 +1,75 @@
1
+ /**
2
+ * @param {Partial<ProtocolConfig>} [options={}]
3
+ * @returns {ProtocolConfig}
4
+ */
5
+ export function initializeProtocol(options?: Partial<ProtocolConfig>): ProtocolConfig;
6
+ /**
7
+ * @returns {string}
8
+ */
9
+ export function getProtocolVersion(): string;
10
+ /**
11
+ * @returns {ProtocolConfig}
12
+ */
13
+ export function getProtocolConfig(): ProtocolConfig;
14
+ /**
15
+ * @param {Partial<Vault>} [vault={}]
16
+ * @returns {Vault}
17
+ */
18
+ export function normalizeVault(vault?: Partial<Vault>): Vault;
19
+ /**
20
+ * @param {Partial<Transaction>} [transaction={}]
21
+ * @returns {Transaction}
22
+ */
23
+ export function normalizeTransaction(transaction?: Partial<Transaction>): Transaction;
24
+ /**
25
+ * Protocol metadata and typed helpers for the TimeFi ecosystem.
26
+ */
27
+ /** @typedef {{ timeLock: boolean, vaults: boolean, governance: boolean, rewards: boolean }} ProtocolFeatures */
28
+ /** @typedef {{ network: string, version: string, features: ProtocolFeatures, initialized?: boolean }} ProtocolConfig */
29
+ /** @typedef {'active' | 'locked' | 'withdrawn' | 'failed'} VaultStatus */
30
+ /** @typedef {{ id: string, owner: string, amount: number, lockTime: number, unlockTime: number, status: VaultStatus, fees: number }} Vault */
31
+ /** @typedef {'deposit' | 'withdraw' | 'create' | 'fee'} TransactionType */
32
+ /** @typedef {'pending' | 'confirmed' | 'failed'} TransactionStatus */
33
+ /** @typedef {{ hash: string, type: TransactionType, amount: number, from: string, to: string, timestamp: number, status: TransactionStatus }} Transaction */
34
+ export const PROTOCOL_VERSION: "1.0.0";
35
+ /** @type {Readonly<ProtocolFeatures>} */
36
+ export const DEFAULT_PROTOCOL_FEATURES: Readonly<ProtocolFeatures>;
37
+ /** @type {Readonly<VaultStatus[]>} */
38
+ export const VAULT_STATUSES: Readonly<VaultStatus[]>;
39
+ /** @type {Readonly<TransactionType[]>} */
40
+ export const TRANSACTION_TYPES: Readonly<TransactionType[]>;
41
+ /** @type {Readonly<TransactionStatus[]>} */
42
+ export const TRANSACTION_STATUSES: Readonly<TransactionStatus[]>;
43
+ export type ProtocolFeatures = {
44
+ timeLock: boolean;
45
+ vaults: boolean;
46
+ governance: boolean;
47
+ rewards: boolean;
48
+ };
49
+ export type ProtocolConfig = {
50
+ network: string;
51
+ version: string;
52
+ features: ProtocolFeatures;
53
+ initialized?: boolean;
54
+ };
55
+ export type VaultStatus = "active" | "locked" | "withdrawn" | "failed";
56
+ export type Vault = {
57
+ id: string;
58
+ owner: string;
59
+ amount: number;
60
+ lockTime: number;
61
+ unlockTime: number;
62
+ status: VaultStatus;
63
+ fees: number;
64
+ };
65
+ export type TransactionType = "deposit" | "withdraw" | "create" | "fee";
66
+ export type TransactionStatus = "pending" | "confirmed" | "failed";
67
+ export type Transaction = {
68
+ hash: string;
69
+ type: TransactionType;
70
+ amount: number;
71
+ from: string;
72
+ to: string;
73
+ timestamp: number;
74
+ status: TransactionStatus;
75
+ };
@@ -0,0 +1,60 @@
1
+ /**
2
+ * @param {number | string | Date} timestamp
3
+ * @returns {string}
4
+ */
5
+ export function formatTimestamp(timestamp: number | string | Date): string;
6
+ /**
7
+ * @param {number | string | Date} endTime
8
+ * @returns {TimeRemaining}
9
+ */
10
+ export function calculateTimeRemaining(endTime: number | string | Date): TimeRemaining;
11
+ /**
12
+ * @param {string} address
13
+ * @returns {ValidationResult}
14
+ */
15
+ export function validateAddressResult(address: string): ValidationResult;
16
+ /**
17
+ * @param {string} address
18
+ * @returns {boolean}
19
+ */
20
+ export function validateAddress(address: string): boolean;
21
+ /**
22
+ * @param {number | string} amount
23
+ * @param {number} [decimals=6]
24
+ * @returns {string}
25
+ */
26
+ export function formatAmount(amount: number | string, decimals?: number): string;
27
+ /**
28
+ * @param {string | number} amountStr
29
+ * @returns {number}
30
+ */
31
+ export function parseAmount(amountStr: string | number): number;
32
+ /**
33
+ * @returns {string}
34
+ */
35
+ export function generateId(): string;
36
+ /**
37
+ * @param {number} ms
38
+ * @returns {Promise<void>}
39
+ */
40
+ export function sleep(ms: number): Promise<void>;
41
+ /**
42
+ * @template T
43
+ * @param {() => Promise<T>} fn
44
+ * @param {number} [maxRetries=3]
45
+ * @param {number} [delay=1000]
46
+ * @returns {Promise<T>}
47
+ */
48
+ export function retry<T>(fn: () => Promise<T>, maxRetries?: number, delay?: number): Promise<T>;
49
+ export type TimeRemaining = {
50
+ days: number;
51
+ hours: number;
52
+ minutes: number;
53
+ seconds: number;
54
+ total: number;
55
+ };
56
+ export type ValidationResult = {
57
+ valid: boolean;
58
+ address?: string;
59
+ error?: string;
60
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "timefi-sdk",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "description": "Official JavaScript SDK for TimeFi Protocol - Time-locked vaults on Stacks blockchain",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",