-
- {contract}
-
+
+
+
+
ArNS Names
+
+ Total Names: {totalNames}
+
+
+
+
+
+ Name |
+
+ Process
+ |
+ Type |
+
+ Expiry
+ |
+
+
+
+ {names.map((record) => (
+
+ {record.name} |
+
+ {record.processId.slice(0, 8)}...
+ |
+ {record.type} |
+
+ {record.type === 'lease' && record.endTimestamp
+ ? new Date(record.endTimestamp).toLocaleDateString()
+ : 'N/A'}
+ |
+
+ ))}
+
+
+
+
+
+
+ {' '}
+
Active Gateways
+
+ Total Gateways: {totalGateways}
+
+
+
+
+
+
+ Address
+ |
+
+ Status
+ |
+
+ Operator Stake (IO)
+ |
+
+ Total Delegated Stake (IO)
+ |
+
+
+
+ {gateways.map((gateway) => (
+
+
+ {gateway.gatewayAddress.slice(0, 8)}...
+ |
+ {gateway.status} |
+
+ {gateway.operatorStake / 10 ** 6}
+ |
+
+ {gateway.totalDelegatedStake / 10 ** 6}
+ |
+
+ ))}
+
+
+
+
+
+ {' '}
+
Active Auctions
+
+ Total Auctions: {totalAuctions}
+
+
+
+
+
+ Name |
+
+ Starts
+ |
+ Ends |
+
+ Base Fee
+ |
+
+ Initiator
+ |
+
+
+
+ {auctions.map((auction) => (
+
+ {auction.name} |
+
+ {new Date(auction.startTimestamp).toLocaleDateString()}
+ |
+
+ {new Date(auction.endTimestamp).toLocaleDateString()}
+ |
+
+ {auction.baseFee / 10 ** 6}
+ |
+
+ {auction.initiator.slice(0, 8)}...
+ |
+
+ ))}
+
+
+
+ {selectedAuction && (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )}
+
+
+
Prescribed Observers
+
+
+
+
+ Observer
+ |
+ Stake |
+
+ Tenure Weight
+ |
+
+ Stake Weight
+ |
+
+ Normalized Weight
+ |
+
+
+
+ {prescribedObservers.map((observer) => (
+
+
+ {observer.gatewayAddress.slice(0, 8)}...
+ |
+ {observer.stake} |
+ {observer.tenureWeight} |
+ {observer.stakeWeight} |
+
+ {observer.compositeWeight}
+ |
+
+ ))}
+
+
+
+
);
}
diff --git a/examples/vite/src/index.css b/examples/vite/src/index.css
index e8c77d29..20d9a81b 100644
--- a/examples/vite/src/index.css
+++ b/examples/vite/src/index.css
@@ -5,7 +5,7 @@ body {
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
- background-color: #282c34;
+ background-color: #f0f0f0;
}
code {
diff --git a/examples/vite/yarn.lock b/examples/vite/yarn.lock
index 8b1eaf2a..2978e213 100644
--- a/examples/vite/yarn.lock
+++ b/examples/vite/yarn.lock
@@ -199,6 +199,13 @@
dependencies:
regenerator-runtime "^0.14.0"
+"@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.9.tgz#65884fd6dc255a775402cc1d9811082918f4bf00"
+ integrity sha512-4zpTHZ9Cm6L9L+uIqghQX8ZXg8HKFcjYO3qHoO8zTmRm6HQUJ8SSJ+KRvbMBZn0EGVlT4DRYeQ/6hjlyXBh+Kg==
+ dependencies:
+ regenerator-runtime "^0.14.0"
+
"@babel/template@^7.22.15", "@babel/template@^7.24.0":
version "7.24.0"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50"
@@ -952,6 +959,57 @@
dependencies:
"@babel/types" "^7.20.7"
+"@types/d3-array@^3.0.3":
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.2.1.tgz#1f6658e3d2006c4fceac53fde464166859f8b8c5"
+ integrity sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==
+
+"@types/d3-color@*":
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-3.1.3.tgz#368c961a18de721da8200e80bf3943fb53136af2"
+ integrity sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==
+
+"@types/d3-ease@^3.0.0":
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-ease/-/d3-ease-3.0.2.tgz#e28db1bfbfa617076f7770dd1d9a48eaa3b6c51b"
+ integrity sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==
+
+"@types/d3-interpolate@^3.0.1":
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz#412b90e84870285f2ff8a846c6eb60344f12a41c"
+ integrity sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==
+ dependencies:
+ "@types/d3-color" "*"
+
+"@types/d3-path@*":
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-3.1.0.tgz#2b907adce762a78e98828f0b438eaca339ae410a"
+ integrity sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==
+
+"@types/d3-scale@^4.0.2":
+ version "4.0.8"
+ resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-4.0.8.tgz#d409b5f9dcf63074464bf8ddfb8ee5a1f95945bb"
+ integrity sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==
+ dependencies:
+ "@types/d3-time" "*"
+
+"@types/d3-shape@^3.1.0":
+ version "3.1.6"
+ resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-3.1.6.tgz#65d40d5a548f0a023821773e39012805e6e31a72"
+ integrity sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==
+ dependencies:
+ "@types/d3-path" "*"
+
+"@types/d3-time@*", "@types/d3-time@^3.0.0":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-3.0.3.tgz#3c186bbd9d12b9d84253b6be6487ca56b54f88be"
+ integrity sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==
+
+"@types/d3-timer@^3.0.0":
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-timer/-/d3-timer-3.0.2.tgz#70bbda77dc23aa727413e22e214afa3f0e852f70"
+ integrity sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==
+
"@types/debug@^4.0.0":
version "4.1.12"
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917"
@@ -1738,6 +1796,11 @@ clean-css@^5.2.2:
dependencies:
source-map "~0.6.0"
+clsx@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999"
+ integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==
+
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
@@ -1933,6 +1996,77 @@ csstype@^3.0.2:
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
+"d3-array@2 - 3", "d3-array@2.10.0 - 3", d3-array@^3.1.6:
+ version "3.2.4"
+ resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.2.4.tgz#15fec33b237f97ac5d7c986dc77da273a8ed0bb5"
+ integrity sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==
+ dependencies:
+ internmap "1 - 2"
+
+"d3-color@1 - 3":
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2"
+ integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==
+
+d3-ease@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4"
+ integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==
+
+"d3-format@1 - 3":
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-3.1.0.tgz#9260e23a28ea5cb109e93b21a06e24e2ebd55641"
+ integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==
+
+"d3-interpolate@1.2.0 - 3", d3-interpolate@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d"
+ integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==
+ dependencies:
+ d3-color "1 - 3"
+
+d3-path@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-3.1.0.tgz#22df939032fb5a71ae8b1800d61ddb7851c42526"
+ integrity sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==
+
+d3-scale@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-4.0.2.tgz#82b38e8e8ff7080764f8dcec77bd4be393689396"
+ integrity sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==
+ dependencies:
+ d3-array "2.10.0 - 3"
+ d3-format "1 - 3"
+ d3-interpolate "1.2.0 - 3"
+ d3-time "2.1.1 - 3"
+ d3-time-format "2 - 4"
+
+d3-shape@^3.1.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-3.2.0.tgz#a1a839cbd9ba45f28674c69d7f855bcf91dfc6a5"
+ integrity sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==
+ dependencies:
+ d3-path "^3.1.0"
+
+"d3-time-format@2 - 4":
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-4.1.0.tgz#7ab5257a5041d11ecb4fe70a5c7d16a195bb408a"
+ integrity sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==
+ dependencies:
+ d3-time "1 - 3"
+
+"d3-time@1 - 3", "d3-time@2.1.1 - 3", d3-time@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-3.1.0.tgz#9310db56e992e3c0175e1ef385e545e48a9bb5c7"
+ integrity sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==
+ dependencies:
+ d3-array "2 - 3"
+
+d3-timer@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0"
+ integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==
+
debug@^4.0.0, debug@^4.1.0, debug@^4.3.1:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
@@ -1940,6 +2074,11 @@ debug@^4.0.0, debug@^4.1.0, debug@^4.3.1:
dependencies:
ms "2.1.2"
+decimal.js-light@^2.4.1:
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz#134fd32508f19e208f4fb2f8dac0d2626a867934"
+ integrity sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==
+
decode-named-character-reference@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz#daabac9690874c394c81e4162a0304b35d824f0e"
@@ -2038,6 +2177,14 @@ dom-accessibility-api@^0.5.6, dom-accessibility-api@^0.5.9:
resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz#5a7429e6066eb3664d911e33fb0e45de8eb08453"
integrity sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==
+dom-helpers@^5.0.1:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902"
+ integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==
+ dependencies:
+ "@babel/runtime" "^7.8.7"
+ csstype "^3.0.2"
+
dom-serializer@^1.0.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30"
@@ -2123,7 +2270,7 @@ elliptic@6.5.4:
minimalistic-assert "^1.0.1"
minimalistic-crypto-utils "^1.0.1"
-elliptic@^6.5.3, elliptic@^6.5.4, elliptic@^6.5.5:
+elliptic@^6.5.3, elliptic@^6.5.5:
version "6.5.5"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.5.tgz#c715e09f78b6923977610d4c2346d6ce22e6dded"
integrity sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==
@@ -2136,6 +2283,19 @@ elliptic@^6.5.3, elliptic@^6.5.4, elliptic@^6.5.5:
minimalistic-assert "^1.0.1"
minimalistic-crypto-utils "^1.0.1"
+elliptic@^6.5.7:
+ version "6.5.7"
+ resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.7.tgz#8ec4da2cb2939926a1b9a73619d768207e647c8b"
+ integrity sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==
+ dependencies:
+ bn.js "^4.11.9"
+ brorand "^1.1.0"
+ hash.js "^1.0.0"
+ hmac-drbg "^1.0.1"
+ inherits "^2.0.4"
+ minimalistic-assert "^1.0.1"
+ minimalistic-crypto-utils "^1.0.1"
+
end-of-stream@^1.4.1:
version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
@@ -2234,6 +2394,11 @@ estree-walker@^2.0.1, estree-walker@^2.0.2:
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
+eventemitter3@^4.0.1:
+ version "4.0.7"
+ resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
+ integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
+
events@3.3.0, events@^3.0.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
@@ -2273,6 +2438,11 @@ fast-copy@^3.0.0:
resolved "https://registry.yarnpkg.com/fast-copy/-/fast-copy-3.0.2.tgz#59c68f59ccbcac82050ba992e0d5c389097c9d35"
integrity sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==
+fast-equals@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-5.0.1.tgz#a4eefe3c5d1c0d021aeed0bc10ba5e0c12ee405d"
+ integrity sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==
+
fast-glob@^3.2.11:
version "3.3.2"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
@@ -2614,6 +2784,11 @@ internal-slot@^1.0.4:
hasown "^2.0.0"
side-channel "^1.0.4"
+"internmap@1 - 2":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/internmap/-/internmap-2.0.3.tgz#6685f23755e43c524e251d29cbc97248e3061009"
+ integrity sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==
+
is-alphabetical@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-2.0.1.tgz#01072053ea7c1036df3c7d19a6daaec7f19e789b"
@@ -3021,7 +3196,7 @@ lodash.union@^4.6.0:
resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88"
integrity sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==
-lodash@^4.17.15:
+lodash@^4.17.15, lodash@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@@ -3031,7 +3206,7 @@ longest-streak@^3.0.0:
resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4"
integrity sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==
-loose-envify@^1.1.0:
+loose-envify@^1.1.0, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@@ -3754,6 +3929,11 @@ nth-check@^2.0.1:
dependencies:
boolbase "^1.0.0"
+object-assign@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+ integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
+
object-inspect@^1.13.1:
version "1.13.1"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2"
@@ -3950,6 +4130,15 @@ process@^0.11.10:
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==
+prop-types@^15.6.2, prop-types@^15.8.1:
+ version "15.8.1"
+ resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
+ integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
+ dependencies:
+ loose-envify "^1.4.0"
+ object-assign "^4.1.1"
+ react-is "^16.13.1"
+
property-information@^6.0.0:
version "6.5.0"
resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.5.0.tgz#6212fbb52ba757e92ef4fb9d657563b933b7ffec"
@@ -4017,12 +4206,17 @@ react-dom@^18.3.1:
loose-envify "^1.1.0"
scheduler "^0.23.2"
+react-is@^16.13.1:
+ version "16.13.1"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
+ integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
+
react-is@^17.0.1:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
-react-is@^18.0.0:
+react-is@^18.0.0, react-is@^18.3.1:
version "18.3.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
@@ -4048,6 +4242,25 @@ react-refresh@^0.14.0:
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9"
integrity sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==
+react-smooth@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/react-smooth/-/react-smooth-4.0.1.tgz#6200d8699bfe051ae40ba187988323b1449eab1a"
+ integrity sha512-OE4hm7XqR0jNOq3Qmk9mFLyd6p2+j6bvbPJ7qlB7+oo0eNcL2l7WQzG6MBnT3EXY6xzkLMUBec3AfewJdA0J8w==
+ dependencies:
+ fast-equals "^5.0.1"
+ prop-types "^15.8.1"
+ react-transition-group "^4.4.5"
+
+react-transition-group@^4.4.5:
+ version "4.4.5"
+ resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1"
+ integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==
+ dependencies:
+ "@babel/runtime" "^7.5.5"
+ dom-helpers "^5.0.1"
+ loose-envify "^1.4.0"
+ prop-types "^15.6.2"
+
react@^18.3.1:
version "18.3.1"
resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891"
@@ -4084,6 +4297,27 @@ readdir-glob@^1.1.2:
dependencies:
minimatch "^5.1.0"
+recharts-scale@^0.4.4:
+ version "0.4.5"
+ resolved "https://registry.yarnpkg.com/recharts-scale/-/recharts-scale-0.4.5.tgz#0969271f14e732e642fcc5bd4ab270d6e87dd1d9"
+ integrity sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==
+ dependencies:
+ decimal.js-light "^2.4.1"
+
+recharts@^2.13.0:
+ version "2.13.0"
+ resolved "https://registry.yarnpkg.com/recharts/-/recharts-2.13.0.tgz#a293322ea357491393cc7ad6fcbb1e5f8e99bc93"
+ integrity sha512-sbfxjWQ+oLWSZEWmvbq/DFVdeRLqqA6d0CDjKx2PkxVVdoXo16jvENCE+u/x7HxOO+/fwx//nYRwb8p8X6s/lQ==
+ dependencies:
+ clsx "^2.0.0"
+ eventemitter3 "^4.0.1"
+ lodash "^4.17.21"
+ react-is "^18.3.1"
+ react-smooth "^4.0.0"
+ recharts-scale "^0.4.4"
+ tiny-invariant "^1.3.1"
+ victory-vendor "^36.6.8"
+
redent@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f"
@@ -4265,11 +4499,11 @@ scrypt-js@3.0.1:
integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==
secp256k1@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-5.0.0.tgz#be6f0c8c7722e2481e9773336d351de8cddd12f7"
- integrity sha512-TKWX8xvoGHrxVdqbYeZM9w+izTF4b9z3NhSaDkdn81btvuh+ivbIMGT/zQvDtTFWhRlThpoz6LEYTr7n8A5GcA==
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-5.0.1.tgz#dc2c86187d48ff2da756f0f7e96417ee03c414b1"
+ integrity sha512-lDFs9AAIaWP9UCdtWrotXWWF9t8PWgQDcxqgAnpM9rMqxb3Oaq2J0thzPVSxBwdJgyQtkU/sYtFtbM1RSt/iYA==
dependencies:
- elliptic "^6.5.4"
+ elliptic "^6.5.7"
node-addon-api "^5.0.0"
node-gyp-build "^4.2.0"
@@ -4471,6 +4705,11 @@ timers-browserify@^2.0.4:
dependencies:
setimmediate "^1.0.4"
+tiny-invariant@^1.3.1:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127"
+ integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==
+
tmp-promise@^3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/tmp-promise/-/tmp-promise-3.0.3.tgz#60a1a1cc98c988674fcbfd23b6e3367bdeac4ce7"
@@ -4667,6 +4906,26 @@ vfile@^6.0.0:
unist-util-stringify-position "^4.0.0"
vfile-message "^4.0.0"
+victory-vendor@^36.6.8:
+ version "36.9.2"
+ resolved "https://registry.yarnpkg.com/victory-vendor/-/victory-vendor-36.9.2.tgz#668b02a448fa4ea0f788dbf4228b7e64669ff801"
+ integrity sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==
+ dependencies:
+ "@types/d3-array" "^3.0.3"
+ "@types/d3-ease" "^3.0.0"
+ "@types/d3-interpolate" "^3.0.1"
+ "@types/d3-scale" "^4.0.2"
+ "@types/d3-shape" "^3.1.0"
+ "@types/d3-time" "^3.0.0"
+ "@types/d3-timer" "^3.0.0"
+ d3-array "^3.1.6"
+ d3-ease "^3.0.1"
+ d3-interpolate "^3.0.1"
+ d3-scale "^4.0.2"
+ d3-shape "^3.1.0"
+ d3-time "^3.0.0"
+ d3-timer "^3.0.1"
+
vite-plugin-html@^3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/vite-plugin-html/-/vite-plugin-html-3.2.2.tgz#661834fa09015d3fda48ba694dbaa809396f5f7a"
diff --git a/examples/webpack/yarn.lock b/examples/webpack/yarn.lock
index 4c56f6ac..e247bb2a 100644
--- a/examples/webpack/yarn.lock
+++ b/examples/webpack/yarn.lock
@@ -3374,7 +3374,7 @@ elliptic@6.5.4:
minimalistic-assert "^1.0.1"
minimalistic-crypto-utils "^1.0.1"
-elliptic@^6.5.3, elliptic@^6.5.4, elliptic@^6.5.5:
+elliptic@^6.5.3, elliptic@^6.5.5:
version "6.5.5"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.5.tgz#c715e09f78b6923977610d4c2346d6ce22e6dded"
integrity sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==
@@ -3387,6 +3387,19 @@ elliptic@^6.5.3, elliptic@^6.5.4, elliptic@^6.5.5:
minimalistic-assert "^1.0.1"
minimalistic-crypto-utils "^1.0.1"
+elliptic@^6.5.7:
+ version "6.5.7"
+ resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.7.tgz#8ec4da2cb2939926a1b9a73619d768207e647c8b"
+ integrity sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==
+ dependencies:
+ bn.js "^4.11.9"
+ brorand "^1.1.0"
+ hash.js "^1.0.0"
+ hmac-drbg "^1.0.1"
+ inherits "^2.0.4"
+ minimalistic-assert "^1.0.1"
+ minimalistic-crypto-utils "^1.0.1"
+
emoji-regex@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
@@ -6538,11 +6551,11 @@ scrypt-js@3.0.1:
integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==
secp256k1@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-5.0.0.tgz#be6f0c8c7722e2481e9773336d351de8cddd12f7"
- integrity sha512-TKWX8xvoGHrxVdqbYeZM9w+izTF4b9z3NhSaDkdn81btvuh+ivbIMGT/zQvDtTFWhRlThpoz6LEYTr7n8A5GcA==
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-5.0.1.tgz#dc2c86187d48ff2da756f0f7e96417ee03c414b1"
+ integrity sha512-lDFs9AAIaWP9UCdtWrotXWWF9t8PWgQDcxqgAnpM9rMqxb3Oaq2J0thzPVSxBwdJgyQtkU/sYtFtbM1RSt/iYA==
dependencies:
- elliptic "^6.5.4"
+ elliptic "^6.5.7"
node-addon-api "^5.0.0"
node-gyp-build "^4.2.0"
diff --git a/package.json b/package.json
index beb4ad34..b85459f9 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@ar.io/sdk",
- "version": "2.3.2",
+ "version": "2.4.0-alpha.16",
"repository": {
"type": "git",
"url": "git+https://github.com/ar-io/ar-io-sdk.git"
@@ -66,16 +66,18 @@
"format": "prettier --check .",
"format:fix": "prettier --write .",
"test": "yarn test:unit && yarn test:e2e",
- "test:cjs": "yarn test:link && cd ./tests/e2e/cjs && yarn && yarn test",
- "test:esm": "yarn test:link && cd ./tests/e2e/esm && yarn && yarn test",
- "test:web": "yarn test:link && cd ./tests/e2e/web && yarn && yarn test",
+ "test:cjs": "yarn build:cjs && yarn link && cd ./tests/e2e/cjs && yarn && yarn test",
+ "test:esm": "yarn build:esm && yarn link && cd ./tests/e2e/esm && yarn && yarn test",
+ "test:web": "yarn build:esm && yarn link && cd ./tests/e2e/web && yarn && yarn test",
"test:unit": "NODE_OPTIONS=\"--import=./register.mjs\" node --test tests/unit/**.test.ts",
"test:link": "yarn build && yarn link",
"test:e2e": "yarn test:cjs && yarn test:esm && yarn test:web",
"prepare": "husky install",
+ "docs:update": "markdown-toc-gen insert README.md",
"example:esm": "cd examples/esm && yarn && node index.mjs",
- "example:cjs": "yarn test:link && cd examples/cjs && yarn && node index.cjs",
- "example:web": "yarn test:link && build:web && http-server --port 8080 --host -o examples/web"
+ "example:cjs": "yarn build:cjs && yarn link && cd examples/cjs && yarn && node index.cjs",
+ "example:web": "yarn build:web && http-server --port 8080 --host -o examples/web",
+ "example:vite": "yarn build:esm && yarn link && cd examples/vite && yarn && yarn start"
},
"devDependencies": {
"@commitlint/cli": "^17.1.2",
@@ -107,6 +109,7 @@
"husky": "^8.0.3",
"lint-staged": "^15.2.2",
"markdown-toc-gen": "^1.0.1",
+ "nock": "^13.5.5",
"prettier": "^3.0.2",
"rimraf": "^5.0.1",
"semantic-release": "^21.0.7",
diff --git a/src/common/ant-registry.ts b/src/common/ant-registry.ts
index adb3b51e..eeb85a54 100644
--- a/src/common/ant-registry.ts
+++ b/src/common/ant-registry.ts
@@ -17,6 +17,8 @@ import { ANT_REGISTRY_ID } from '../constants.js';
import {
AoANTRegistryRead,
AoANTRegistryWrite,
+} from '../types/ant-registry.js';
+import {
AoMessageResult,
AoSigner,
OptionalSigner,
@@ -24,7 +26,7 @@ import {
WithSigner,
isProcessConfiguration,
isProcessIdConfiguration,
-} from '../types.js';
+} from '../types/index.js';
import { createAoSigner } from '../utils/ao.js';
import { AOProcess, InvalidContractConfigurationError } from './index.js';
diff --git a/src/common/ant.ts b/src/common/ant.ts
index 74f97056..f715e30f 100644
--- a/src/common/ant.ts
+++ b/src/common/ant.ts
@@ -13,12 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import { z } from 'zod';
+
import {
+ AntBalancesSchema,
+ AntControllersSchema,
+ AntInfoSchema,
+ AntReadOptions,
+ AntRecordSchema,
+ AntRecordsSchema,
+ AntStateSchema,
AoANTInfo,
AoANTRead,
AoANTRecord,
AoANTState,
AoANTWrite,
+} from '../types/ant.js';
+import {
AoMessageResult,
AoSigner,
OptionalSigner,
@@ -28,28 +39,37 @@ import {
WriteOptions,
isProcessConfiguration,
isProcessIdConfiguration,
-} from '../types.js';
+} from '../types/index.js';
import { createAoSigner } from '../utils/ao.js';
+import { parseSchemaResult } from '../utils/schema.js';
import { AOProcess, InvalidContractConfigurationError } from './index.js';
export class ANT {
static init(
- config: Required
& { signer?: undefined },
+ config: Required & {
+ signer?: undefined;
+ strict?: boolean;
+ },
): AoANTRead;
static init({
signer,
...config
- }: WithSigner>): AoANTWrite;
+ }: WithSigner> & {
+ strict?: boolean;
+ }): AoANTWrite;
static init({
signer,
+ strict = false,
...config
- }: OptionalSigner>): AoANTRead | AoANTWrite {
+ }: OptionalSigner> & { strict?: boolean }):
+ | AoANTRead
+ | AoANTWrite {
// ao supported implementation
if (isProcessConfiguration(config) || isProcessIdConfiguration(config)) {
if (!signer) {
- return new AoANTReadable(config);
+ return new AoANTReadable({ strict, ...config });
}
- return new AoANTWriteable({ signer, ...config });
+ return new AoANTWriteable({ signer, strict, ...config });
}
throw new InvalidContractConfigurationError();
@@ -58,8 +78,10 @@ export class ANT {
export class AoANTReadable implements AoANTRead {
protected process: AOProcess;
+ private strict: boolean;
- constructor(config: Required) {
+ constructor(config: Required & { strict?: boolean }) {
+ this.strict = config.strict || false;
if (isProcessConfiguration(config)) {
this.process = config.process;
} else if (isProcessIdConfiguration(config)) {
@@ -71,19 +93,37 @@ export class AoANTReadable implements AoANTRead {
}
}
- async getState(): Promise {
+ async getState(
+ { strict }: AntReadOptions = { strict: this.strict },
+ ): Promise {
const tags = [{ name: 'Action', value: 'State' }];
const res = await this.process.read({
tags,
});
+ if (strict) {
+ parseSchemaResult(
+ AntStateSchema.passthrough().and(
+ z.object({
+ Records: z.record(z.string(), AntRecordSchema.passthrough()),
+ }),
+ ),
+ res,
+ );
+ }
+
return res;
}
- async getInfo(): Promise {
+ async getInfo(
+ { strict }: AntReadOptions = { strict: this.strict },
+ ): Promise {
const tags = [{ name: 'Action', value: 'Info' }];
const info = await this.process.read({
tags,
});
+ if (strict) {
+ parseSchemaResult(AntInfoSchema.passthrough(), info);
+ }
return info;
}
@@ -96,7 +136,10 @@ export class AoANTReadable implements AoANTRead {
* ant.getRecord({ undername: "john" });
* ```
*/
- async getRecord({ undername }: { undername: string }): Promise {
+ async getRecord(
+ { undername }: { undername: string },
+ { strict }: AntReadOptions = { strict: this.strict },
+ ): Promise {
const tags = [
{ name: 'Sub-Domain', value: undername },
{ name: 'Action', value: 'Record' },
@@ -105,6 +148,8 @@ export class AoANTReadable implements AoANTRead {
const record = await this.process.read({
tags,
});
+ if (strict) parseSchemaResult(AntRecordSchema.passthrough(), record);
+
return record;
}
@@ -116,11 +161,14 @@ export class AoANTReadable implements AoANTRead {
* ant.getRecords();
* ````
*/
- async getRecords(): Promise> {
+ async getRecords(
+ { strict }: AntReadOptions = { strict: this.strict },
+ ): Promise> {
const tags = [{ name: 'Action', value: 'Records' }];
const records = await this.process.read>({
tags,
});
+ if (strict) parseSchemaResult(AntRecordsSchema, records);
return records;
}
@@ -132,8 +180,10 @@ export class AoANTReadable implements AoANTRead {
* ant.getOwner();
* ```
*/
- async getOwner(): Promise {
- const info = await this.getInfo();
+ async getOwner(
+ { strict }: AntReadOptions = { strict: this.strict },
+ ): Promise {
+ const info = await this.getInfo({ strict });
return info.Owner;
}
@@ -145,11 +195,14 @@ export class AoANTReadable implements AoANTRead {
* ant.getControllers();
* ```
*/
- async getControllers(): Promise {
+ async getControllers(
+ { strict }: AntReadOptions = { strict: this.strict },
+ ): Promise {
const tags = [{ name: 'Action', value: 'Controllers' }];
const controllers = await this.process.read({
tags,
});
+ if (strict) parseSchemaResult(AntControllersSchema, controllers);
return controllers;
}
@@ -161,8 +214,10 @@ export class AoANTReadable implements AoANTRead {
* ant.getName();
* ```
*/
- async getName(): Promise {
- const info = await this.getInfo();
+ async getName(
+ { strict }: AntReadOptions = { strict: this.strict },
+ ): Promise {
+ const info = await this.getInfo({ strict });
return info.Name;
}
@@ -174,8 +229,10 @@ export class AoANTReadable implements AoANTRead {
* ant.getTicker();
* ```
*/
- async getTicker(): Promise {
- const info = await this.getInfo();
+ async getTicker(
+ { strict }: AntReadOptions = { strict: this.strict },
+ ): Promise {
+ const info = await this.getInfo({ strict });
return info.Ticker;
}
@@ -187,11 +244,14 @@ export class AoANTReadable implements AoANTRead {
* ant.getBalances();
* ```
*/
- async getBalances(): Promise> {
+ async getBalances(
+ { strict }: AntReadOptions = { strict: this.strict },
+ ): Promise> {
const tags = [{ name: 'Action', value: 'Balances' }];
const balances = await this.process.read>({
tags,
});
+ if (strict) parseSchemaResult(AntBalancesSchema, balances);
return balances;
}
@@ -204,7 +264,10 @@ export class AoANTReadable implements AoANTRead {
* ant.getBalance({ address });
* ```
*/
- async getBalance({ address }: { address: string }): Promise {
+ async getBalance(
+ { address }: { address: string },
+ { strict }: AntReadOptions = { strict: this.strict },
+ ): Promise {
const tags = [
{ name: 'Action', value: 'Balance' },
{ name: 'Recipient', value: address },
@@ -212,6 +275,7 @@ export class AoANTReadable implements AoANTRead {
const balance = await this.process.read({
tags,
});
+ if (strict) parseSchemaResult(z.number(), balance);
return balance;
}
}
@@ -222,7 +286,7 @@ export class AoANTWriteable extends AoANTReadable implements AoANTWrite {
constructor({
signer,
...config
- }: WithSigner>) {
+ }: WithSigner> & { strict?: boolean }) {
super(config);
this.signer = createAoSigner(signer);
}
@@ -393,7 +457,7 @@ export class AoANTWriteable extends AoANTReadable implements AoANTWrite {
* @returns {Promise} The result of the interaction.
* @example
* ```ts
- * ant.setName({ name: "ships at sea" });
+ * ant.setName({ name: "test" }); // results in the resolution of `test_.ar.io`
* ```
*/
async setName(
@@ -409,4 +473,103 @@ export class AoANTWriteable extends AoANTReadable implements AoANTWrite {
signer: this.signer,
});
}
+
+ /**
+ * @param description @type {string} Sets the ANT Description.
+ * @returns {Promise} The result of the interaction.
+ * @example
+ * ```ts
+ * ant.setDescription({ description: "This name is used for the ArDrive" });
+ * ```
+ */
+ async setDescription(
+ { description }: { description: string },
+ options?: WriteOptions,
+ ): Promise {
+ return this.process.send({
+ tags: [
+ ...(options?.tags ?? []),
+ { name: 'Action', value: 'Set-Description' },
+ { name: 'Description', value: description },
+ ],
+ signer: this.signer,
+ });
+ }
+
+ /**
+ * @param keywords @type {string[]} Sets the ANT Keywords.
+ * @returns {Promise} The result of the interaction.
+ * @example
+ * ```ts
+ * ant.setKeywords({ keywords: ['keyword1', 'keyword2', 'keyword3']});
+ * ```
+ */
+ async setKeywords(
+ { keywords }: { keywords: string[] },
+ options?: WriteOptions,
+ ): Promise {
+ return this.process.send({
+ tags: [
+ ...(options?.tags ?? []),
+ { name: 'Action', value: 'Set-Keywords' },
+ { name: 'Description', value: JSON.stringify(keywords) },
+ ],
+ signer: this.signer,
+ });
+ }
+
+ /**
+ * @param name @type {string} The name you want to release. The name will be put up for auction on the IO contract. 50% of the winning bid will be distributed to the ANT owner at the time of release. If no bids, the name will be released and can be reregistered by anyone.
+ * @param ioProcessId @type {string} The processId of the IO contract. This is where the ANT will send the message to release the name.
+ * @returns {Promise} The result of the interaction.
+ * @example
+ * ```ts
+ * ant.releaseName({ name: "ardrive", ioProcessId: IO_TESTNET_PROCESS_ID });
+ * ```
+ */
+ async releaseName(
+ { name, ioProcessId }: { name: string; ioProcessId: string },
+ options?: WriteOptions,
+ ): Promise {
+ return this.process.send({
+ tags: [
+ ...(options?.tags ?? []),
+ { name: 'Action', value: 'Release-Name' },
+ { name: 'Name', value: name },
+ { name: 'IO-Process-Id', value: ioProcessId },
+ ],
+ signer: this.signer,
+ });
+ }
+
+ /**
+ * Sends a message to the IO contract to reassign the name to a new ANT. This can only be done by the current owner of the ANT.
+ * @param name @type {string} The name you want to reassign.
+ * @param ioProcessId @type {string} The processId of the IO contract.
+ * @param antProcessId @type {string} The processId of the ANT contract.
+ * @returns {Promise} The result of the interaction.
+ * @example
+ * ```ts
+ * ant.reassignName({ name: "ardrive", ioProcessId: IO_TESTNET_PROCESS_ID, antProcessId: NEW_ANT_PROCESS_ID });
+ * ```
+ */
+ async reassignName(
+ {
+ name,
+ ioProcessId,
+ antProcessId,
+ }: { name: string; ioProcessId: string; antProcessId: string },
+ options?: WriteOptions,
+ ): Promise {
+ return this.process.send({
+ tags: [
+ ...(options?.tags ?? []),
+ { name: 'Action', value: 'Reassign-Name' },
+ { name: 'Name', value: name },
+ { name: 'IO-Process-Id', value: ioProcessId },
+ { name: 'Process-Id', value: antProcessId },
+ ],
+ signer: this.signer,
+ });
+ }
}
diff --git a/src/common/contracts/ao-process.ts b/src/common/contracts/ao-process.ts
index 2de06a03..ca80de60 100644
--- a/src/common/contracts/ao-process.ts
+++ b/src/common/contracts/ao-process.ts
@@ -15,7 +15,7 @@
*/
import { connect } from '@permaweb/aoconnect';
-import { AOContract, AoClient, AoSigner } from '../../types.js';
+import { AOContract, AoClient, AoSigner } from '../../types/index.js';
import { safeDecode } from '../../utils/json.js';
import { version } from '../../version.js';
import { WriteInteractionError } from '../error.js';
@@ -59,25 +59,33 @@ export class AOProcess implements AOContract {
process: this.processId,
tags,
});
+ this.logger.debug(`Read interaction result`, {
+ result,
+ });
if (result.Messages === undefined || result.Messages.length === 0) {
+ this.logger.debug(
+ `Process ${this.processId} does not support provided action.`,
+ result,
+ tags,
+ );
throw new Error(
`Process ${this.processId} does not support provided action.`,
);
}
const tagsOutput = result.Messages[0].Tags;
+ const messageData = result.Messages[0].Data;
+
const error = tagsOutput.find((tag) => tag.name === 'Error');
if (error) {
- throw new Error(`${error.Value}: ${result.Messages[0].Data}`);
+ throw new Error(
+ `${error.value}${messageData ? `: ${messageData}` : ''}`,
+ );
}
- this.logger.debug(`Read interaction result`, {
- result: result.Messages[0].Data,
- });
-
// return empty object if no data is returned
- if (result.Messages[0].Data === undefined) {
+ if (messageData === undefined) {
return {} as K;
}
@@ -90,6 +98,7 @@ export class AOProcess implements AOContract {
tags,
});
lastError = e;
+
// exponential backoff
await new Promise((resolve) =>
setTimeout(resolve, 2 ** attempts * 1000),
diff --git a/src/common/http.ts b/src/common/http.ts
index 943de9c0..e79dfadb 100644
--- a/src/common/http.ts
+++ b/src/common/http.ts
@@ -15,8 +15,8 @@
*/
import { AxiosInstance } from 'axios';
-import { HTTPClient } from '../types.js';
-import { createAxiosInstance } from '../utils/index.js';
+import { HTTPClient } from '../types/index.js';
+import { createAxiosInstance } from '../utils/http-client.js';
import { FailedRequestError, NotFound, UnknownError } from './error.js';
import { ILogger, Logger } from './logger.js';
diff --git a/src/common/io.ts b/src/common/io.ts
index 016b94fc..24b31c68 100644
--- a/src/common/io.ts
+++ b/src/common/io.ts
@@ -16,22 +16,10 @@
import Arweave from 'arweave';
import { IO_TESTNET_PROCESS_ID } from '../constants.js';
-import {
- AoArNSNameData,
- AoEpochData,
- AoEpochSettings,
- AoGateway,
- AoIORead,
- AoIOWrite,
- AoRegistrationFees,
- EpochInput,
- isProcessConfiguration,
- isProcessIdConfiguration,
-} from '../io.js';
-import { AoSigner, mIOToken } from '../token.js';
import {
AoArNSNameDataWithName,
AoArNSReservedNameData,
+ AoAuction,
AoBalanceWithAddress,
AoEpochDistributionData,
AoEpochObservationData,
@@ -50,8 +38,26 @@ import {
WalletAddress,
WithSigner,
WriteOptions,
-} from '../types.js';
+} from '../types/index.js';
+import {
+ AoArNSNameData,
+ AoAuctionPriceData,
+ AoEpochData,
+ AoEpochSettings,
+ AoGateway,
+ AoGatewayDelegateWithAddress,
+ AoIORead,
+ AoIOWrite,
+ AoRegistrationFees,
+ AoVaultData,
+ AoWalletVault,
+ EpochInput,
+ isProcessConfiguration,
+ isProcessIdConfiguration,
+} from '../types/io.js';
+import { AoSigner, mIOToken } from '../types/token.js';
import { createAoSigner } from '../utils/ao.js';
+import { getCurrentBlockUnixTimestampMs, pruneTags } from '../utils/arweave.js';
import { defaultArweave } from './arweave.js';
import { AOProcess } from './contracts/ao-process.js';
import { InvalidContractConfigurationError } from './error.js';
@@ -145,16 +151,7 @@ export class IOReadable implements AoIORead {
name: 'Timestamp',
value:
(params as { timestamp?: number })?.timestamp?.toString() ??
- (
- await this.arweave.blocks
- .getCurrent()
- .then((block) => {
- return { timestamp: block.timestamp * 1000 };
- })
- .catch(() => {
- return { timestamp: Date.now() }; // fallback to current time
- })
- ).timestamp.toString(),
+ (await getCurrentBlockUnixTimestampMs(this.arweave)).toString(),
},
{
name: 'Epoch-Index',
@@ -162,15 +159,8 @@ export class IOReadable implements AoIORead {
},
];
- const prunedTags: { name: string; value: string }[] = allTags.filter(
- (tag: {
- name: string;
- value: string | undefined;
- }): tag is { name: string; value: string } => tag.value !== undefined,
- );
-
return this.process.read({
- tags: prunedTags,
+ tags: pruneTags(allTags),
});
}
async getEpoch(epoch?: EpochInput): Promise {
@@ -180,16 +170,7 @@ export class IOReadable implements AoIORead {
name: 'Timestamp',
value:
(epoch as { timestamp?: number })?.timestamp?.toString() ??
- (
- await this.arweave.blocks
- .getCurrent()
- .then((block) => {
- return { timestamp: block.timestamp * 1000 };
- })
- .catch(() => {
- return { timestamp: Date.now() }; // fallback to current time
- })
- ).timestamp.toString(),
+ (await getCurrentBlockUnixTimestampMs(this.arweave)).toString(),
},
{
name: 'Epoch-Index',
@@ -197,15 +178,8 @@ export class IOReadable implements AoIORead {
},
];
- const prunedTags: { name: string; value: string }[] = allTags.filter(
- (tag: {
- name: string;
- value: string | undefined;
- }): tag is { name: string; value: string } => tag.value !== undefined,
- );
-
return this.process.read({
- tags: prunedTags,
+ tags: pruneTags(allTags),
});
}
@@ -223,25 +197,18 @@ export class IOReadable implements AoIORead {
}
async getArNSRecords(
- pageParams?: PaginationParams,
+ params?: PaginationParams,
): Promise> {
const allTags = [
{ name: 'Action', value: 'Paginated-Records' },
- { name: 'Cursor', value: pageParams?.cursor?.toString() },
- { name: 'Limit', value: pageParams?.limit?.toString() },
- { name: 'Sort-By', value: pageParams?.sortBy },
- { name: 'Sort-Order', value: pageParams?.sortOrder },
+ { name: 'Cursor', value: params?.cursor?.toString() },
+ { name: 'Limit', value: params?.limit?.toString() },
+ { name: 'Sort-By', value: params?.sortBy },
+ { name: 'Sort-Order', value: params?.sortOrder },
];
- const prunedTags: { name: string; value: string }[] = allTags.filter(
- (tag: {
- name: string;
- value: string | undefined;
- }): tag is { name: string; value: string } => tag.value !== undefined,
- );
-
return this.process.read>({
- tags: prunedTags,
+ tags: pruneTags(allTags),
});
}
@@ -276,25 +243,50 @@ export class IOReadable implements AoIORead {
}
async getBalances(
- pageParams?: PaginationParams,
+ params?: PaginationParams,
): Promise> {
const allTags = [
{ name: 'Action', value: 'Paginated-Balances' },
- { name: 'Cursor', value: pageParams?.cursor?.toString() },
- { name: 'Limit', value: pageParams?.limit?.toString() },
- { name: 'Sort-By', value: pageParams?.sortBy },
- { name: 'Sort-Order', value: pageParams?.sortOrder },
+ { name: 'Cursor', value: params?.cursor?.toString() },
+ { name: 'Limit', value: params?.limit?.toString() },
+ { name: 'Sort-By', value: params?.sortBy },
+ { name: 'Sort-Order', value: params?.sortOrder },
];
- const prunedTags: { name: string; value: string }[] = allTags.filter(
- (tag: {
- name: string;
- value: string | undefined;
- }): tag is { name: string; value: string } => tag.value !== undefined,
- );
-
return this.process.read>({
- tags: prunedTags,
+ tags: pruneTags(allTags),
+ });
+ }
+
+ async getVault({
+ address,
+ vaultId,
+ }: {
+ address: WalletAddress;
+ vaultId: string;
+ }): Promise {
+ return this.process.read({
+ tags: [
+ { name: 'Action', value: 'Vault' },
+ { name: 'Address', value: address },
+ { name: 'Vault-Id', value: vaultId },
+ ],
+ });
+ }
+
+ async getVaults(
+ params?: PaginationParams,
+ ): Promise> {
+ const allTags = [
+ { name: 'Action', value: 'Paginated-Vaults' },
+ { name: 'Cursor', value: params?.cursor?.toString() },
+ { name: 'Limit', value: params?.limit?.toString() },
+ { name: 'Sort-By', value: params?.sortBy },
+ { name: 'Sort-Order', value: params?.sortOrder },
+ ];
+
+ return this.process.read>({
+ tags: pruneTags(allTags),
});
}
@@ -311,8 +303,48 @@ export class IOReadable implements AoIORead {
});
}
+ async getGatewayDelegates({
+ address,
+ ...pageParams
+ }): Promise> {
+ const allTags = [
+ { name: 'Action', value: 'Paginated-Delegates' },
+ { name: 'Address', value: address },
+ { name: 'Cursor', value: pageParams?.cursor?.toString() },
+ { name: 'Limit', value: pageParams?.limit?.toString() },
+ { name: 'Sort-By', value: pageParams?.sortBy },
+ { name: 'Sort-Order', value: pageParams?.sortOrder },
+ ];
+
+ return this.process.read>({
+ tags: pruneTags(allTags),
+ });
+ }
+
+ async getGatewayDelegateAllowList({
+ address,
+ ...pageParams
+ }: {
+ address: WalletAddress;
+ } & PaginationParams): Promise<
+ PaginationResult
+ > {
+ const allTags = [
+ { name: 'Action', value: 'Paginated-Allowed-Delegates' },
+ { name: 'Address', value: address },
+ { name: 'Cursor', value: pageParams?.cursor?.toString() },
+ { name: 'Limit', value: pageParams?.limit?.toString() },
+ { name: 'Sort-Order', value: pageParams?.sortOrder },
+ // note: sortBy is omitted because it's not supported for this action as table is an of addresses
+ ];
+
+ return this.process.read>({
+ tags: pruneTags(allTags),
+ });
+ }
+
async getGateways(
- pageParams?: PaginationParams,
+ pageParams?: PaginationParams,
): Promise> {
const allTags = [
{ name: 'Action', value: 'Paginated-Gateways' },
@@ -322,15 +354,8 @@ export class IOReadable implements AoIORead {
{ name: 'Sort-Order', value: pageParams?.sortOrder },
];
- const prunedTags: { name: string; value: string }[] = allTags.filter(
- (tag: {
- name: string;
- value: string | undefined;
- }): tag is { name: string; value: string } => tag.value !== undefined,
- );
-
return this.process.read>({
- tags: prunedTags,
+ tags: pruneTags(allTags),
});
}
@@ -364,16 +389,7 @@ export class IOReadable implements AoIORead {
name: 'Timestamp',
value:
(epoch as { timestamp?: number })?.timestamp?.toString() ??
- (
- await this.arweave.blocks
- .getCurrent()
- .then((block) => {
- return { timestamp: block.timestamp * 1000 };
- })
- .catch(() => {
- return { timestamp: Date.now() }; // fallback to current time
- })
- ).timestamp.toString(),
+ (await getCurrentBlockUnixTimestampMs(this.arweave)).toString(),
},
{
name: 'Epoch-Index',
@@ -381,15 +397,8 @@ export class IOReadable implements AoIORead {
},
];
- const prunedTags: { name: string; value: string }[] = allTags.filter(
- (tag: {
- name: string;
- value: string | undefined;
- }): tag is { name: string; value: string } => tag.value !== undefined,
- );
-
return this.process.read({
- tags: prunedTags,
+ tags: pruneTags(allTags),
});
}
@@ -400,16 +409,7 @@ export class IOReadable implements AoIORead {
name: 'Timestamp',
value:
(epoch as { timestamp?: number })?.timestamp?.toString() ??
- (
- await this.arweave.blocks
- .getCurrent()
- .then((block) => {
- return { timestamp: block.timestamp * 1000 };
- })
- .catch(() => {
- return { timestamp: Date.now() }; // fallback to current time
- })
- ).timestamp.toString(),
+ (await getCurrentBlockUnixTimestampMs(this.arweave)).toString(),
},
{
name: 'Epoch-Index',
@@ -417,15 +417,8 @@ export class IOReadable implements AoIORead {
},
];
- const prunedTags: { name: string; value: string }[] = allTags.filter(
- (tag: {
- name: string;
- value: string | undefined;
- }): tag is { name: string; value: string } => tag.value !== undefined,
- );
-
return this.process.read({
- tags: prunedTags,
+ tags: pruneTags(allTags),
});
}
@@ -453,15 +446,8 @@ export class IOReadable implements AoIORead {
},
];
- const prunedTags: { name: string; value: string }[] = allTags.filter(
- (tag: {
- name: string;
- value: string | undefined;
- }): tag is { name: string; value: string } => tag.value !== undefined,
- );
-
return this.process.read({
- tags: prunedTags,
+ tags: pruneTags(allTags),
});
}
@@ -472,16 +458,7 @@ export class IOReadable implements AoIORead {
name: 'Timestamp',
value:
(epoch as { timestamp?: number })?.timestamp?.toString() ??
- (
- await this.arweave.blocks
- .getCurrent()
- .then((block) => {
- return { timestamp: block.timestamp * 1000 };
- })
- .catch(() => {
- return { timestamp: Date.now() }; // fallback to current time
- })
- ).timestamp.toString(),
+ (await getCurrentBlockUnixTimestampMs(this.arweave)).toString(),
},
{
name: 'Epoch-Index',
@@ -489,21 +466,14 @@ export class IOReadable implements AoIORead {
},
];
- const prunedTags: { name: string; value: string }[] = allTags.filter(
- (tag: {
- name: string;
- value: string | undefined;
- }): tag is { name: string; value: string } => tag.value !== undefined,
- );
-
return this.process.read({
- tags: prunedTags,
+ tags: pruneTags(allTags),
});
}
async getTokenCost(params: {
intent: 'Buy-Record';
- purchaseType: 'permabuy' | 'lease';
+ type: 'permabuy' | 'lease';
years: number;
name: string;
}): Promise;
@@ -519,13 +489,13 @@ export class IOReadable implements AoIORead {
}): Promise;
async getTokenCost({
intent,
- purchaseType,
+ type,
years,
name,
quantity,
}: {
intent: 'Buy-Record' | 'Extend-Lease' | 'Increase-Undername-Limit';
- purchaseType?: 'permabuy' | 'lease';
+ type?: 'permabuy' | 'lease';
years?: number;
name?: string;
quantity?: number;
@@ -550,7 +520,7 @@ export class IOReadable implements AoIORead {
},
{
name: 'Purchase-Type',
- value: purchaseType,
+ value: type,
},
{
name: 'Timestamp',
@@ -567,15 +537,8 @@ export class IOReadable implements AoIORead {
},
];
- const prunedTags: { name: string; value: string }[] = allTags.filter(
- (tag: {
- name: string;
- value: string | undefined;
- }): tag is { name: string; value: string } => tag.value !== undefined,
- );
-
return this.process.read({
- tags: prunedTags,
+ tags: pruneTags(allTags),
});
}
@@ -590,6 +553,90 @@ export class IOReadable implements AoIORead {
tags: [{ name: 'Action', value: 'Demand-Factor' }],
});
}
+
+ // Auctions
+ async getArNSAuctions(
+ params?: PaginationParams,
+ ): Promise> {
+ const allTags = [
+ { name: 'Action', value: 'Auctions' },
+ { name: 'Cursor', value: params?.cursor?.toString() },
+ { name: 'Limit', value: params?.limit?.toString() },
+ { name: 'Sort-By', value: params?.sortBy },
+ { name: 'Sort-Order', value: params?.sortOrder },
+ ];
+
+ return this.process.read>({
+ tags: pruneTags(allTags),
+ });
+ }
+
+ async getArNSAuction({
+ name,
+ }: {
+ name: string;
+ }): Promise {
+ const allTags = [
+ { name: 'Action', value: 'Auction-Info' },
+ { name: 'Name', value: name },
+ ];
+
+ return this.process.read({
+ tags: allTags,
+ });
+ }
+
+ /**
+ * Get auction prices for a given auction at the provided intervals
+ *
+ * @param {Object} params - The parameters for fetching auction prices
+ * @param {string} params.name - The name of the auction
+ * @param {('permabuy'|'lease')} [params.type='lease'] - The type of purchase
+ * @param {number} [params.years=1] - The number of years for lease (only applicable if type is 'lease')
+ * @param {number} [params.timestamp=Date.now()] - The timestamp to fetch prices for
+ * @param {number} [params.intervalMs=900000] - The interval in milliseconds between price points (default is 15 minutes)
+ * @returns {Promise} The auction price data
+ */
+ async getArNSAuctionPrices({
+ name,
+ type,
+ years,
+ timestamp,
+ intervalMs,
+ }: {
+ name: string;
+ type?: 'permabuy' | 'lease';
+ years?: number;
+ timestamp?: number;
+ intervalMs?: number;
+ }): Promise {
+ const prunedPriceTags: { name: string; value: string }[] = [
+ { name: 'Action', value: 'Auction-Prices' },
+ { name: 'Name', value: name },
+ {
+ name: 'Timestamp',
+ value: timestamp?.toString() ?? Date.now().toString(),
+ },
+ { name: 'Purchase-Type', value: type ?? 'lease' },
+ {
+ name: 'Years',
+ value:
+ type == undefined || type === 'lease'
+ ? years?.toString() ?? '1'
+ : undefined,
+ },
+ {
+ name: 'Price-Interval-Ms',
+ value: intervalMs?.toString() ?? '900000',
+ },
+ ].filter(
+ (tag): tag is { name: string; value: string } => tag.value !== undefined,
+ );
+
+ return this.process.read({
+ tags: prunedPriceTags,
+ });
+ }
}
export class IOWriteable extends IOReadable implements AoIOWrite {
@@ -658,6 +705,7 @@ export class IOWriteable extends IOReadable implements AoIOWrite {
{
operatorStake,
allowDelegatedStaking,
+ allowedDelegates,
delegateRewardShareRatio,
fqdn,
label,
@@ -683,6 +731,10 @@ export class IOWriteable extends IOReadable implements AoIOWrite {
name: 'Allow-Delegated-Staking',
value: allowDelegatedStaking?.toString(),
},
+ {
+ name: 'Allowed-Delegates',
+ value: allowedDelegates?.join(','),
+ },
{
name: 'Delegate-Reward-Share-Ratio',
value: delegateRewardShareRatio?.toString(),
@@ -725,16 +777,9 @@ export class IOWriteable extends IOReadable implements AoIOWrite {
},
];
- const prunedTags: { name: string; value: string }[] = allTags.filter(
- (tag: {
- name: string;
- value: string | undefined;
- }): tag is { name: string; value: string } => tag.value !== undefined,
- );
-
return this.process.send({
signer: this.signer,
- tags: prunedTags,
+ tags: pruneTags(allTags),
});
}
@@ -749,6 +794,7 @@ export class IOWriteable extends IOReadable implements AoIOWrite {
async updateGatewaySettings(
{
allowDelegatedStaking,
+ allowedDelegates,
delegateRewardShareRatio,
fqdn,
label,
@@ -777,6 +823,10 @@ export class IOWriteable extends IOReadable implements AoIOWrite {
name: 'Allow-Delegated-Staking',
value: allowDelegatedStaking?.toString(),
},
+ {
+ name: 'Allowed-Delegates',
+ value: allowedDelegates?.join(','),
+ },
{
name: 'Delegate-Reward-Share-Ratio',
value: delegateRewardShareRatio?.toString(),
@@ -788,16 +838,9 @@ export class IOWriteable extends IOReadable implements AoIOWrite {
{ name: 'Auto-Stake', value: autoStake?.toString() },
];
- const prunedTags: { name: string; value: string }[] = allTags.filter(
- (tag: {
- name: string;
- value: string | undefined;
- }): tag is { name: string; value: string } => tag.value !== undefined,
- );
-
return this.process.send({
signer: this.signer,
- tags: prunedTags,
+ tags: pruneTags(allTags),
});
}
@@ -824,10 +867,12 @@ export class IOWriteable extends IOReadable implements AoIOWrite {
params: {
target: string;
decreaseQty: number | mIOToken;
+ instant?: boolean;
},
options?: WriteOptions,
): Promise {
const { tags = [] } = options || {};
+
return this.process.send({
signer: this.signer,
tags: [
@@ -835,10 +880,41 @@ export class IOWriteable extends IOReadable implements AoIOWrite {
{ name: 'Action', value: 'Decrease-Delegate-Stake' },
{ name: 'Target', value: params.target },
{ name: 'Quantity', value: params.decreaseQty.valueOf().toString() },
+ { name: 'Instant', value: `${params.instant || false}` },
],
});
}
+ /**
+ * Initiates an instant withdrawal from a gateway.
+ *
+ * @param {Object} params - The parameters for initiating an instant withdrawal
+ * @param {string} params.address - The gateway address of the withdrawal, if not provided, the signer's address will be used
+ * @param {string} params.vaultId - The vault ID of the withdrawal
+ * @returns {Promise} The result of the withdrawal
+ */
+ async instantWithdrawal(
+ params: {
+ gatewayAddress?: string;
+ vaultId: string;
+ },
+ options?: WriteOptions,
+ ): Promise {
+ const { tags = [] } = options || {};
+
+ const allTags = [
+ ...tags,
+ { name: 'Action', value: 'Instant-Withdrawal' },
+ { name: 'Vault-Id', value: params.vaultId },
+ { name: 'Address', value: params.gatewayAddress },
+ ];
+
+ return this.process.send({
+ signer: this.signer,
+ tags: pruneTags(allTags),
+ });
+ }
+
async increaseOperatorStake(
params: {
increaseQty: number | mIOToken;
@@ -917,19 +993,46 @@ export class IOWriteable extends IOReadable implements AoIOWrite {
{ name: 'Purchase-Type', value: params.type || 'lease' },
];
- const prunedTags: { name: string; value: string }[] = allTags.filter(
- (tag: {
- name: string;
- value: string | undefined;
- }): tag is { name: string; value: string } => tag.value !== undefined,
- );
+ return this.process.send({
+ signer: this.signer,
+ tags: pruneTags(allTags),
+ });
+ }
+ /**
+ * Upgrades an existing leased record to a permabuy.
+ *
+ * @param {Object} params - The parameters for upgrading a record
+ * @param {string} params.name - The name of the record to upgrade
+ * @param {Object} [options] - The options for the upgrade
+ * @returns {Promise} The result of the upgrade
+ */
+ async upgradeRecord(
+ params: {
+ name: string;
+ },
+ options?: WriteOptions,
+ ): Promise {
+ const { tags = [] } = options || {};
return this.process.send({
signer: this.signer,
- tags: prunedTags,
+ tags: [
+ ...tags,
+ { name: 'Action', value: 'Upgrade-Name' }, // TODO: align on Update-Record vs. Upgrade-Name (contract currently uses Upgrade-Name)
+ { name: 'Name', value: params.name },
+ ],
});
}
+ /**
+ * Extends the lease of an existing leased record.
+ *
+ * @param {Object} params - The parameters for extending a lease
+ * @param {string} params.name - The name of the record to extend
+ * @param {number} params.years - The number of years to extend the lease
+ * @param {Object} [options] - The options for the extension
+ * @returns {Promise} The result of the extension
+ */
async extendLease(
params: {
name: string;
@@ -968,19 +1071,58 @@ export class IOWriteable extends IOReadable implements AoIOWrite {
});
}
- async cancelDelegateWithdrawal(
- params: { address: string; vaultId: string },
+ /**
+ * Cancel a withdrawal from a gateway.
+ *
+ * @param {Object} params - The parameters for cancelling a withdrawal
+ * @param {string} [params.address] - The address of the withdrawal (optional). If not provided, the signer's address will be used.
+ * @param {string} params.vaultId - The vault ID of the withdrawal.
+ * @param {Object} [options] - The options for the cancellation
+ * @returns {Promise} The result of the cancellation
+ */
+ async cancelWithdrawal(
+ params: { gatewayAddress?: WalletAddress; vaultId: string },
options?: WriteOptions | undefined,
): Promise {
const { tags = [] } = options || {};
+
+ const allTags = [
+ ...tags,
+ { name: 'Action', value: 'Cancel-Withdrawal' },
+ { name: 'Vault-Id', value: params.vaultId },
+ { name: 'Address', value: params.gatewayAddress },
+ ];
+
return this.process.send({
signer: this.signer,
- tags: [
- ...tags,
- { name: 'Action', value: 'Cancel-Delegate-Withdrawal' },
- { name: 'Address', value: params.address },
- { name: 'Vault-Id', value: params.vaultId },
- ],
+ tags: pruneTags(allTags),
+ });
+ }
+
+ async submitAuctionBid(
+ params: {
+ name: string;
+ processId: string;
+ quantity?: number;
+ type?: 'lease' | 'permabuy';
+ years?: number;
+ },
+ options?: WriteOptions,
+ ): Promise {
+ const { tags = [] } = options || {};
+ const allTags = [
+ ...tags,
+ { name: 'Action', value: 'Auction-Bid' },
+ { name: 'Name', value: params.name },
+ { name: 'Process-Id', value: params.processId },
+ { name: 'Quantity', value: params.quantity?.toString() ?? undefined },
+ { name: 'Purchase-Type', value: params.type || 'lease' },
+ { name: 'Years', value: params.years?.toString() ?? undefined },
+ ];
+
+ return this.process.send({
+ signer: this.signer,
+ tags: pruneTags(allTags),
});
}
}
diff --git a/src/node/index.ts b/src/node/index.ts
index a40d0e6c..cd943831 100644
--- a/src/node/index.ts
+++ b/src/node/index.ts
@@ -15,7 +15,7 @@
*/
export { ArweaveSigner, ArconnectSigner } from '@dha-team/arbundles';
-export * from '../types.js';
+export * from '../types/index.js';
export * from '../common/index.js';
export * from '../constants.js';
export * from '../utils/index.js';
diff --git a/src/types/ant-registry.ts b/src/types/ant-registry.ts
new file mode 100644
index 00000000..781bd5b3
--- /dev/null
+++ b/src/types/ant-registry.ts
@@ -0,0 +1,26 @@
+/**
+ * Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { AoMessageResult } from './common.js';
+
+export interface AoANTRegistryRead {
+ accessControlList(params: {
+ address: string;
+ }): Promise<{ Owned: string[]; Controlled: string[] }>;
+}
+
+export interface AoANTRegistryWrite extends AoANTRegistryRead {
+ register(params: { processId: string }): Promise;
+}
diff --git a/src/types/ant.ts b/src/types/ant.ts
new file mode 100644
index 00000000..a2e607ab
--- /dev/null
+++ b/src/types/ant.ts
@@ -0,0 +1,260 @@
+/**
+ * Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { z } from 'zod';
+
+import { ARWEAVE_TX_REGEX } from '../constants.js';
+import { AoMessageResult, WalletAddress, WriteOptions } from './common.js';
+
+/**
+ * example error:
+ * {
+ "code": "custom",
+ "message": "Must be an Arweave Transaction ID",
+ "path": [
+ "Records",
+ "record1",
+ "transactionId"
+ ]
+ },
+ */
+export const ArweaveTxIdSchema = z
+ .string({
+ description: 'Arweave Transaction ID',
+ })
+ .refine((val) => ARWEAVE_TX_REGEX.test(val), {
+ message: 'Must be an Arweave Transaction ID',
+ });
+
+export const IntegerStringSchema = z
+ .string({
+ description: 'Integer String',
+ })
+ .refine(
+ (val) => {
+ const num = parseInt(val);
+ return Number.isInteger(num) && num >= 0;
+ },
+ { message: 'Must be a non negative integer string' },
+ );
+
+export const AntDescriptionSchema = z.string(); // TODO: add specific limits for description ie max length
+export const AntKeywordsSchema = z.array(z.string()); // TODO: add specific limits for keywords ie max amount and max length
+export const AntRecordSchema = z.object({
+ transactionId: ArweaveTxIdSchema.describe('The Target ID of the undername'),
+ ttlSeconds: z.number(),
+});
+export type AoANTRecord = z.infer;
+
+export const AntRecordsSchema = z.record(z.string(), AntRecordSchema);
+export const AntControllersSchema = z.array(
+ ArweaveTxIdSchema.describe('Controller address'),
+);
+export const AntBalancesSchema = z.record(
+ ArweaveTxIdSchema.describe('Holder address'),
+ z.number(),
+);
+
+export const AntStateSchema = z.object({
+ Name: z.string().describe('The name of the ANT.'),
+ Ticker: z.string().describe('The ticker symbol for the ANT.'),
+ Description: z.string().describe('The description for the ANT.'),
+ Keywords: AntKeywordsSchema.describe('The keywords for the ANT.'),
+ Denomination: z
+ .number()
+ .describe(
+ 'The number of decimal places to use for the ANT. Defaults to 0 if not set representing whole numbers.',
+ )
+ .min(0, { message: 'Denomination must be a non-negative number' }),
+ Owner: ArweaveTxIdSchema.describe('The Owners address.'),
+ Controllers: AntControllersSchema.describe(
+ 'Controllers of the ANT who have administrative privileges.',
+ ),
+ Records: AntRecordsSchema.describe('Records associated with the ANT.'),
+ Balances: AntBalancesSchema.describe(
+ 'Balance details for each address holding the ANT.',
+ ),
+ Logo: ArweaveTxIdSchema.describe('Transaction ID of the ANT logo.'),
+ TotalSupply: z
+ .number()
+ .describe('Total supply of the ANT in circulation.')
+ .min(0, { message: 'Total supply must be a non-negative number' }),
+ Initialized: z
+ .boolean()
+ .describe('Flag indicating whether the ANT has been initialized.'),
+ ['Source-Code-TX-ID']: ArweaveTxIdSchema.describe(
+ 'Transaction ID of the Source Code for the ANT.',
+ ),
+});
+
+export type AoANTState = z.infer;
+export const AntHandlerNames = [
+ 'evolve',
+ '_eval',
+ '_default',
+ 'transfer',
+ 'balance',
+ 'balances',
+ 'totalSupply',
+ 'info',
+ 'addController',
+ 'removeController',
+ 'controllers',
+ 'setRecord',
+ 'removeRecord',
+ 'record',
+ 'records',
+ 'setName',
+ 'setTicker',
+ 'setDescription',
+ 'setKeywords',
+ 'initializeState',
+ 'state',
+ 'releaseName',
+ 'reassignName',
+];
+export const AntHandlersSchema = z
+ .array(z.string({ description: 'Handler Name' }))
+ .refine(
+ (antHandlers: string[]) => {
+ return AntHandlerNames.every((handler) => antHandlers.includes(handler));
+ },
+ {
+ message: 'ANT is missing required handlers',
+ },
+ );
+
+export const AntInfoSchema = z.object({
+ Name: z.string().describe('The name of the ANT.'),
+ Owner: ArweaveTxIdSchema.describe('The Owners address.'),
+ ['Source-Code-TX-ID']: ArweaveTxIdSchema.describe(
+ 'Transaction ID of the Source Code for the ANT.',
+ ),
+ Ticker: z.string().describe('The ticker symbol for the ANT.'),
+ ['Total-Supply']: IntegerStringSchema.describe(
+ 'Total supply of the ANT in circulation.',
+ ),
+ Description: AntDescriptionSchema.describe('The description for the ANT.'),
+ Keywords: AntKeywordsSchema.describe('The keywords for the ANT.'),
+
+ Logo: ArweaveTxIdSchema.describe('Transaction ID of the ANT logo.'),
+ Denomination: IntegerStringSchema.describe(
+ 'The number of decimal places to use for the ANT. Defaults to 0 if not set representing whole numbers.',
+ ),
+ Handlers: AntHandlersSchema.optional().describe(
+ 'List of handlers for the ANT.',
+ ),
+ HandlerNames: AntHandlersSchema.optional().describe(
+ 'Deprecated: List of handlers for the ANT. Use "Handlers" instead.',
+ ),
+});
+
+export type AoANTInfo = z.infer;
+
+/**
+ * @param state {object}
+ * @returns {boolean}
+ */
+export function isAoANTState(state: object): state is AoANTState {
+ return AntStateSchema.safeParse(state).success;
+}
+
+export type AntReadOptions = { strict?: boolean };
+
+export interface AoANTRead {
+ getState(opts?: AntReadOptions): Promise;
+ getInfo(opts?: AntReadOptions): Promise;
+ getRecord(
+ { undername }: { undername: string },
+ opts?: AntReadOptions,
+ ): Promise;
+ getRecords(opts?: AntReadOptions): Promise>;
+ getOwner(opts?: AntReadOptions): Promise;
+ getControllers(): Promise;
+ getTicker(opts?: AntReadOptions): Promise;
+ getName(opts?: AntReadOptions): Promise;
+ getBalance(
+ { address }: { address: WalletAddress },
+ opts?: AntReadOptions,
+ ): Promise;
+ getBalances(opts?: AntReadOptions): Promise>;
+}
+
+export interface AoANTWrite extends AoANTRead {
+ transfer(
+ { target }: { target: WalletAddress },
+ options?: WriteOptions,
+ ): Promise;
+ addController(
+ {
+ controller,
+ }: {
+ controller: WalletAddress;
+ },
+ options?: WriteOptions,
+ ): Promise;
+ removeController(
+ {
+ controller,
+ }: {
+ controller: WalletAddress;
+ },
+ options?: WriteOptions,
+ ): Promise;
+ setRecord(
+ {
+ undername,
+ transactionId,
+ ttlSeconds,
+ }: {
+ undername: string;
+ transactionId: string;
+ ttlSeconds: number;
+ },
+ options?: WriteOptions,
+ ): Promise;
+ removeRecord(
+ { undername }: { undername: string },
+ options?: WriteOptions,
+ ): Promise;
+ setTicker(
+ { ticker }: { ticker: string },
+ options?: WriteOptions,
+ ): Promise;
+ setDescription(
+ { description }: { description: string },
+ options?: WriteOptions,
+ ): Promise;
+ setKeywords(
+ { keywords }: { keywords: string[] },
+ options?: WriteOptions,
+ ): Promise;
+ setName(
+ { name }: { name: string },
+ options?: WriteOptions,
+ ): Promise;
+ releaseName(
+ { name, ioProcessId }: { name: string; ioProcessId: string },
+ options?: WriteOptions,
+ ): Promise;
+ reassignName(
+ {
+ name,
+ ioProcessId,
+ antProcessId,
+ }: { name: string; ioProcessId: string; antProcessId: string },
+ options?: WriteOptions,
+ ): Promise;
+}
diff --git a/src/common.ts b/src/types/common.ts
similarity index 87%
rename from src/common.ts
rename to src/types/common.ts
index 528012bf..f2fde650 100644
--- a/src/common.ts
+++ b/src/types/common.ts
@@ -88,3 +88,22 @@ export interface AoClient {
unmonitor: typeof unmonitor;
dryrun: typeof dryrun;
}
+
+export interface AOContract {
+ read({
+ tags,
+ retries,
+ }: {
+ tags?: { name: string; value: string }[];
+ retries?: number;
+ }): Promise;
+ send({
+ tags,
+ data,
+ signer,
+ }: {
+ tags: { name: string; value: string }[];
+ data: string | undefined;
+ signer: AoSigner;
+ }): Promise<{ id: string; result?: K }>;
+}
diff --git a/src/types.ts b/src/types/index.ts
similarity index 92%
rename from src/types.ts
rename to src/types/index.ts
index 249e70eb..2756e096 100644
--- a/src/types.ts
+++ b/src/types/index.ts
@@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+export * from './ant-registry.js';
+export * from './ant.js';
export * from './common.js';
-export * from './token.js';
export * from './io.js';
+export * from './token.js';
diff --git a/src/io.ts b/src/types/io.ts
similarity index 74%
rename from src/io.ts
rename to src/types/io.ts
index 4f87e24f..055b49e4 100644
--- a/src/io.ts
+++ b/src/types/io.ts
@@ -13,11 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { AOProcess } from './common/index.js';
-import { mIOToken } from './token.js';
+import { AOProcess } from '../common/index.js';
+import { validateArweaveId } from '../utils/arweave.js';
import {
AoMessageResult,
- AoSigner,
AtLeastOne,
BlockHeight,
ProcessId,
@@ -25,15 +24,15 @@ import {
TransactionId,
WalletAddress,
WriteOptions,
-} from './types.js';
-import { validateArweaveId } from './utils/arweave.js';
+} from './index.js';
+import { mIOToken } from './token.js';
// Pagination
-export type PaginationParams = {
+export type PaginationParams> = {
cursor?: string;
limit?: number;
- sortBy?: string;
+ sortBy?: keyof T extends never ? string : keyof T; // default to string if T is empty
sortOrder?: 'asc' | 'desc';
};
@@ -41,7 +40,7 @@ export type PaginationResult = {
items: T[];
nextCursor: string | undefined;
totalItems: number;
- sortBy: keyof T;
+ sortBy?: keyof T;
sortOrder: 'asc' | 'desc';
hasMore: boolean;
};
@@ -96,7 +95,7 @@ export type AoEpochObservationData = {
export type AoVaultData = {
balance: number;
- locked: number;
+ startTimestamp: Timestamp;
endTimestamp: Timestamp;
};
@@ -189,10 +188,19 @@ export type AoGatewayServices =
}
| undefined; // not required, for now
+export type AoGatewayDelegates = Record;
+export type AoGatewayDelegateAllowList = WalletAddress[];
+
+export type AoWalletVault = AoVaultData & {
+ address: WalletAddress;
+ vaultId: string;
+};
+
export type AoGateway = {
settings: AoGatewaySettings;
+ // @deprecated - use getGatewayDelegates instead
+ delegates: AoGatewayDelegates;
stats: AoGatewayStats;
- delegates: Record;
totalDelegatedStake: number;
vaults: Record;
startTimestamp: Timestamp;
@@ -240,9 +248,14 @@ export type AoGatewayDelegate = {
vaults: Record;
};
+export type AoGatewayDelegateWithAddress = AoGatewayDelegate & {
+ address: WalletAddress;
+};
+
export type AoGatewaySettings = {
- allowDelegatedStaking: boolean;
+ allowDelegatedStaking: boolean | 'allowlist';
delegateRewardShareRatio: number;
+ allowedDelegates: WalletAddress[];
minDelegatedStake: number;
autoStake: boolean;
label: string;
@@ -258,37 +271,29 @@ export type AoBalanceWithAddress = {
balance: number;
};
-// ANT Contract
-
-export type AoANTState = {
- Name: string;
- Ticker: string;
- Denomination: number;
- Owner: WalletAddress;
- Controllers: WalletAddress[];
- Records: Record;
- Balances: Record;
- Logo: string;
- TotalSupply: number;
- Initialized: boolean;
- ['Source-Code-TX-ID']: string;
+// Auctions
+export type AoAuctionSettings = {
+ durationMs: number;
+ decayRate: number;
+ scalingExponent: number;
+ startPriceMultiplier: number;
};
-export type AoANTInfo = {
- Name: string;
- Owner: string;
- Handlers: string[];
- ['Source-Code-TX-ID']: string;
- // token related
- Ticker: string;
- ['Total-Supply']: string;
- Logo: string;
- Denomination: string;
+export type AoAuction = {
+ name: string;
+ startTimestamp: Timestamp;
+ endTimestamp: Timestamp;
+ initiator: string;
+ baseFee: number;
+ demandFactor: number;
+ settings: AoAuctionSettings;
};
-export type AoANTRecord = {
- transactionId: string;
- ttlSeconds: number;
+export type AoAuctionPriceData = {
+ type: 'lease' | 'permabuy';
+ years?: number;
+ prices: Record;
+ currentPrice: number;
};
// Input types
@@ -304,25 +309,6 @@ export type AoUpdateGatewaySettingsParams = AtLeastOne;
// Interfaces
-export interface AOContract {
- read({
- tags,
- retries,
- }: {
- tags?: { name: string; value: string }[];
- retries?: number;
- }): Promise;
- send({
- tags,
- data,
- signer,
- }: {
- tags: { name: string; value: string }[];
- data: string | undefined;
- signer: AoSigner;
- }): Promise<{ id: string; result?: K }>;
-}
-
export interface AoIORead {
// read interactions
getInfo(): Promise<{
@@ -340,12 +326,25 @@ export interface AoIORead {
}: {
address: WalletAddress;
}): Promise;
+ // TODO: these could be moved to a separate Gateways class that implements gateway specific interactions
+ getGatewayDelegates({
+ address,
+ ...pageParams
+ }: {
+ address: WalletAddress;
+ } & PaginationParams): Promise<
+ PaginationResult
+ >;
+ getGatewayDelegateAllowList(
+ params?: PaginationParams,
+ ): Promise>;
+ // END OF GATEWAY SPECIFIC INTERACTIONS
getGateways(
- params?: PaginationParams,
+ params?: PaginationParams,
): Promise>;
getBalance(params: { address: WalletAddress }): Promise;
getBalances(
- params?: PaginationParams,
+ params?: PaginationParams,
): Promise>;
getArNSRecord({
name,
@@ -353,7 +352,7 @@ export interface AoIORead {
name: string;
}): Promise;
getArNSRecords(
- params?: PaginationParams,
+ params?: PaginationParams,
): Promise>;
getArNSReservedNames(): Promise<
Record | Record
@@ -363,6 +362,23 @@ export interface AoIORead {
}: {
name: string;
}): Promise;
+ getArNSAuctions(
+ params?: PaginationParams,
+ ): Promise>;
+ getArNSAuction({ name }: { name: string }): Promise;
+ getArNSAuctionPrices({
+ name,
+ type,
+ years,
+ timestamp,
+ intervalMs,
+ }: {
+ name: string;
+ type: 'lease' | 'permabuy';
+ years?: number;
+ timestamp?: number;
+ intervalMs?: number;
+ }): Promise;
getEpoch(epoch?: EpochInput): Promise;
getCurrentEpoch(): Promise;
getPrescribedObservers(epoch?: EpochInput): Promise;
@@ -371,19 +387,29 @@ export interface AoIORead {
getDistributions(epoch?: EpochInput): Promise;
getTokenCost({
intent,
- purchaseType,
+ type,
years,
name,
quantity,
}: {
intent: 'Buy-Record' | 'Extend-Lease' | 'Increase-Undername-Limit';
- purchaseType?: 'permabuy' | 'lease';
+ type?: 'permabuy' | 'lease';
years?: number;
name?: string;
quantity?: number;
}): Promise;
getRegistrationFees(): Promise;
getDemandFactor(): Promise;
+ getVaults(
+ params?: PaginationParams,
+ ): Promise>;
+ getVault({
+ address,
+ vaultId,
+ }: {
+ address: WalletAddress;
+ vaultId: string;
+ }): Promise;
}
export interface AoIOWrite extends AoIORead {
@@ -398,38 +424,14 @@ export interface AoIOWrite extends AoIORead {
},
options?: WriteOptions,
): Promise;
+ // TODO: these could be moved to a separate Gateways class that implements gateway specific interactions
joinNetwork(
- {
- operatorStake,
- allowDelegatedStaking,
- delegateRewardShareRatio,
- fqdn,
- label,
- minDelegatedStake,
- note,
- port,
- properties,
- protocol,
- autoStake,
- observerAddress,
- }: AoJoinNetworkParams,
+ params: AoJoinNetworkParams,
options?: WriteOptions,
): Promise;
leaveNetwork(options?: WriteOptions): Promise;
updateGatewaySettings(
- {
- allowDelegatedStaking,
- delegateRewardShareRatio,
- fqdn,
- label,
- minDelegatedStake,
- note,
- port,
- properties,
- protocol,
- autoStake,
- observerAddress,
- }: AoUpdateGatewaySettingsParams,
+ params: AoUpdateGatewaySettingsParams,
options?: WriteOptions,
): Promise;
increaseOperatorStake(
@@ -455,6 +457,14 @@ export interface AoIOWrite extends AoIORead {
params: {
target: WalletAddress;
decreaseQty: number | mIOToken;
+ instant?: boolean;
+ },
+ options?: WriteOptions,
+ ): Promise;
+ instantWithdrawal(
+ params: {
+ gatewayAddress?: WalletAddress;
+ vaultId: string;
},
options?: WriteOptions,
): Promise;
@@ -465,6 +475,7 @@ export interface AoIOWrite extends AoIORead {
},
options?: WriteOptions,
): Promise;
+ // END OF GATEWAY SPECIFIC INTERACTIONS
buyRecord(
params: {
name: string;
@@ -474,6 +485,12 @@ export interface AoIOWrite extends AoIORead {
},
options?: WriteOptions,
): Promise;
+ upgradeRecord(
+ params: {
+ name: string;
+ },
+ options?: WriteOptions,
+ ): Promise;
extendLease(
params: {
name: string;
@@ -488,83 +505,23 @@ export interface AoIOWrite extends AoIORead {
},
options?: WriteOptions,
): Promise;
- cancelDelegateWithdrawal(
+ cancelWithdrawal(
params: {
- address: string;
+ gatewayAddress?: WalletAddress;
vaultId: string;
},
options?: WriteOptions,
): Promise;
-}
-
-export interface AoANTRead {
- getState(): Promise;
- getInfo(): Promise;
- getRecord({ undername }): Promise;
- getRecords(): Promise>;
- getOwner(): Promise;
- getControllers(): Promise;
- getTicker(): Promise;
- getName(): Promise;
- getBalance({ address }: { address: WalletAddress }): Promise;
- getBalances(): Promise>;
-}
-
-export interface AoANTWrite extends AoANTRead {
- transfer(
- { target }: { target: WalletAddress },
- options?: WriteOptions,
- ): Promise;
- addController(
- {
- controller,
- }: {
- controller: WalletAddress;
- },
- options?: WriteOptions,
- ): Promise;
- removeController(
- {
- controller,
- }: {
- controller: WalletAddress;
- },
- options?: WriteOptions,
- ): Promise;
- setRecord(
- {
- undername,
- transactionId,
- ttlSeconds,
- }: {
- undername: string;
- transactionId: string;
- ttlSeconds: number;
+ submitAuctionBid(
+ params: {
+ name: string;
+ processId: string;
+ quantity?: number;
+ type?: 'lease' | 'permabuy';
+ years?: number;
},
options?: WriteOptions,
): Promise;
- removeRecord(
- { undername }: { undername: string },
- options?: WriteOptions,
- ): Promise;
- setTicker(
- { ticker }: { ticker: string },
- options?: WriteOptions,
- ): Promise;
- setName(
- { name }: { name: string },
- options?: WriteOptions,
- ): Promise;
-}
-
-export interface AoANTRegistryRead {
- accessControlList(params: {
- address: string;
- }): Promise<{ Owned: string[]; Controlled: string[] }>;
-}
-
-export interface AoANTRegistryWrite extends AoANTRegistryRead {
- register(params: { processId: string }): Promise;
}
// Typeguard functions
diff --git a/src/token.ts b/src/types/token.ts
similarity index 98%
rename from src/token.ts
rename to src/types/token.ts
index 2ff0ce96..5b932339 100644
--- a/src/token.ts
+++ b/src/types/token.ts
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { MIO_PER_IO } from './constants.js';
+import { MIO_PER_IO } from '../constants.js';
interface Equatable {
equals(other: T): boolean;
diff --git a/src/utils/ao.ts b/src/utils/ao.ts
index b5b6cfc7..ae694186 100644
--- a/src/utils/ao.ts
+++ b/src/utils/ao.ts
@@ -26,14 +26,13 @@ import {
AOS_MODULE_ID,
DEFAULT_SCHEDULER_ID,
} from '../constants.js';
+import { AoANTRecord } from '../types/ant.js';
import {
- AoANTRecord,
- AoANTState,
AoClient,
AoSigner,
ContractSigner,
WalletAddress,
-} from '../types.js';
+} from '../types/index.js';
export async function spawnANT({
signer,
@@ -254,43 +253,3 @@ export function createAoSigner(signer: ContractSigner): AoSigner {
return aoSigner;
}
-
-// using passThrough to require the minimum fields and allow others (eg TotalSupply, Logo, etc)
-export const AntStateSchema = z
- .object({
- Name: z.string(),
- Ticker: z.string(),
- Owner: z.string(),
- Controllers: z.array(z.string()),
- Records: z.record(
- z.string(),
- z
- .object({
- transactionId: z.string(),
- ttlSeconds: z.number(),
- })
- .passthrough(),
- ),
- Balances: z.record(z.string(), z.number()),
- ['Source-Code-TX-ID']: z.string(),
- })
- .passthrough();
-
-/**
- * @param state
- * @returns {boolean}
- * @throws {z.ZodError} if the state object does not match the expected schema
- */
-export function isAoANTState(
- state: object,
- logger: Logger = Logger.default,
-): state is AoANTState {
- try {
- AntStateSchema.parse(state);
- return true;
- } catch (error) {
- // this allows us to see the path of the error in the object as well as the expected schema on invalid fields
- logger.error(error.issues);
- return false;
- }
-}
diff --git a/src/utils/arweave.ts b/src/utils/arweave.ts
index 6d5e3631..36ed72ce 100644
--- a/src/utils/arweave.ts
+++ b/src/utils/arweave.ts
@@ -13,8 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { BlockHeight } from '../common.js';
+import Arweave from 'arweave';
+
import { ARWEAVE_TX_REGEX } from '../constants.js';
+import { BlockHeight, Timestamp } from '../types/common.js';
export const validateArweaveId = (id: string): boolean => {
return ARWEAVE_TX_REGEX.test(id);
@@ -23,3 +25,27 @@ export const validateArweaveId = (id: string): boolean => {
export function isBlockHeight(height: string | number): height is BlockHeight {
return height !== undefined && !isNaN(parseInt(height.toString()));
}
+
+export const pruneTags = (
+ tags: { name: string; value: string | undefined }[],
+): { name: string; value: string }[] => {
+ return tags.filter(
+ (tag: {
+ name: string;
+ value: string | undefined;
+ }): tag is { name: string; value: string } => tag.value !== undefined,
+ );
+};
+
+export const getCurrentBlockUnixTimestampMs = async (
+ arweave: Arweave,
+): Promise => {
+ return await arweave.blocks
+ .getCurrent()
+ .then((block) => {
+ return block.timestamp * 1000;
+ })
+ .catch(() => {
+ return Date.now(); // fallback to current time
+ });
+};
diff --git a/src/utils/index.ts b/src/utils/index.ts
index d7e8dd72..1dae79b6 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -13,8 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-export * from './arweave.js';
-export * from './http-client.js';
export * from './ao.js';
+export * from './arweave.js';
+export * from './base64.js';
export * from './json.js';
export * from './processes.js';
+export * from './schema.js';
diff --git a/src/utils/processes.ts b/src/utils/processes.ts
index 5a8d00f1..1c119dab 100644
--- a/src/utils/processes.ts
+++ b/src/utils/processes.ts
@@ -21,14 +21,14 @@ import { ANT } from '../common/ant.js';
import { IO } from '../common/io.js';
import { ILogger, Logger } from '../common/logger.js';
import { IO_TESTNET_PROCESS_ID } from '../constants.js';
+import { AoANTRegistryRead } from '../types/ant-registry.js';
+import { AoANTState } from '../types/ant.js';
import {
- AoANTRegistryRead,
- AoANTState,
AoArNSNameData,
AoIORead,
ProcessId,
WalletAddress,
-} from '../types.js';
+} from '../types/index.js';
/**
* @beta This API is in beta and may change in the future.
@@ -67,6 +67,7 @@ export class ArNSEventEmitter extends EventEmitter {
private timeoutMs: number; // timeout for each request to 3 seconds
private throttle;
private logger: ILogger;
+ private strict: boolean;
constructor({
contract = IO.init({
processId: IO_TESTNET_PROCESS_ID,
@@ -74,17 +75,20 @@ export class ArNSEventEmitter extends EventEmitter {
timeoutMs = 60_000,
concurrency = 30,
logger = Logger.default,
+ strict = false,
}: {
contract?: AoIORead;
timeoutMs?: number;
concurrency?: number;
logger?: ILogger;
+ strict?: boolean;
} = {}) {
super();
this.contract = contract;
this.timeoutMs = timeoutMs;
this.throttle = pLimit(concurrency);
this.logger = logger;
+ this.strict = strict;
}
async fetchProcessesOwnedByWallet({
@@ -144,6 +148,7 @@ export class ArNSEventEmitter extends EventEmitter {
}
const ant = ANT.init({
processId,
+ strict: this.strict,
});
const state: AoANTState | undefined = (await timeout(
this.timeoutMs,
diff --git a/src/utils/schema.ts b/src/utils/schema.ts
new file mode 100644
index 00000000..5e7bf511
--- /dev/null
+++ b/src/utils/schema.ts
@@ -0,0 +1,30 @@
+/**
+ * Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { z } from 'zod';
+
+/**
+ *
+ * @param schema - zod schema
+ * @param v - value to parse
+ * @throws {z.SafeParseError} - if the value fails to parse
+ */
+export function parseSchemaResult(schema: z.ZodTypeAny, v: unknown) {
+ const schemaResult = schema.safeParse(v);
+ if (!schemaResult.success) {
+ throw new Error(JSON.stringify(schemaResult.error.format(), null, 2));
+ }
+ return schemaResult;
+}
diff --git a/src/version.ts b/src/version.ts
index 493353ea..da4b4698 100644
--- a/src/version.ts
+++ b/src/version.ts
@@ -16,4 +16,4 @@
// AUTOMATICALLY GENERATED FILE - DO NOT TOUCH
-export const version = '2.3.2';
+export const version = '2.4.0-alpha.16';
diff --git a/src/web/index.ts b/src/web/index.ts
index a40d0e6c..cd943831 100644
--- a/src/web/index.ts
+++ b/src/web/index.ts
@@ -15,7 +15,7 @@
*/
export { ArweaveSigner, ArconnectSigner } from '@dha-team/arbundles';
-export * from '../types.js';
+export * from '../types/index.js';
export * from '../common/index.js';
export * from '../constants.js';
export * from '../utils/index.js';
diff --git a/tests/e2e/cjs/index.test.js b/tests/e2e/cjs/index.test.js
index 5895da96..7af75f4b 100644
--- a/tests/e2e/cjs/index.test.js
+++ b/tests/e2e/cjs/index.test.js
@@ -30,343 +30,383 @@ const signers = [
createAoSigner(new ArweaveSigner(testWallet)),
];
+const aoClient = connect({
+ CU_URL: 'http://localhost:6363',
+});
+
const io = IO.init({
process: new AOProcess({
processId: process.env.IO_PROCESS_ID || ioDevnetProcessId,
- ao: connect({
- CU_URL: 'http://localhost:6363',
- }),
+ ao: aoClient,
}),
});
-describe('IO', async () => {
- let compose;
- before(async () => {
- compose = await new DockerComposeEnvironment(
- projectRootPath,
- '../docker-compose.test.yml',
- )
- .withBuild()
- .withWaitStrategy('ao-cu-1', Wait.forHttp('/', 6363))
- .up(['ao-cu']);
- });
+describe('e2e cjs tests', async () => {
+ describe('IO', async () => {
+ let compose;
+ before(async () => {
+ compose = await new DockerComposeEnvironment(
+ projectRootPath,
+ '../docker-compose.test.yml',
+ )
+ .withBuild()
+ .withWaitStrategy('ao-cu-1', Wait.forHttp('/', 6363))
+ .up(['ao-cu']);
+ });
- after(async () => {
- await compose.down();
- });
- it('should be able to get the process information', async () => {
- const epoch = await io.getInfo();
- assert.ok(epoch);
- });
+ after(async () => {
+ await compose.down();
+ });
+ it('should be able to get the process information', async () => {
+ const epoch = await io.getInfo();
+ assert.ok(epoch);
+ });
- it('should be able to get the total token supply', async () => {
- const tokenSupply = await io.getTokenSupply();
- assert.ok(tokenSupply);
- });
+ it('should be able to get the total token supply', async () => {
+ const tokenSupply = await io.getTokenSupply();
+ assert.ok(tokenSupply);
+ });
- it('should be able to get first set of arns records', async () => {
- const records = await io.getArNSRecords();
- assert.ok(records);
- assert(records.limit === 100);
- assert(records.sortOrder === 'desc');
- assert(records.sortBy === 'startTimestamp');
- assert(typeof records.totalItems === 'number');
- assert(typeof records.sortBy === 'string');
- assert(typeof records.sortOrder === 'string');
- assert(typeof records.limit === 'number');
- assert(typeof records.hasMore === 'boolean');
- if (records.nextCursor) {
- assert(typeof records.nextCursor === 'string');
- }
- assert(Array.isArray(records.items));
- records.items.forEach((record) => {
- assert(typeof record.processId === 'string');
- assert(typeof record.name === 'string');
- assert(typeof record.startTimestamp === 'number');
- assert(['lease', 'permabuy'].includes(record.type));
- assert(typeof record.undernameLimit === 'number');
+ it('should be able to get first set of arns records', async () => {
+ const records = await io.getArNSRecords();
+ assert.ok(records);
+ assert(records.limit === 100);
+ assert(records.sortOrder === 'desc');
+ assert(records.sortBy === 'startTimestamp');
+ assert(typeof records.totalItems === 'number');
+ assert(typeof records.sortBy === 'string');
+ assert(typeof records.sortOrder === 'string');
+ assert(typeof records.limit === 'number');
+ assert(typeof records.hasMore === 'boolean');
+ if (records.nextCursor) {
+ assert(typeof records.nextCursor === 'string');
+ }
+ assert(Array.isArray(records.items));
+ records.items.forEach((record) => {
+ assert(typeof record.processId === 'string');
+ assert(typeof record.name === 'string');
+ assert(typeof record.startTimestamp === 'number');
+ assert(['lease', 'permabuy'].includes(record.type));
+ assert(typeof record.undernameLimit === 'number');
+ });
});
- });
- it('should be able to return a specific page of arns records', async () => {
- const records = await io.getArNSRecords({
- cursor: 'ardrive',
- limit: 5,
- sortOrder: 'desc',
- sortBy: 'name',
+ it('should be able to return a specific page of arns records', async () => {
+ const records = await io.getArNSRecords({
+ cursor: 'ardrive',
+ limit: 5,
+ sortOrder: 'desc',
+ sortBy: 'name',
+ });
+ assert.ok(records);
+ assert(records.limit === 5);
+ assert(records.sortOrder === 'desc');
+ assert(records.sortBy === 'name');
+ assert(typeof records.totalItems === 'number');
+ assert(typeof records.sortBy === 'string');
+ assert(typeof records.sortOrder === 'string');
+ assert(typeof records.limit === 'number');
+ assert(typeof records.hasMore === 'boolean');
+ if (records.nextCursor) {
+ assert(typeof records.nextCursor === 'string');
+ }
+ assert(Array.isArray(records.items));
+ records.items.forEach((record) => {
+ assert(typeof record.processId === 'string');
+ assert(typeof record.name === 'string');
+ assert(typeof record.startTimestamp === 'number');
+ assert(['lease', 'permabuy'].includes(record.type));
+ assert(typeof record.undernameLimit === 'number');
+ });
});
- assert.ok(records);
- assert(records.limit === 5);
- assert(records.sortOrder === 'desc');
- assert(records.sortBy === 'name');
- assert(typeof records.totalItems === 'number');
- assert(typeof records.sortBy === 'string');
- assert(typeof records.sortOrder === 'string');
- assert(typeof records.limit === 'number');
- assert(typeof records.hasMore === 'boolean');
- if (records.nextCursor) {
- assert(typeof records.nextCursor === 'string');
- }
- assert(Array.isArray(records.items));
- records.items.forEach((record) => {
- assert(typeof record.processId === 'string');
- assert(typeof record.name === 'string');
- assert(typeof record.startTimestamp === 'number');
- assert(['lease', 'permabuy'].includes(record.type));
- assert(typeof record.undernameLimit === 'number');
+ it('should be able to get a single arns record', async () => {
+ const arns = await io.getArNSRecord({ name: 'ardrive' });
+ assert.ok(arns);
});
- });
- it('should be able to get a single arns record', async () => {
- const arns = await io.getArNSRecord({ name: 'ardrive' });
- assert.ok(arns);
- });
- it('should be able to get the current epoch using getCurrentEpoch', async () => {
- const epoch = await io.getCurrentEpoch();
- assert.ok(epoch);
- });
-
- it('should be able to get the current epoch using getEpoch', async () => {
- const epoch = await io.getEpoch({ epochIndex: 0 });
- assert.ok(epoch);
- });
+ it('should be able to get the current epoch using getCurrentEpoch', async () => {
+ const epoch = await io.getCurrentEpoch();
+ assert.ok(epoch);
+ });
- it('should be able to get epoch-settings', async () => {
- const epochSettings = await io.getEpochSettings();
- assert.ok(epochSettings);
- });
+ it('should be able to get the current epoch using getEpoch', async () => {
+ const epoch = await io.getEpoch({ epochIndex: 0 });
+ assert.ok(epoch);
+ });
- it('should be able to get reserved names', async () => {
- const reservedNames = await io.getArNSReservedNames();
- assert.ok(reservedNames);
- });
+ it('should be able to get epoch-settings', async () => {
+ const epochSettings = await io.getEpochSettings();
+ assert.ok(epochSettings);
+ });
- it('should be able to get a single reserved name', async () => {
- const reservedNames = await io.getArNSReservedNames({ name: 'www ' });
- assert.ok(reservedNames);
- });
+ it('should be able to get reserved names', async () => {
+ const reservedNames = await io.getArNSReservedNames();
+ assert.ok(reservedNames);
+ });
- it('should be able to get first page of gateways', async () => {
- const gateways = await io.getGateways();
- assert.ok(gateways);
- assert(gateways.limit === 100);
- assert(gateways.sortOrder === 'desc');
- assert(gateways.sortBy === 'startTimestamp');
- assert(typeof gateways.totalItems === 'number');
- assert(typeof gateways.sortBy === 'string');
- assert(typeof gateways.sortOrder === 'string');
- assert(typeof gateways.limit === 'number');
- assert(typeof gateways.hasMore === 'boolean');
- if (gateways.nextCursor) {
- assert(typeof gateways.nextCursor === 'string');
- }
- assert(Array.isArray(gateways.items));
- gateways.items.forEach((gateway) => {
- assert(typeof gateway.gatewayAddress === 'string');
- assert(typeof gateway.observerAddress === 'string');
- assert(typeof gateway.startTimestamp === 'number');
- assert(typeof gateway.operatorStake === 'number');
- assert(typeof gateway.totalDelegatedStake === 'number');
- assert(typeof gateway.settings === 'object');
- assert(typeof gateway.weights === 'object');
- assert(typeof gateway.weights.normalizedCompositeWeight === 'number');
- assert(typeof gateway.weights.compositeWeight === 'number');
- assert(typeof gateway.weights.stakeWeight === 'number');
- assert(typeof gateway.weights.tenureWeight === 'number');
- assert(typeof gateway.weights.observerRewardRatioWeight === 'number');
- assert(typeof gateway.weights.gatewayRewardRatioWeight === 'number');
+ it('should be able to get a single reserved name', async () => {
+ const reservedNames = await io.getArNSReservedNames({ name: 'www ' });
+ assert.ok(reservedNames);
});
- });
- it('should be able to get a specific page of gateways', async () => {
- const gateways = await io.getGateways({
- cursor: 1000000,
- limit: 1,
- sortBy: 'operatorStake',
- sortOrder: 'desc',
+ it('should be able to get first page of gateways', async () => {
+ const gateways = await io.getGateways();
+ assert.ok(gateways);
+ assert(gateways.limit === 100);
+ assert(gateways.sortOrder === 'desc');
+ assert(gateways.sortBy === 'startTimestamp');
+ assert(typeof gateways.totalItems === 'number');
+ assert(typeof gateways.sortBy === 'string');
+ assert(typeof gateways.sortOrder === 'string');
+ assert(typeof gateways.limit === 'number');
+ assert(typeof gateways.hasMore === 'boolean');
+ if (gateways.nextCursor) {
+ assert(typeof gateways.nextCursor === 'string');
+ }
+ assert(Array.isArray(gateways.items));
+ gateways.items.forEach((gateway) => {
+ assert(typeof gateway.gatewayAddress === 'string');
+ assert(typeof gateway.observerAddress === 'string');
+ assert(typeof gateway.startTimestamp === 'number');
+ assert(typeof gateway.operatorStake === 'number');
+ assert(typeof gateway.totalDelegatedStake === 'number');
+ assert(typeof gateway.settings === 'object');
+ assert(typeof gateway.weights === 'object');
+ assert(typeof gateway.weights.normalizedCompositeWeight === 'number');
+ assert(typeof gateway.weights.compositeWeight === 'number');
+ assert(typeof gateway.weights.stakeWeight === 'number');
+ assert(typeof gateway.weights.tenureWeight === 'number');
+ assert(typeof gateway.weights.observerRewardRatioWeight === 'number');
+ assert(typeof gateway.weights.gatewayRewardRatioWeight === 'number');
+ });
});
- assert.ok(gateways);
- assert(gateways.limit === 1);
- assert(gateways.sortOrder === 'desc');
- assert(gateways.sortBy === 'operatorStake');
- assert(typeof gateways.totalItems === 'number');
- assert(typeof gateways.sortBy === 'string');
- assert(typeof gateways.sortOrder === 'string');
- assert(typeof gateways.limit === 'number');
- assert(typeof gateways.hasMore === 'boolean');
- if (gateways.nextCursor) {
- assert(typeof gateways.nextCursor === 'string');
- }
- assert(Array.isArray(gateways.items));
- gateways.items.forEach((gateway) => {
- assert(typeof gateway.gatewayAddress === 'string');
- assert(typeof gateway.observerAddress === 'string');
- assert(typeof gateway.startTimestamp === 'number');
- assert(typeof gateway.operatorStake === 'number');
- assert(typeof gateway.totalDelegatedStake === 'number');
- assert(typeof gateway.settings === 'object');
- assert(typeof gateway.weights === 'object');
- assert(typeof gateway.weights.normalizedCompositeWeight === 'number');
- assert(typeof gateway.weights.compositeWeight === 'number');
- assert(typeof gateway.weights.stakeWeight === 'number');
- assert(typeof gateway.weights.tenureWeight === 'number');
- assert(typeof gateway.weights.observerRewardRatioWeight === 'number');
- assert(typeof gateway.weights.gatewayRewardRatioWeight === 'number');
+
+ it('should be able to get a specific page of gateways', async () => {
+ const gateways = await io.getGateways({
+ cursor: 1000000,
+ limit: 1,
+ sortBy: 'operatorStake',
+ sortOrder: 'desc',
+ });
+ assert.ok(gateways);
+ assert(gateways.limit === 1);
+ assert(gateways.sortOrder === 'desc');
+ assert(gateways.sortBy === 'operatorStake');
+ assert(typeof gateways.totalItems === 'number');
+ assert(typeof gateways.sortBy === 'string');
+ assert(typeof gateways.sortOrder === 'string');
+ assert(typeof gateways.limit === 'number');
+ assert(typeof gateways.hasMore === 'boolean');
+ if (gateways.nextCursor) {
+ assert(typeof gateways.nextCursor === 'string');
+ }
+ assert(Array.isArray(gateways.items));
+ gateways.items.forEach((gateway) => {
+ assert(typeof gateway.gatewayAddress === 'string');
+ assert(typeof gateway.observerAddress === 'string');
+ assert(typeof gateway.startTimestamp === 'number');
+ assert(typeof gateway.operatorStake === 'number');
+ assert(typeof gateway.totalDelegatedStake === 'number');
+ assert(typeof gateway.settings === 'object');
+ assert(typeof gateway.weights === 'object');
+ assert(typeof gateway.weights.normalizedCompositeWeight === 'number');
+ assert(typeof gateway.weights.compositeWeight === 'number');
+ assert(typeof gateway.weights.stakeWeight === 'number');
+ assert(typeof gateway.weights.tenureWeight === 'number');
+ assert(typeof gateway.weights.observerRewardRatioWeight === 'number');
+ assert(typeof gateway.weights.gatewayRewardRatioWeight === 'number');
+ });
});
- });
- it('should be able to get a single gateway', async () => {
- const gateways = await io.getGateway({
- address: 'QGWqtJdLLgm2ehFWiiPzMaoFLD50CnGuzZIPEdoDRGQ',
+ it('should be able to get a single gateway', async () => {
+ const gateways = await io.getGateway({
+ address: 'QGWqtJdLLgm2ehFWiiPzMaoFLD50CnGuzZIPEdoDRGQ',
+ });
+ assert.ok(gateways);
});
- assert.ok(gateways);
- });
- it('should be able to get balances, defaulting to first page', async () => {
- const balances = await io.getBalances();
- assert.ok(balances);
- assert(balances.limit === 100);
- assert(balances.sortOrder === 'desc');
- assert(balances.sortBy === 'balance');
- assert(typeof balances.totalItems === 'number');
- assert(typeof balances.sortBy === 'string');
- assert(typeof balances.sortOrder === 'string');
- assert(typeof balances.limit === 'number');
- assert(typeof balances.hasMore === 'boolean');
- if (balances.nextCursor) {
- assert(typeof gateways.nextCursor === 'string');
- }
- assert(Array.isArray(balances.items));
- balances.items.forEach((wallet) => {
- assert(typeof wallet.address === 'string');
- assert(typeof wallet.balance === 'number');
+ it('should be able to get balances, defaulting to first page', async () => {
+ const balances = await io.getBalances();
+ assert.ok(balances);
+ assert(balances.limit === 100);
+ assert(balances.sortOrder === 'desc');
+ assert(balances.sortBy === 'balance');
+ assert(typeof balances.totalItems === 'number');
+ assert(typeof balances.sortBy === 'string');
+ assert(typeof balances.sortOrder === 'string');
+ assert(typeof balances.limit === 'number');
+ assert(typeof balances.hasMore === 'boolean');
+ if (balances.nextCursor) {
+ assert(typeof gateways.nextCursor === 'string');
+ }
+ assert(Array.isArray(balances.items));
+ balances.items.forEach((wallet) => {
+ assert(typeof wallet.address === 'string');
+ assert(typeof wallet.balance === 'number');
+ });
});
- });
- it('should be able to get balances of a specific to first page', async () => {
- const balances = await io.getBalances({
- cursor: 1000000,
- limit: 1,
- sortBy: 'address',
- sortOrder: 'asc',
+ it('should be able to get balances of a specific to first page', async () => {
+ const balances = await io.getBalances({
+ cursor: 1000000,
+ limit: 1,
+ sortBy: 'address',
+ sortOrder: 'asc',
+ });
+ assert.ok(balances);
+ assert(balances.limit === 1);
+ assert(balances.sortOrder === 'asc');
+ assert(balances.sortBy === 'address');
+ assert(typeof balances.totalItems === 'number');
+ assert(typeof balances.sortBy === 'string');
+ assert(typeof balances.sortOrder === 'string');
+ assert(typeof balances.limit === 'number');
+ assert(typeof balances.hasMore === 'boolean');
+ if (balances.nextCursor) {
+ assert(typeof balances.nextCursor === 'string');
+ }
+ assert(Array.isArray(balances.items));
+ balances.items.forEach((wallet) => {
+ assert(typeof wallet.address === 'string');
+ assert(typeof wallet.balance === 'number');
+ });
});
- assert.ok(balances);
- assert(balances.limit === 1);
- assert(balances.sortOrder === 'asc');
- assert(balances.sortBy === 'address');
- assert(typeof balances.totalItems === 'number');
- assert(typeof balances.sortBy === 'string');
- assert(typeof balances.sortOrder === 'string');
- assert(typeof balances.limit === 'number');
- assert(typeof balances.hasMore === 'boolean');
- if (balances.nextCursor) {
- assert(typeof balances.nextCursor === 'string');
- }
- assert(Array.isArray(balances.items));
- balances.items.forEach((wallet) => {
- assert(typeof wallet.address === 'string');
- assert(typeof wallet.balance === 'number');
+
+ it('should be able to get a single balance', async () => {
+ const balances = await io.getBalance({
+ address: 'QGWqtJdLLgm2ehFWiiPzMaoFLD50CnGuzZIPEdoDRGQ',
+ });
+ assert.ok(balances);
});
- });
- it('should be able to get a single balance', async () => {
- const balances = await io.getBalance({
- address: 'QGWqtJdLLgm2ehFWiiPzMaoFLD50CnGuzZIPEdoDRGQ',
+ it('should be able to get prescribed names', async () => {
+ const prescribedNames = await io.getPrescribedNames();
+ assert.ok(prescribedNames);
});
- assert.ok(balances);
- });
- it('should be able to get prescribed names', async () => {
- const prescribedNames = await io.getPrescribedNames();
- assert.ok(prescribedNames);
- });
+ it('should return the prescribed observers for a given epoch', async () => {
+ const observers = await io.getPrescribedObservers();
+ assert.ok(observers);
+ for (const observer of observers) {
+ assert(typeof observer.gatewayAddress === 'string');
+ assert(typeof observer.observerAddress === 'string');
+ assert(typeof observer.stake === 'number');
+ assert(typeof observer.startTimestamp === 'number');
+ assert(typeof observer.stakeWeight === 'number');
+ assert(typeof observer.tenureWeight === 'number');
+ assert(typeof observer.gatewayRewardRatioWeight === 'number');
+ assert(typeof observer.observerRewardRatioWeight === 'number');
+ assert(typeof observer.compositeWeight === 'number');
+ }
+ });
- it('should return the prescribed observers for a given epoch', async () => {
- const observers = await io.getPrescribedObservers();
- assert.ok(observers);
- for (const observer of observers) {
- assert(typeof observer.gatewayAddress === 'string');
- assert(typeof observer.observerAddress === 'string');
- assert(typeof observer.stake === 'number');
- assert(typeof observer.startTimestamp === 'number');
- assert(typeof observer.stakeWeight === 'number');
- assert(typeof observer.tenureWeight === 'number');
- assert(typeof observer.gatewayRewardRatioWeight === 'number');
- assert(typeof observer.observerRewardRatioWeight === 'number');
- assert(typeof observer.compositeWeight === 'number');
- }
- });
+ it('should be able to get token cost for leasing a name', async () => {
+ const tokenCost = await io.getTokenCost({
+ intent: 'Buy-Record',
+ name: 'new-name',
+ years: 1,
+ });
+ assert.ok(tokenCost);
+ });
- it('should be able to get token cost for leasing a name', async () => {
- const tokenCost = await io.getTokenCost({
- intent: 'Buy-Record',
- name: 'new-name',
- years: 1,
+ it('should be able to get token cost for buying a name name', async () => {
+ const tokenCost = await io.getTokenCost({
+ intent: 'Buy-Record',
+ name: 'new-name',
+ type: 'permabuy',
+ });
+ assert.ok(tokenCost);
});
- assert.ok(tokenCost);
- });
- it('should be able to get token cost for buying a name name', async () => {
- const tokenCost = await io.getTokenCost({
- intent: 'Buy-Record',
- name: 'new-name',
- type: 'permabuy',
+ it('should be able to get registration fees', async () => {
+ const registrationFees = await io.getRegistrationFees();
+ assert(registrationFees);
+ assert.equal(Object.keys(registrationFees).length, 51);
+ for (const nameLength of Object.keys(registrationFees)) {
+ // assert lease is length of 5
+ assert(registrationFees[nameLength]['lease']['1'] > 0);
+ assert(registrationFees[nameLength]['lease']['2'] > 0);
+ assert(registrationFees[nameLength]['lease']['3'] > 0);
+ assert(registrationFees[nameLength]['lease']['4'] > 0);
+ assert(registrationFees[nameLength]['lease']['5'] > 0);
+ assert(registrationFees[nameLength]['permabuy'] > 0);
+ }
});
- assert.ok(tokenCost);
- });
+ it('should be able to create IOWriteable with valid signers', async () => {
+ for (const signer of signers) {
+ const io = IO.init({ signer });
- it('should be able to get registration fees', async () => {
- const registrationFees = await io.getRegistrationFees();
- assert(registrationFees);
- assert.equal(Object.keys(registrationFees).length, 51);
- for (const nameLength of Object.keys(registrationFees)) {
- // assert lease is length of 5
- assert(registrationFees[nameLength]['lease']['1'] > 0);
- assert(registrationFees[nameLength]['lease']['2'] > 0);
- assert(registrationFees[nameLength]['lease']['3'] > 0);
- assert(registrationFees[nameLength]['lease']['4'] > 0);
- assert(registrationFees[nameLength]['lease']['5'] > 0);
- assert(registrationFees[nameLength]['permabuy'] > 0);
- }
- });
- it('should be able to create IOWriteable with valid signers', async () => {
- for (const signer of signers) {
- const io = IO.init({ signer });
+ assert(io instanceof IOWriteable);
+ }
+ });
- assert(io instanceof IOWriteable);
- }
+ it('should be able to get paginated vaults', async () => {
+ const vaults = await io.getVaults();
+ assert.ok(vaults);
+ assert(vaults.limit === 100);
+ assert(vaults.sortOrder === 'desc');
+ assert(vaults.sortBy === 'address');
+ assert(typeof vaults.totalItems === 'number');
+ assert(typeof vaults.sortBy === 'string');
+ assert(typeof vaults.sortOrder === 'string');
+ assert(typeof vaults.limit === 'number');
+ assert(typeof vaults.hasMore === 'boolean');
+ if (vaults.nextCursor) {
+ assert(typeof vaults.nextCursor === 'string');
+ }
+ assert(Array.isArray(vaults.items));
+ vaults.items.forEach(
+ ({ address, vaultId, balance, endTimestamp, startTimestamp }) => {
+ assert(typeof address === 'string');
+ assert(typeof balance === 'number');
+ assert(typeof startTimestamp === 'number');
+ assert(typeof endTimestamp === 'number');
+ assert(typeof vaultId === 'string');
+ },
+ );
+ });
});
-});
-describe('ANTRegistry', async () => {
- const registry = ANTRegistry.init();
- const address = '7waR8v4STuwPnTck1zFVkQqJh5K9q9Zik4Y5-5dV7nk';
+ describe('ANTRegistry', async () => {
+ const registry = ANTRegistry.init();
+ const address = '7waR8v4STuwPnTck1zFVkQqJh5K9q9Zik4Y5-5dV7nk';
- it('should retrieve ids from registry', async () => {
- const affiliatedAnts = await registry.accessControlList({ address });
- assert(Array.isArray(affiliatedAnts.Owned));
- assert(Array.isArray(affiliatedAnts.Controlled));
- });
+ it('should retrieve ids from registry', async () => {
+ const affiliatedAnts = await registry.accessControlList({ address });
+ assert(Array.isArray(affiliatedAnts.Owned));
+ assert(Array.isArray(affiliatedAnts.Controlled));
+ });
- it('should be able to create AoANTRegistryWriteable with valid signers', async () => {
- for (const signer of signers) {
- const registry = ANTRegistry.init({
- signer,
- });
- assert(registry instanceof AoANTRegistryWriteable);
- }
+ it('should be able to create AoANTRegistryWriteable with valid signers', async () => {
+ for (const signer of signers) {
+ const registry = ANTRegistry.init({
+ signer,
+ });
+ assert(registry instanceof AoANTRegistryWriteable);
+ }
+ });
});
-});
-describe('ANT', async () => {
- it('should be able to create ANTWriteable with valid signers', async () => {
- for (const signer of signers) {
- const ant = ANT.init({
- processId: 'aWI_dq1JH7facsulLuas1X3l5dkKuWtixcZDYMw9mpg',
- signer,
- });
+ describe('ANT', async () => {
+ const processId = 'YcxE5IbqZYK72H64ELoysxiJ-0wb36deYPv55wgl8xo';
+ it('should be able to create ANTWriteable with valid signers', async () => {
+ for (const signer of signers) {
+ const ant = ANT.init({
+ processId,
+ signer,
+ strict: true,
+ ao: aoClient,
+ });
+ const strictAnt = ANT.init({
+ processId,
+ signer,
+ strict: true,
+ ao: aoClient,
+ });
- assert(ant instanceof AoANTWriteable);
- }
+ assert(ant instanceof AoANTWriteable);
+ assert(strictAnt instanceof AoANTWriteable);
+ }
+ });
});
});
diff --git a/tests/e2e/cjs/yarn.lock b/tests/e2e/cjs/yarn.lock
index 46d05d90..1d96fcbf 100644
--- a/tests/e2e/cjs/yarn.lock
+++ b/tests/e2e/cjs/yarn.lock
@@ -785,10 +785,10 @@ elliptic@6.5.4:
minimalistic-assert "^1.0.1"
minimalistic-crypto-utils "^1.0.1"
-elliptic@^6.5.4:
- version "6.5.5"
- resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.5.tgz"
- integrity sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==
+elliptic@^6.5.7:
+ version "6.5.7"
+ resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.7.tgz#8ec4da2cb2939926a1b9a73619d768207e647c8b"
+ integrity sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==
dependencies:
bn.js "^4.11.9"
brorand "^1.1.0"
@@ -1289,11 +1289,11 @@ scrypt-js@3.0.1:
integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==
secp256k1@^5.0.0:
- version "5.0.0"
- resolved "https://registry.npmjs.org/secp256k1/-/secp256k1-5.0.0.tgz"
- integrity sha512-TKWX8xvoGHrxVdqbYeZM9w+izTF4b9z3NhSaDkdn81btvuh+ivbIMGT/zQvDtTFWhRlThpoz6LEYTr7n8A5GcA==
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-5.0.1.tgz#dc2c86187d48ff2da756f0f7e96417ee03c414b1"
+ integrity sha512-lDFs9AAIaWP9UCdtWrotXWWF9t8PWgQDcxqgAnpM9rMqxb3Oaq2J0thzPVSxBwdJgyQtkU/sYtFtbM1RSt/iYA==
dependencies:
- elliptic "^6.5.4"
+ elliptic "^6.5.7"
node-addon-api "^5.0.0"
node-gyp-build "^4.2.0"
diff --git a/tests/e2e/esm/index.test.js b/tests/e2e/esm/index.test.js
index 24bbdc3d..db0709c9 100644
--- a/tests/e2e/esm/index.test.js
+++ b/tests/e2e/esm/index.test.js
@@ -1,6 +1,7 @@
import {
ANT,
ANTRegistry,
+ ANT_REGISTRY_ID,
AOProcess,
AoANTRegistryWriteable,
AoANTWriteable,
@@ -32,16 +33,18 @@ const signers = [
* (simply running npm run test:integration will ensure npm link is ran)
*/
+const aoClient = connect({
+ CU_URL: 'http://localhost:6363',
+});
+
const io = IO.init({
process: new AOProcess({
processId: ioDevnetProcessId,
- ao: connect({
- CU_URL: 'http://localhost:6363',
- }),
+ ao: aoClient,
}),
});
-describe('IO', async () => {
+describe('e2e esm tests', async () => {
let compose;
before(async () => {
compose = await new DockerComposeEnvironment(
@@ -57,410 +60,571 @@ describe('IO', async () => {
await compose.down();
});
- it('should be able to get the process information', async () => {
- const info = await io.getInfo();
- assert.ok(info);
- assert(typeof info.Name === 'string');
- assert(typeof info.Ticker === 'string');
- assert(typeof info.Logo === 'string');
- assert(typeof info.Denomination === 'number');
- assert(Array.isArray(info.Handlers));
- assert(typeof info.LastTickedEpochIndex === 'number');
- });
+ describe('IO', async () => {
+ it('should be able to get the process information', async () => {
+ const info = await io.getInfo();
+ assert.ok(info);
+ assert(typeof info.Name === 'string');
+ assert(typeof info.Ticker === 'string');
+ assert(typeof info.Logo === 'string');
+ assert(typeof info.Denomination === 'number');
+ assert(Array.isArray(info.Handlers));
+ assert(typeof info.LastTickedEpochIndex === 'number');
+ });
- it('should be able to get the total token supply', async () => {
- const tokenSupply = await io.getTokenSupply();
- assert.ok(tokenSupply);
- assert(typeof tokenSupply.total === 'number');
- assert(typeof tokenSupply.circulating === 'number');
- assert(typeof tokenSupply.locked === 'number');
- assert(typeof tokenSupply.withdrawn === 'number');
- assert(typeof tokenSupply.delegated === 'number');
- assert(typeof tokenSupply.staked === 'number');
- assert(typeof tokenSupply.protocolBalance === 'number');
- });
+ it('should be able to return a specific page of arns records', async () => {
+ const records = await io.getArNSRecords({
+ cursor: 'ardrive',
+ limit: 5,
+ sortOrder: 'desc',
+ sortBy: 'name',
+ });
+ assert.ok(records);
+ assert(records.limit === 5);
+ assert(records.sortOrder === 'desc');
+ assert(records.sortBy === 'name');
+ assert(typeof records.totalItems === 'number');
+ assert(typeof records.sortBy === 'string');
+ assert(typeof records.sortOrder === 'string');
+ assert(typeof records.limit === 'number');
+ assert(typeof records.hasMore === 'boolean');
+ if (records.nextCursor) {
+ assert(typeof records.nextCursor === 'string');
+ }
+ assert(Array.isArray(records.items));
+ records.items.forEach((record) => {
+ assert(typeof record.processId === 'string');
+ assert(typeof record.name === 'string');
+ assert(typeof record.startTimestamp === 'number');
+ assert(['lease', 'permabuy'].includes(record.type));
+ assert(typeof record.undernameLimit === 'number');
+ });
+ });
+ it('should be able to get a single arns record', async () => {
+ const arns = await io.getArNSRecord({ name: 'ardrive' });
+ assert.ok(arns);
+ });
- it('should be able to get first set of arns records', async () => {
- const records = await io.getArNSRecords();
- assert.ok(records);
- assert(records.limit === 100);
- assert(records.sortOrder === 'desc');
- assert(records.sortBy === 'startTimestamp');
- assert(typeof records.totalItems === 'number');
- assert(typeof records.sortBy === 'string');
- assert(typeof records.sortOrder === 'string');
- assert(typeof records.limit === 'number');
- assert(typeof records.hasMore === 'boolean');
- if (records.nextCursor) {
- assert(typeof records.nextCursor === 'string');
- }
- assert(Array.isArray(records.items));
- records.items.forEach((record) => {
- assert(typeof record.processId === 'string');
- assert(typeof record.name === 'string');
- assert(typeof record.startTimestamp === 'number');
- assert(['lease', 'permabuy'].includes(record.type));
- assert(typeof record.undernameLimit === 'number');
+ it('should be able to get the current epoch', async () => {
+ const epoch = await io.getCurrentEpoch();
+ assert.ok(epoch);
});
- });
- it('should be able to return a specific page of arns records', async () => {
- const records = await io.getArNSRecords({
- cursor: 'ardrive',
- limit: 5,
- sortOrder: 'desc',
- sortBy: 'name',
- });
- assert.ok(records);
- assert(records.limit === 5);
- assert(records.sortOrder === 'desc');
- assert(records.sortBy === 'name');
- assert(typeof records.totalItems === 'number');
- assert(typeof records.sortBy === 'string');
- assert(typeof records.sortOrder === 'string');
- assert(typeof records.limit === 'number');
- assert(typeof records.hasMore === 'boolean');
- if (records.nextCursor) {
- assert(typeof records.nextCursor === 'string');
- }
- assert(Array.isArray(records.items));
- records.items.forEach((record) => {
- assert(typeof record.processId === 'string');
- assert(typeof record.name === 'string');
- assert(typeof record.startTimestamp === 'number');
- assert(['lease', 'permabuy'].includes(record.type));
- assert(typeof record.undernameLimit === 'number');
+ it('should be able to get epoch-settings', async () => {
+ const epochSettings = await io.getEpochSettings();
+ assert.ok(epochSettings);
});
- });
- it('should be able to get a single arns record', async () => {
- const arns = await io.getArNSRecord({ name: 'ardrive' });
- assert.ok(arns);
- });
- it('should be able to get the current epoch', async () => {
- const epoch = await io.getCurrentEpoch();
- assert.ok(epoch);
- });
+ it('should be able to get reserved names', async () => {
+ const reservedNames = await io.getArNSReservedNames();
+ assert.ok(reservedNames);
+ });
- it('should be able to get epoch-settings', async () => {
- const epochSettings = await io.getEpochSettings();
- assert.ok(epochSettings);
- });
+ it('should be able to get a single reserved name', async () => {
+ const reservedNames = await io.getArNSReservedNames({ name: 'www ' });
+ assert.ok(reservedNames);
+ });
- it('should be able to get reserved names', async () => {
- const reservedNames = await io.getArNSReservedNames();
- assert.ok(reservedNames);
- });
+ it('should be able to get first page of gateways', async () => {
+ const gateways = await io.getGateways();
+ assert.ok(gateways);
+ assert(gateways.limit === 100);
+ assert(gateways.sortOrder === 'desc');
+ assert(gateways.sortBy === 'startTimestamp');
+ assert(typeof gateways.totalItems === 'number');
+ assert(typeof gateways.sortBy === 'string');
+ assert(typeof gateways.sortOrder === 'string');
+ assert(typeof gateways.limit === 'number');
+ assert(typeof gateways.hasMore === 'boolean');
+ if (gateways.nextCursor) {
+ assert(typeof gateways.nextCursor === 'string');
+ }
+ assert(Array.isArray(gateways.items));
+ gateways.items.forEach((gateway) => {
+ assert(typeof gateway.gatewayAddress === 'string');
+ assert(typeof gateway.observerAddress === 'string');
+ assert(typeof gateway.startTimestamp === 'number');
+ assert(typeof gateway.operatorStake === 'number');
+ assert(typeof gateway.totalDelegatedStake === 'number');
+ assert(typeof gateway.settings === 'object');
+ assert(typeof gateway.weights === 'object');
+ assert(typeof gateway.weights.normalizedCompositeWeight === 'number');
+ assert(typeof gateway.weights.compositeWeight === 'number');
+ assert(typeof gateway.weights.stakeWeight === 'number');
+ assert(typeof gateway.weights.tenureWeight === 'number');
+ assert(typeof gateway.weights.observerRewardRatioWeight === 'number');
+ assert(typeof gateway.weights.gatewayRewardRatioWeight === 'number');
+ if (gateway.vaults?.length > 0) {
+ gateway.vaults.forEach((vault) => {
+ assert(typeof vault.balance === 'number');
+ assert(typeof vault.startTimestamp === 'number');
+ });
+ }
+ });
+ });
- it('should be able to get a single reserved name', async () => {
- const reservedNames = await io.getArNSReservedNames({ name: 'www ' });
- assert.ok(reservedNames);
- });
+ it('should be able to get a specific page of gateways', async () => {
+ const gateways = await io.getGateways({
+ cursor: 1000000,
+ limit: 1,
+ sortBy: 'operatorStake',
+ sortOrder: 'desc',
+ });
+ assert.ok(gateways);
+ assert(gateways.limit === 1);
+ assert(gateways.sortOrder === 'desc');
+ assert(gateways.sortBy === 'operatorStake');
+ assert(typeof gateways.totalItems === 'number');
+ assert(typeof gateways.sortBy === 'string');
+ assert(typeof gateways.sortOrder === 'string');
+ assert(typeof gateways.limit === 'number');
+ assert(typeof gateways.hasMore === 'boolean');
+ if (gateways.nextCursor) {
+ assert(typeof gateways.nextCursor === 'string');
+ }
+ assert(Array.isArray(gateways.items));
+ gateways.items.forEach((gateway) => {
+ assert(typeof gateway.gatewayAddress === 'string');
+ assert(typeof gateway.observerAddress === 'string');
+ assert(typeof gateway.startTimestamp === 'number');
+ assert(typeof gateway.operatorStake === 'number');
+ assert(typeof gateway.totalDelegatedStake === 'number');
+ assert(typeof gateway.settings === 'object');
+ assert(typeof gateway.weights === 'object');
+ assert(typeof gateway.weights.normalizedCompositeWeight === 'number');
+ assert(typeof gateway.weights.compositeWeight === 'number');
+ assert(typeof gateway.weights.stakeWeight === 'number');
+ assert(typeof gateway.weights.tenureWeight === 'number');
+ assert(typeof gateway.weights.observerRewardRatioWeight === 'number');
+ assert(typeof gateway.weights.gatewayRewardRatioWeight === 'number');
+ if (gateway.vaults?.length > 0) {
+ gateway.vaults.forEach((vault) => {
+ assert(typeof vault.balance === 'number');
+ assert(typeof vault.startTimestamp === 'number');
+ });
+ }
+ });
+ });
- it('should be able to get first page of gateways', async () => {
- const gateways = await io.getGateways();
- assert.ok(gateways);
- assert(gateways.limit === 100);
- assert(gateways.sortOrder === 'desc');
- assert(gateways.sortBy === 'startTimestamp');
- assert(typeof gateways.totalItems === 'number');
- assert(typeof gateways.sortBy === 'string');
- assert(typeof gateways.sortOrder === 'string');
- assert(typeof gateways.limit === 'number');
- assert(typeof gateways.hasMore === 'boolean');
- if (gateways.nextCursor) {
- assert(typeof gateways.nextCursor === 'string');
- }
- assert(Array.isArray(gateways.items));
- gateways.items.forEach((gateway) => {
- assert(typeof gateway.gatewayAddress === 'string');
- assert(typeof gateway.observerAddress === 'string');
- assert(typeof gateway.startTimestamp === 'number');
- assert(typeof gateway.operatorStake === 'number');
- assert(typeof gateway.totalDelegatedStake === 'number');
- assert(typeof gateway.settings === 'object');
- assert(typeof gateway.weights === 'object');
- assert(typeof gateway.weights.normalizedCompositeWeight === 'number');
- assert(typeof gateway.weights.compositeWeight === 'number');
- assert(typeof gateway.weights.stakeWeight === 'number');
- assert(typeof gateway.weights.tenureWeight === 'number');
- assert(typeof gateway.weights.observerRewardRatioWeight === 'number');
- assert(typeof gateway.weights.gatewayRewardRatioWeight === 'number');
+ it('should be able to get a single gateway', async () => {
+ const gateway = await io.getGateway({
+ address: 'QGWqtJdLLgm2ehFWiiPzMaoFLD50CnGuzZIPEdoDRGQ',
+ });
+ assert.ok(gateway);
});
- });
- it('should be able to get a specific page of gateways', async () => {
- const gateways = await io.getGateways({
- cursor: 1000000,
- limit: 1,
- sortBy: 'operatorStake',
- sortOrder: 'desc',
- });
- assert.ok(gateways);
- assert(gateways.limit === 1);
- assert(gateways.sortOrder === 'desc');
- assert(gateways.sortBy === 'operatorStake');
- assert(typeof gateways.totalItems === 'number');
- assert(typeof gateways.sortBy === 'string');
- assert(typeof gateways.sortOrder === 'string');
- assert(typeof gateways.limit === 'number');
- assert(typeof gateways.hasMore === 'boolean');
- if (gateways.nextCursor) {
- assert(typeof gateways.nextCursor === 'string');
- }
- assert(Array.isArray(gateways.items));
- gateways.items.forEach((gateway) => {
- assert(typeof gateway.gatewayAddress === 'string');
- assert(typeof gateway.observerAddress === 'string');
- assert(typeof gateway.startTimestamp === 'number');
- assert(typeof gateway.operatorStake === 'number');
- assert(typeof gateway.totalDelegatedStake === 'number');
- assert(typeof gateway.settings === 'object');
- assert(typeof gateway.weights === 'object');
- assert(typeof gateway.weights.normalizedCompositeWeight === 'number');
- assert(typeof gateway.weights.compositeWeight === 'number');
- assert(typeof gateway.weights.stakeWeight === 'number');
- assert(typeof gateway.weights.tenureWeight === 'number');
- assert(typeof gateway.weights.observerRewardRatioWeight === 'number');
- assert(typeof gateway.weights.gatewayRewardRatioWeight === 'number');
+ it('should be able to get gateway delegates', async () => {
+ const delegates = await io.getGatewayDelegates({
+ address: 'QGWqtJdLLgm2ehFWiiPzMaoFLD50CnGuzZIPEdoDRGQ',
+ limit: 1,
+ sortBy: 'startTimestamp',
+ sortOrder: 'desc',
+ });
+ assert.ok(delegates);
+ assert(delegates.limit === 1);
+ assert(delegates.sortOrder === 'desc');
+ assert(delegates.sortBy === 'startTimestamp');
+ assert(typeof delegates.totalItems === 'number');
+ assert(typeof delegates.sortBy === 'string');
+ assert(typeof delegates.sortOrder === 'string');
+ assert(typeof delegates.limit === 'number');
+ assert(typeof delegates.hasMore === 'boolean');
+ if (delegates.nextCursor) {
+ assert(typeof delegates.nextCursor === 'string');
+ }
+ assert(Array.isArray(delegates.items));
+ delegates.items.forEach((delegate) => {
+ assert(Array.isArray(delegate.vaults));
+ assert(typeof delegate.delegatedStake === 'number');
+ assert(typeof delegate.startTimestamp === 'number');
+ assert(typeof delegate.address === 'string');
+ });
});
- });
- it('should be able to get a single gateway', async () => {
- const gateways = await io.getGateway({
- address: 'QGWqtJdLLgm2ehFWiiPzMaoFLD50CnGuzZIPEdoDRGQ',
+ it('should be able to get gateway delegate allow list', async () => {
+ const allowList = await io.getGatewayDelegateAllowList({
+ address: 'QGWqtJdLLgm2ehFWiiPzMaoFLD50CnGuzZIPEdoDRGQ',
+ limit: 1,
+ sortBy: 'startTimestamp',
+ sortOrder: 'desc',
+ });
+ assert.ok(allowList);
+ // note: sortBy is omitted because it's not supported for by this contract handler, the result is an array of addresses
+ assert(allowList.limit === 1);
+ assert(allowList.sortOrder === 'desc');
+ assert(typeof allowList.totalItems === 'number');
+ assert(typeof allowList.sortOrder === 'string');
+ assert(typeof allowList.limit === 'number');
+ assert(typeof allowList.hasMore === 'boolean');
+ if (allowList.nextCursor) {
+ assert(typeof allowList.nextCursor === 'string');
+ }
+ assert(Array.isArray(allowList.items));
+ allowList.items.forEach((address) => {
+ assert(typeof address === 'string');
+ });
});
- assert.ok(gateways);
- });
- it('should be able to get balances, defaulting to first page', async () => {
- const balances = await io.getBalances();
- assert.ok(balances);
- assert(balances.limit === 100);
- assert(balances.sortOrder === 'desc');
- assert(balances.sortBy === 'balance');
- assert(typeof balances.totalItems === 'number');
- assert(typeof balances.sortBy === 'string');
- assert(typeof balances.sortOrder === 'string');
- assert(typeof balances.limit === 'number');
- assert(typeof balances.hasMore === 'boolean');
- if (balances.nextCursor) {
- assert(typeof gateways.nextCursor === 'string');
- }
- assert(Array.isArray(balances.items));
- balances.items.forEach((wallet) => {
- assert(typeof wallet.address === 'string');
- assert(typeof wallet.balance === 'number');
+ it('should be able to get balances, defaulting to first page', async () => {
+ const balances = await io.getBalances();
+ assert.ok(balances);
+ assert(balances.limit === 100);
+ assert(balances.sortOrder === 'desc');
+ assert(balances.sortBy === 'balance');
+ assert(typeof balances.totalItems === 'number');
+ assert(typeof balances.sortBy === 'string');
+ assert(typeof balances.sortOrder === 'string');
+ assert(typeof balances.limit === 'number');
+ assert(typeof balances.hasMore === 'boolean');
+ if (balances.nextCursor) {
+ assert(typeof gateways.nextCursor === 'string');
+ }
+ assert(Array.isArray(balances.items));
+ balances.items.forEach((wallet) => {
+ assert(typeof wallet.address === 'string');
+ assert(typeof wallet.balance === 'number');
+ });
});
- });
- it('should be able to get balances of a specific to first page', async () => {
- const balances = await io.getBalances({
- cursor: 1000000,
- limit: 1,
- sortBy: 'address',
- sortOrder: 'asc',
- });
- assert.ok(balances);
- assert(balances.limit === 1);
- assert(balances.sortOrder === 'asc');
- assert(balances.sortBy === 'address');
- assert(typeof balances.totalItems === 'number');
- assert(typeof balances.sortBy === 'string');
- assert(typeof balances.sortOrder === 'string');
- assert(typeof balances.limit === 'number');
- assert(typeof balances.hasMore === 'boolean');
- if (balances.nextCursor) {
- assert(typeof balances.nextCursor === 'string');
- }
- assert(Array.isArray(balances.items));
- balances.items.forEach((wallet) => {
- assert(typeof wallet.address === 'string');
- assert(typeof wallet.balance === 'number');
+ it('should be able to get balances of a specific to first page', async () => {
+ const balances = await io.getBalances({
+ cursor: 1000000,
+ limit: 1,
+ sortBy: 'address',
+ sortOrder: 'asc',
+ });
+ assert.ok(balances);
+ assert(balances.limit === 1);
+ assert(balances.sortOrder === 'asc');
+ assert(balances.sortBy === 'address');
+ assert(typeof balances.totalItems === 'number');
+ assert(typeof balances.sortBy === 'string');
+ assert(typeof balances.sortOrder === 'string');
+ assert(typeof balances.limit === 'number');
+ assert(typeof balances.hasMore === 'boolean');
+ if (balances.nextCursor) {
+ assert(typeof balances.nextCursor === 'string');
+ }
+ assert(Array.isArray(balances.items));
+ balances.items.forEach((wallet) => {
+ assert(typeof wallet.address === 'string');
+ assert(typeof wallet.balance === 'number');
+ });
});
- });
- it('should be able to get a single balance', async () => {
- const balances = await io.getBalance({
- address: 'QGWqtJdLLgm2ehFWiiPzMaoFLD50CnGuzZIPEdoDRGQ',
+ it('should be able to get a single balance', async () => {
+ const balances = await io.getBalance({
+ address: 'QGWqtJdLLgm2ehFWiiPzMaoFLD50CnGuzZIPEdoDRGQ',
+ });
+ assert.ok(balances);
});
- assert.ok(balances);
- });
- it('should be able to get prescribed names', async () => {
- const prescribedNames = await io.getPrescribedNames();
- assert.ok(prescribedNames);
- });
+ it('should be able to get prescribed names', async () => {
+ const prescribedNames = await io.getPrescribedNames();
+ assert.ok(prescribedNames);
+ });
- it('should return the prescribed observers for a given epoch', async () => {
- const observers = await io.getPrescribedObservers();
- assert.ok(observers);
- for (const observer of observers) {
- assert(typeof observer.gatewayAddress === 'string');
- assert(typeof observer.observerAddress === 'string');
- assert(typeof observer.stake === 'number');
- assert(typeof observer.startTimestamp === 'number');
- assert(typeof observer.stakeWeight === 'number');
- assert(typeof observer.tenureWeight === 'number');
- assert(typeof observer.gatewayRewardRatioWeight === 'number');
- assert(typeof observer.observerRewardRatioWeight === 'number');
- assert(typeof observer.compositeWeight === 'number');
- }
- });
+ it('should return the prescribed observers for a given epoch', async () => {
+ const observers = await io.getPrescribedObservers();
+ assert.ok(observers);
+ for (const observer of observers) {
+ assert(typeof observer.gatewayAddress === 'string');
+ assert(typeof observer.observerAddress === 'string');
+ assert(typeof observer.stake === 'number');
+ assert(typeof observer.startTimestamp === 'number');
+ assert(typeof observer.stakeWeight === 'number');
+ assert(typeof observer.tenureWeight === 'number');
+ assert(typeof observer.gatewayRewardRatioWeight === 'number');
+ assert(typeof observer.observerRewardRatioWeight === 'number');
+ assert(typeof observer.compositeWeight === 'number');
+ }
+ });
- it('should be able to get token cost for leasing a name', async () => {
- const tokenCost = await io.getTokenCost({
- intent: 'Buy-Record',
- name: 'new-name',
- years: 1,
+ it('should be able to get token cost for leasing a name', async () => {
+ const tokenCost = await io.getTokenCost({
+ intent: 'Buy-Record',
+ name: 'new-name',
+ years: 1,
+ });
+ assert.ok(tokenCost);
});
- assert.ok(tokenCost);
- });
- it('should be able to get token cost for buying a name name', async () => {
- const tokenCost = await io.getTokenCost({
- intent: 'Buy-Record',
- name: 'new-name',
- type: 'permabuy',
+ it('should be able to get token cost for buying a name name', async () => {
+ const tokenCost = await io.getTokenCost({
+ intent: 'Buy-Record',
+ name: 'new-name',
+ type: 'permabuy',
+ });
+ assert.ok(tokenCost);
});
- assert.ok(tokenCost);
- });
- it('should be able to get registration fees', async () => {
- const registrationFees = await io.getRegistrationFees();
- assert(registrationFees);
- assert.equal(Object.keys(registrationFees).length, 51);
- for (const nameLength of Object.keys(registrationFees)) {
- // assert lease is length of 5
- assert(registrationFees[nameLength]['lease']['1'] > 0);
- assert(registrationFees[nameLength]['lease']['2'] > 0);
- assert(registrationFees[nameLength]['lease']['3'] > 0);
- assert(registrationFees[nameLength]['lease']['4'] > 0);
- assert(registrationFees[nameLength]['lease']['5'] > 0);
- assert(registrationFees[nameLength]['permabuy'] > 0);
- }
- });
+ it('should be able to get registration fees', async () => {
+ const registrationFees = await io.getRegistrationFees();
+ assert(registrationFees);
+ assert.equal(Object.keys(registrationFees).length, 51);
+ for (const nameLength of Object.keys(registrationFees)) {
+ // assert lease is length of 5
+ assert(registrationFees[nameLength]['lease']['1'] > 0);
+ assert(registrationFees[nameLength]['lease']['2'] > 0);
+ assert(registrationFees[nameLength]['lease']['3'] > 0);
+ assert(registrationFees[nameLength]['lease']['4'] > 0);
+ assert(registrationFees[nameLength]['lease']['5'] > 0);
+ assert(registrationFees[nameLength]['permabuy'] > 0);
+ }
+ });
- it('should be able to get current epoch distributions', async () => {
- const distributions = await io.getDistributions();
- assert.ok(distributions);
- });
+ it('should be able to get current epoch distributions', async () => {
+ const distributions = await io.getDistributions();
+ assert.ok(distributions);
+ });
- it('should be able to get epoch distributions at a specific epoch', async () => {
- const distributions = await io.getDistributions({ epochIndex: 0 });
- assert.ok(distributions);
- });
+ it('should be able to get epoch distributions at a specific epoch', async () => {
+ const distributions = await io.getDistributions({ epochIndex: 0 });
+ assert.ok(distributions);
+ });
- it('should be able to get current epoch observations', async () => {
- const observations = await io.getObservations();
- assert.ok(observations);
- });
+ it('should be able to get current epoch observations', async () => {
+ const observations = await io.getObservations();
+ assert.ok(observations);
+ });
- it('should be able to get epoch observations at a specific epoch', async () => {
- const observations = await io.getObservations({ epochIndex: 0 });
- assert.ok(observations);
- });
+ it('should be able to get epoch observations at a specific epoch', async () => {
+ const observations = await io.getObservations({ epochIndex: 0 });
+ assert.ok(observations);
+ });
- it('should be able to get current demand factor', async () => {
- const demandFactor = await io.getDemandFactor();
- assert.ok(demandFactor);
- });
+ it('should be able to get current demand factor', async () => {
+ const demandFactor = await io.getDemandFactor();
+ assert.ok(demandFactor);
+ });
- it('should be able to create IOWriteable with valid signers', async () => {
- for (const signer of signers) {
- const io = IO.init({ signer });
+ it('should be able to get current auctions', async () => {
+ const { items: auctions } = await io.getArNSAuctions();
+ assert.ok(auctions);
+ });
- assert(io instanceof IOWriteable);
- }
- });
-});
+ it('should be able to get a specific auction', async () => {
+ const { items: auctions } = await io.getArNSAuctions();
+ if (auctions.length === 0) {
+ return;
+ }
+ const auction = await io.getArNSAuction({ name: auctions[0].name });
+ assert.ok(auction);
+ });
-describe('ANTRegistry', async () => {
- const registry = ANTRegistry.init();
- const address = '7waR8v4STuwPnTck1zFVkQqJh5K9q9Zik4Y5-5dV7nk';
+ it('should be able to get auction prices for an existing auction', async () => {
+ const { items: auctions } = await io.getArNSAuctions();
+ if (auctions.length === 0) {
+ return;
+ }
+ const auctionPrices = await io.getArNSAuctionPrices({
+ name: auctions[0].name,
+ type: 'lease',
+ years: 1,
+ });
+ assert.ok(auctionPrices);
+ });
- it('should retrieve ids from registry', async () => {
- const affiliatedAnts = await registry.accessControlList({ address });
- assert(Array.isArray(affiliatedAnts.Owned));
- assert(Array.isArray(affiliatedAnts.Controlled));
- });
+ it('should be able to create IOWriteable with valid signers', async () => {
+ for (const signer of signers) {
+ const io = IO.init({ signer });
+
+ assert(io instanceof IOWriteable);
+ }
+ });
+
+ // TODO: Make a vault within this test environment's context to cover this
+ // it('should be able to get a specific vault', async () => {
+ // const vault = await io.getVault({
+ // address: '31LPFYoow2G7j-eSSsrIh8OlNaARZ84-80J-8ba68d8',
+ // vaultId: 'Dmsrp1YIYUY5hA13euO-pAGbT1QPazfj1bKD9EpiZeo',
+ // });
+ // assert.deepEqual(vault, {
+ // balance: 1,
+ // startTimestamp: 1729962428678,
+ // endTimestamp: 1731172028678,
+ // });
+ // });
+
+ it('should throw an error when unable to get a specific vault', async () => {
+ const error = await io
+ .getVault({
+ address: '31LPFYoow2G7j-eSSsrIh8OlNaARZ84-80J-8ba68d8',
+ vaultId: 'Dmsrp1YIYUY5hA13euO-pAGbT1QPazfj1bKD9EpiZeo',
+ })
+ .catch((e) => e);
+ assert.ok(error);
+ assert(error instanceof Error);
+ assert(error.message === 'Vault-Not-Found');
+ });
+
+ it('should be able to get paginated vaults', async () => {
+ const vaults = await io.getVaults();
+ assert.ok(vaults);
+ assert(vaults.limit === 100);
+ assert(vaults.sortOrder === 'desc');
+ assert(vaults.sortBy === 'address');
+ assert(typeof vaults.totalItems === 'number');
+ assert(typeof vaults.sortBy === 'string');
+ assert(typeof vaults.sortOrder === 'string');
+ assert(typeof vaults.limit === 'number');
+ assert(typeof vaults.hasMore === 'boolean');
+ if (vaults.nextCursor) {
+ assert(typeof vaults.nextCursor === 'string');
+ }
+ assert(Array.isArray(vaults.items));
+ vaults.items.forEach(
+ ({ address, vaultId, balance, endTimestamp, startTimestamp }) => {
+ assert(typeof address === 'string');
+ assert(typeof balance === 'number');
+ assert(typeof startTimestamp === 'number');
+ assert(typeof endTimestamp === 'number');
+ assert(typeof vaultId === 'string');
+ },
+ );
+ });
- it('should be able to create AoANTRegistryWriteable with valid signers', async () => {
- for (const signer of signers) {
- const registry = ANTRegistry.init({
- signer,
+ it('should be able to get paginated vaults with custom sort', async () => {
+ const vaults = await io.getVaults({
+ sortBy: 'balance',
+ sortOrder: 'asc',
});
- assert(registry instanceof AoANTRegistryWriteable);
- }
+ assert.ok(vaults);
+ assert(vaults.limit === 100);
+ assert(vaults.sortOrder === 'asc');
+ assert(vaults.sortBy === 'balance');
+ assert(typeof vaults.totalItems === 'number');
+ assert(typeof vaults.sortBy === 'string');
+ assert(typeof vaults.sortOrder === 'string');
+ assert(typeof vaults.limit === 'number');
+ assert(typeof vaults.hasMore === 'boolean');
+ if (vaults.nextCursor) {
+ assert(typeof vaults.nextCursor === 'string');
+ }
+ assert(Array.isArray(vaults.items));
+ vaults.items.forEach(
+ ({ address, vaultId, balance, endTimestamp, startTimestamp }) => {
+ assert(typeof address === 'string');
+ assert(typeof balance === 'number');
+ assert(typeof startTimestamp === 'number');
+ assert(typeof endTimestamp === 'number');
+ assert(typeof vaultId === 'string');
+ },
+ );
+ });
});
-});
-describe('ANT', async () => {
- const processId = 'aWI_dq1JH7facsulLuas1X3l5dkKuWtixcZDYMw9mpg';
- const ant = ANT.init({
- processId,
+ describe('ANTRegistry', async () => {
+ const registry = ANTRegistry.init({
+ process: new AOProcess({
+ processId: ANT_REGISTRY_ID,
+ ao: aoClient,
+ }),
+ });
+ const address = '7waR8v4STuwPnTck1zFVkQqJh5K9q9Zik4Y5-5dV7nk';
+
+ it('should retrieve ids from registry', async () => {
+ const affiliatedAnts = await registry.accessControlList({ address });
+ assert(Array.isArray(affiliatedAnts.Owned));
+ assert(Array.isArray(affiliatedAnts.Controlled));
+ });
+
+ it('should be able to create AoANTRegistryWriteable with valid signers', async () => {
+ for (const signer of signers) {
+ const registry = ANTRegistry.init({
+ signer,
+ process: new AOProcess({
+ processId: ANT_REGISTRY_ID,
+ ao: aoClient,
+ }),
+ });
+ assert(registry instanceof AoANTRegistryWriteable);
+ }
+ });
});
- it('should be able to create ANTWriteable with valid signers', async () => {
- for (const signer of signers) {
- const writeable = ANT.init({
+ describe('ANT', async () => {
+ const processId = 'YcxE5IbqZYK72H64ELoysxiJ-0wb36deYPv55wgl8xo';
+ const ant = ANT.init({
+ process: new AOProcess({
processId,
- signer,
- });
+ ao: aoClient,
+ }),
+ });
- assert(writeable instanceof AoANTWriteable);
- }
- });
+ it('should be able to create ANTWriteable with valid signers', async () => {
+ for (const signer of signers) {
+ const nonStrictAnt = ANT.init({
+ process: new AOProcess({
+ processId,
+ ao: aoClient,
+ }),
+ signer,
+ });
+ const strictAnt = ANT.init({
+ process: new AOProcess({
+ processId,
+ ao: aoClient,
+ }),
+ signer,
+ strict: true,
+ });
+
+ assert(nonStrictAnt instanceof AoANTWriteable);
+ assert(strictAnt instanceof AoANTWriteable);
+ }
+ });
- it('should be able to get ANT info', async () => {
- const info = await ant.getInfo({ processId });
- assert.ok(info);
- });
+ it('should be able to get ANT info', async () => {
+ const info = await ant.getInfo();
+ assert.ok(info);
+ });
- it('should be able to get the ANT records', async () => {
- const records = await ant.getRecords({ processId });
- assert.ok(records);
- });
+ it('should be able to get the ANT records', async () => {
+ const records = await ant.getRecords();
+ assert.ok(records);
+ });
- it('should be able to get a @ record from the ANT', async () => {
- const record = await ant.getRecord({ undername: '@' });
- assert.ok(record);
- });
+ it('should be able to get a @ record from the ANT', async () => {
+ const record = await ant.getRecord({ undername: '@' });
+ assert.ok(record);
+ });
- it('should be able to get the ANT owner', async () => {
- const owner = await ant.getOwner();
- assert.ok(owner);
- });
+ it('should be able to get the ANT owner', async () => {
+ const owner = await ant.getOwner();
+ assert.ok(owner);
+ });
- it('should be able to get the ANT name', async () => {
- const name = await ant.getName();
- assert.ok(name);
- });
+ it('should be able to get the ANT name', async () => {
+ const name = await ant.getName();
+ assert.ok(name);
+ });
- it('should be able to get the ANT ticker', async () => {
- const ticker = await ant.getTicker();
- assert.ok(ticker);
- });
+ it('should be able to get the ANT ticker', async () => {
+ const ticker = await ant.getTicker();
+ assert.ok(ticker);
+ });
- it('should be able to get the ANT controllers', async () => {
- const controllers = await ant.getControllers();
- assert.ok(controllers);
- });
+ it('should be able to get the ANT controllers', async () => {
+ const controllers = await ant.getControllers();
+ assert.ok(controllers);
+ });
- it('should be able to get the ANT state', async () => {
- const state = await ant.getState();
- assert.ok(state);
- });
+ it('should be able to get the ANT state', async () => {
+ const state = await ant.getState();
+ assert.ok(state);
+ });
- it('should be able to get the ANT balance for an address', async () => {
- const balance = await ant.getBalance({
- address: '"7waR8v4STuwPnTck1zFVkQqJh5K9q9Zik4Y5-5dV7nk',
+ it('should be able to get the ANT balance for an address', async () => {
+ const balance = await ant.getBalance({
+ address: '7waR8v4STuwPnTck1zFVkQqJh5K9q9Zik4Y5-5dV7nk',
+ });
+ assert.notEqual(balance, undefined);
});
- assert.notEqual(balance, undefined);
- });
- it('should be able to get the ANT balances', async () => {
- const balances = await ant.getBalances();
- assert.ok(balances);
+ it('should be able to get the ANT balances', async () => {
+ const balances = await ant.getBalances();
+ assert.ok(balances);
+ });
});
});
diff --git a/tests/e2e/esm/yarn.lock b/tests/e2e/esm/yarn.lock
index 9a75a12c..f8477428 100644
--- a/tests/e2e/esm/yarn.lock
+++ b/tests/e2e/esm/yarn.lock
@@ -785,10 +785,10 @@ elliptic@6.5.4:
minimalistic-assert "^1.0.1"
minimalistic-crypto-utils "^1.0.1"
-elliptic@^6.5.4:
- version "6.5.5"
- resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.5.tgz#c715e09f78b6923977610d4c2346d6ce22e6dded"
- integrity sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==
+elliptic@^6.5.7:
+ version "6.5.7"
+ resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.7.tgz#8ec4da2cb2939926a1b9a73619d768207e647c8b"
+ integrity sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==
dependencies:
bn.js "^4.11.9"
brorand "^1.1.0"
@@ -1289,11 +1289,11 @@ scrypt-js@3.0.1:
integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==
secp256k1@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-5.0.0.tgz#be6f0c8c7722e2481e9773336d351de8cddd12f7"
- integrity sha512-TKWX8xvoGHrxVdqbYeZM9w+izTF4b9z3NhSaDkdn81btvuh+ivbIMGT/zQvDtTFWhRlThpoz6LEYTr7n8A5GcA==
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-5.0.1.tgz#dc2c86187d48ff2da756f0f7e96417ee03c414b1"
+ integrity sha512-lDFs9AAIaWP9UCdtWrotXWWF9t8PWgQDcxqgAnpM9rMqxb3Oaq2J0thzPVSxBwdJgyQtkU/sYtFtbM1RSt/iYA==
dependencies:
- elliptic "^6.5.4"
+ elliptic "^6.5.7"
node-addon-api "^5.0.0"
node-gyp-build "^4.2.0"
diff --git a/tests/e2e/web/yarn.lock b/tests/e2e/web/yarn.lock
index e3f08cb1..55246d4c 100644
--- a/tests/e2e/web/yarn.lock
+++ b/tests/e2e/web/yarn.lock
@@ -2327,7 +2327,7 @@ elliptic@6.5.4:
minimalistic-assert "^1.0.1"
minimalistic-crypto-utils "^1.0.1"
-elliptic@^6.5.3, elliptic@^6.5.4, elliptic@^6.5.5:
+elliptic@^6.5.3, elliptic@^6.5.5:
version "6.5.5"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.5.tgz#c715e09f78b6923977610d4c2346d6ce22e6dded"
integrity sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==
@@ -2340,6 +2340,19 @@ elliptic@^6.5.3, elliptic@^6.5.4, elliptic@^6.5.5:
minimalistic-assert "^1.0.1"
minimalistic-crypto-utils "^1.0.1"
+elliptic@^6.5.7:
+ version "6.5.7"
+ resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.7.tgz#8ec4da2cb2939926a1b9a73619d768207e647c8b"
+ integrity sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==
+ dependencies:
+ bn.js "^4.11.9"
+ brorand "^1.1.0"
+ hash.js "^1.0.0"
+ hmac-drbg "^1.0.1"
+ inherits "^2.0.4"
+ minimalistic-assert "^1.0.1"
+ minimalistic-crypto-utils "^1.0.1"
+
emoji-regex@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
@@ -4632,11 +4645,11 @@ scrypt-js@3.0.1:
integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==
secp256k1@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-5.0.0.tgz#be6f0c8c7722e2481e9773336d351de8cddd12f7"
- integrity sha512-TKWX8xvoGHrxVdqbYeZM9w+izTF4b9z3NhSaDkdn81btvuh+ivbIMGT/zQvDtTFWhRlThpoz6LEYTr7n8A5GcA==
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-5.0.1.tgz#dc2c86187d48ff2da756f0f7e96417ee03c414b1"
+ integrity sha512-lDFs9AAIaWP9UCdtWrotXWWF9t8PWgQDcxqgAnpM9rMqxb3Oaq2J0thzPVSxBwdJgyQtkU/sYtFtbM1RSt/iYA==
dependencies:
- elliptic "^6.5.4"
+ elliptic "^6.5.7"
node-addon-api "^5.0.0"
node-gyp-build "^4.2.0"
diff --git a/tests/unit/ant.test.ts b/tests/unit/ant.test.ts
index 97e6ba43..da4910cc 100644
--- a/tests/unit/ant.test.ts
+++ b/tests/unit/ant.test.ts
@@ -1,36 +1,142 @@
import { strict as assert } from 'node:assert';
import { describe, it } from 'node:test';
+import { z } from 'zod';
-import { isAoANTState } from '../../src/utils/ao.js';
-
-const testAoANTState = {
- Name: 'TestToken',
- Ticker: 'TST',
- Denomination: 1,
- Owner: ''.padEnd(43, '1'),
- Controllers: [''.padEnd(43, '2')],
- Records: {
- record1: {
- transactionId: ''.padEnd(43, '1'),
- ttlSeconds: 3600,
- },
- },
- Balances: {
- [''.padEnd(43, '1')]: 1,
- },
- Logo: ''.padEnd(43, '1'),
- TotalSupply: 0,
- Initialized: true,
- ['Source-Code-TX-ID']: ''.padEnd(43, '1'),
-};
-describe('ANT', () => {
- it('should validate accurate ANT state', () => {
- const res = isAoANTState(testAoANTState);
- assert.strictEqual(res, true);
+import {
+ AntHandlerNames,
+ AntInfoSchema,
+ AntStateSchema,
+ isAoANTState,
+} from '../../src/types/ant.js';
+
+const stub_address = 'valid-address'.padEnd(43, '1');
+
+describe('ANT Schemas', () => {
+ it('should validate AntStateSchema', () => {
+ const validState = {
+ Name: 'TestToken',
+ Ticker: 'TST',
+ Description: 'Test description',
+ Keywords: ['keyword1', 'keyword2', 'keyword3'],
+ Denomination: 0,
+ Owner: stub_address,
+ Controllers: [stub_address],
+ Records: {
+ record1: {
+ transactionId: stub_address,
+ ttlSeconds: 3600,
+ },
+ },
+ Balances: {
+ [stub_address]: 1,
+ },
+ Logo: stub_address,
+ TotalSupply: 1,
+ Initialized: true,
+ ['Source-Code-TX-ID']: stub_address,
+ };
+ const invalidState = {
+ Name: 'TestToken',
+ Ticker: 'TST',
+ Description: 'Test description',
+ Keywords: ['keyword1', 'keyword2', 'keyword3'],
+ Denomination: 0,
+ Owner: stub_address,
+ Controllers: [stub_address],
+ Records: {
+ record1: {
+ transactionId: 'invalid-id',
+ ttlSeconds: '3600',
+ },
+ },
+ Balances: {
+ [stub_address]: 1,
+ },
+ Logo: stub_address,
+ TotalSupply: -1,
+ Initialized: true,
+ ['Source-Code-TX-ID']: stub_address,
+ };
+
+ assert.doesNotThrow(() => AntStateSchema.parse(validState));
+ assert.throws(() => AntStateSchema.parse(invalidState), z.ZodError);
});
- it('should invalidate inaccurate ANT state', () => {
- const res = isAoANTState({ ...testAoANTState, Name: 1 });
- assert.strictEqual(res, false);
+ it('should validate AntInfoSchema', () => {
+ const validInfo = {
+ Name: 'TestToken',
+ Owner: stub_address,
+ ['Source-Code-TX-ID']: stub_address,
+ Ticker: 'TST',
+ Description: 'Test description',
+ Keywords: ['keyword1', 'keyword2', 'keyword3'],
+ ['Total-Supply']: '1',
+ Logo: stub_address,
+ Denomination: '0',
+ Handlers: AntHandlerNames,
+ };
+ const invalidInfo = {
+ Name: 'TestToken',
+ Owner: stub_address,
+ ['Source-Code-TX-ID']: stub_address,
+ Ticker: 'TST',
+ ['Total-Supply']: 1000,
+ Logo: stub_address,
+ Denomination: '1',
+ Handlers: AntHandlerNames,
+ };
+
+ assert.doesNotThrow(() => AntInfoSchema.parse(validInfo));
+ assert.throws(() => AntInfoSchema.parse(invalidInfo), z.ZodError);
+ });
+
+ it('should validate isAoANTState', () => {
+ const validState = {
+ Name: 'TestToken',
+ Ticker: 'TST',
+ Description: 'Test description',
+ Keywords: ['keyword1', 'keyword2', 'keyword3'],
+ Denomination: 0,
+ Owner: stub_address,
+ Controllers: [stub_address],
+ Records: {
+ record1: {
+ transactionId: stub_address,
+ ttlSeconds: 3600,
+ },
+ },
+ Balances: {
+ [stub_address]: 1,
+ },
+ Logo: stub_address,
+ TotalSupply: 0,
+ Initialized: true,
+ ['Source-Code-TX-ID']: stub_address,
+ };
+ const invalidState = {
+ Name: 'TestToken',
+ Ticker: 'TST',
+ Description: 'Test description',
+ Keywords: ['keyword1', 'keyword2', 'keyword3'],
+ Denomination: 0,
+ Owner: stub_address,
+ Controllers: [stub_address],
+ Records: {
+ record1: {
+ transactionId: 'invalid-id',
+ ttlSeconds: '3600',
+ },
+ },
+ Balances: {
+ [stub_address]: 1,
+ },
+ Logo: stub_address,
+ TotalSupply: -1,
+ Initialized: true,
+ ['Source-Code-TX-ID']: stub_address,
+ };
+
+ assert.strictEqual(isAoANTState(validState), true);
+ assert.strictEqual(isAoANTState(invalidState), false);
});
});
diff --git a/tests/unit/token.test.ts b/tests/unit/token.test.ts
index 8a4dd88a..b8dc277a 100644
--- a/tests/unit/token.test.ts
+++ b/tests/unit/token.test.ts
@@ -1,7 +1,7 @@
import { strict as assert } from 'node:assert';
import { describe, it } from 'node:test';
-import { IOToken, mIOToken } from '../../src/token.js';
+import { IOToken, mIOToken } from '../../src/types/token.js';
describe('IOToken', () => {
it('should throw an error on invalid input', () => {
diff --git a/tests/unit/utils.test.ts b/tests/unit/utils.test.ts
new file mode 100644
index 00000000..022329ab
--- /dev/null
+++ b/tests/unit/utils.test.ts
@@ -0,0 +1,66 @@
+import Arweave from 'arweave';
+import { strict as assert } from 'node:assert';
+import { describe, it } from 'node:test';
+
+import {
+ getCurrentBlockUnixTimestampMs,
+ pruneTags,
+} from '../../src/utils/arweave.js';
+
+describe('pruneTags', () => {
+ it('should remove tags with undefined values', () => {
+ const tags = [
+ { name: 'Tag1', value: 'value1' },
+ { name: 'Tag2', value: undefined },
+ { name: 'Tag3', value: 'value3' },
+ { name: 'Tag4', value: undefined },
+ ];
+
+ const prunedTags = pruneTags(tags);
+
+ assert.deepEqual(prunedTags, [
+ { name: 'Tag1', value: 'value1' },
+ { name: 'Tag3', value: 'value3' },
+ ]);
+ });
+
+ it('should return empty array when all tags have undefined values', () => {
+ const tags = [
+ { name: 'Tag1', value: undefined },
+ { name: 'Tag2', value: undefined },
+ ];
+
+ const prunedTags = pruneTags(tags);
+
+ assert.deepEqual(prunedTags, []);
+ });
+
+ it('should return same array when no tags have undefined values', () => {
+ const tags = [
+ { name: 'Tag1', value: 'value1' },
+ { name: 'Tag2', value: 'value2' },
+ ];
+
+ const prunedTags = pruneTags(tags);
+
+ assert.deepEqual(prunedTags, tags);
+ });
+
+ it('should return empty array with no tags', () => {
+ const tags: { name: string; value: string | undefined }[] = [];
+ const prunedTags = pruneTags(tags);
+ assert.deepEqual(prunedTags, []);
+ });
+});
+
+describe('getCurrentBlockUnixTimestamp', () => {
+ it('should return the current block timestamp', async () => {
+ const arweave = Arweave.init({});
+ // cheap way to check the returned timestamp is within the boundaries of the async call
+ const minTimestamp = Date.now();
+ const timestamp = await getCurrentBlockUnixTimestampMs(arweave);
+ const maxTimestamp = Date.now();
+ assert.ok(timestamp >= minTimestamp);
+ assert.ok(timestamp <= maxTimestamp);
+ });
+});
diff --git a/yarn.lock b/yarn.lock
index 3e2df580..d7ea89f6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3474,7 +3474,7 @@ elliptic@6.5.4:
minimalistic-assert "^1.0.1"
minimalistic-crypto-utils "^1.0.1"
-elliptic@^6.5.3, elliptic@^6.5.4, elliptic@^6.5.5:
+elliptic@^6.5.3, elliptic@^6.5.5:
version "6.5.5"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.5.tgz#c715e09f78b6923977610d4c2346d6ce22e6dded"
integrity sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==
@@ -3487,6 +3487,19 @@ elliptic@^6.5.3, elliptic@^6.5.4, elliptic@^6.5.5:
minimalistic-assert "^1.0.1"
minimalistic-crypto-utils "^1.0.1"
+elliptic@^6.5.7:
+ version "6.5.7"
+ resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.7.tgz#8ec4da2cb2939926a1b9a73619d768207e647c8b"
+ integrity sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==
+ dependencies:
+ bn.js "^4.11.9"
+ brorand "^1.1.0"
+ hash.js "^1.0.0"
+ hmac-drbg "^1.0.1"
+ inherits "^2.0.4"
+ minimalistic-assert "^1.0.1"
+ minimalistic-crypto-utils "^1.0.1"
+
emoji-regex@^10.3.0:
version "10.3.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.3.0.tgz#76998b9268409eb3dae3de989254d456e70cfe23"
@@ -6254,6 +6267,15 @@ nise@^5.1.4:
just-extend "^6.2.0"
path-to-regexp "^6.2.1"
+nock@^13.5.5:
+ version "13.5.5"
+ resolved "https://registry.yarnpkg.com/nock/-/nock-13.5.5.tgz#cd1caaca281d42be17d51946367a3d53a6af3e78"
+ integrity sha512-XKYnqUrCwXC8DGG1xX4YH5yNIrlh9c065uaMZZHUoeUUINTOyt+x/G+ezYk0Ft6ExSREVIs+qBJDK503viTfFA==
+ dependencies:
+ debug "^4.1.0"
+ json-stringify-safe "^5.0.1"
+ propagate "^2.0.0"
+
node-addon-api@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32"
@@ -7291,6 +7313,11 @@ promzard@^1.0.0:
dependencies:
read "^3.0.1"
+propagate@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/propagate/-/propagate-2.0.1.tgz#40cdedab18085c792334e64f0ac17256d38f9a45"
+ integrity sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==
+
proper-lockfile@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f"
@@ -7753,11 +7780,11 @@ scrypt-js@3.0.1:
integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==
secp256k1@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-5.0.0.tgz#be6f0c8c7722e2481e9773336d351de8cddd12f7"
- integrity sha512-TKWX8xvoGHrxVdqbYeZM9w+izTF4b9z3NhSaDkdn81btvuh+ivbIMGT/zQvDtTFWhRlThpoz6LEYTr7n8A5GcA==
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-5.0.1.tgz#dc2c86187d48ff2da756f0f7e96417ee03c414b1"
+ integrity sha512-lDFs9AAIaWP9UCdtWrotXWWF9t8PWgQDcxqgAnpM9rMqxb3Oaq2J0thzPVSxBwdJgyQtkU/sYtFtbM1RSt/iYA==
dependencies:
- elliptic "^6.5.4"
+ elliptic "^6.5.7"
node-addon-api "^5.0.0"
node-gyp-build "^4.2.0"