Skip to content

Commit

Permalink
Merge pull request #235 from ar-io/PE-6656-auctions
Browse files Browse the repository at this point in the history
feat(auctions): add auctions api to IO classes
  • Loading branch information
dtfiedler authored Oct 24, 2024
2 parents e4fc487 + b0d46d4 commit 7490a95
Show file tree
Hide file tree
Showing 14 changed files with 1,347 additions and 694 deletions.
147 changes: 147 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ This is the home of [ar.io] SDK. This SDK provides functionality for interacting
- [`getGateways({ cursor, limit, sortBy, sortOrder })`](#getgateways-cursor-limit-sortby-sortorder-)
- [`getArNSRecord({ name })`](#getarnsrecord-name-)
- [`getArNSRecords({ cursor, limit, sortBy, sortOrder })`](#getarnsrecords-cursor-limit-sortby-sortorder-)
- [`getAuctions({ cursor, limit, sortBy, sortOrder })`](#getauctions-cursor-limit-sortby-sortorder-)
- [`getAuction({ name })`](#getauction-name-)
- [`getAuctionPrices({ name, type, years, intervalMs })`](#getauctionprices-name-type-years-intervalms-)
- [`getDemandFactor()`](#getdemandfactor)
- [`getObservations({ epochIndex })`](#getobservations-epochindex-)
- [`getDistributions({ epochIndex })`](#getdistributions-epochindex-)
Expand Down Expand Up @@ -69,6 +72,7 @@ This is the home of [ar.io] SDK. This SDK provides functionality for interacting
- [`removeRecord({ undername })`](#removerecord-undername-)
- [`setName({ name })`](#setname-name-)
- [`setTicker({ ticker })`](#setticker-ticker-)
- [`releaseName({ name, ioProcessId })`](#releasename-name-ioprocessid-)
- [Configuration](#configuration-1)
- [Logging](#logging)
- [Configuration](#configuration-2)
Expand Down Expand Up @@ -598,6 +602,136 @@ Available `sortBy` options are any of the keys on the record object, e.g. `name`

</details>

#### `getAuctions({ cursor, limit, sortBy, sortOrder })`

Retrieves all active auctions of the IO process, paginated and sorted by the specified criteria. The `cursor` used for pagination is the last auction name from the previous request.

```typescript
const io = IO.init();
const auctions = await io.getAuctions({
limit: 100,
sortBy: 'endTimestamp',
sortOrder: 'asc', // return the auctions ending soonest first
});
```

<details>
<summary>Output</summary>

```json
{
"items": [
{
"name": "permalink",
"endTimestamp": 1730985241349,
"startTimestamp": 1729775641349,
"baseFee": 250000000,
"demandFactor": 1.05256,
"initiator": "GaQrvEMKBpkjofgnBi_B3IgIDmY_XYelVLB6GcRGrHc",
"settings": {
"durationMs": 1209600000,
"decayRate": 0.000000000016847809193121693,
"scalingExponent": 190,
"startPriceMultiplier": 50
}
}
],
"hasMore": false,
"totalItems": 1,
"sortBy": "endTimestamp",
"sortOrder": "asc"
}
```

</details>

#### `getAuction({ name })`

Retrieves the auction data for the specified auction name.

```typescript
const io = IO.init();
const auction = await io.getAuction({ name: 'permalink' });
```

<details>
<summary>Output</summary>

```json
{
"name": "permalink",
"endTimestamp": 1730985241349,
"startTimestamp": 1729775641349,
"baseFee": 250000000,
"demandFactor": 1.05256,
"initiator": "GaQrvEMKBpkjofgnBi_B3IgIDmY_XYelVLB6GcRGrHc",
"settings": {
"durationMs": 1209600000,
"decayRate": 0.000000000016847809193121693,
"scalingExponent": 190,
"startPriceMultiplier": 50
}
}
```

</details>

#### `getAuctionPrices({ name, type, years, intervalMs })`

Retrieves the auction price curve of the specified auction name for the specified type, duration, and interval. The `intervalMs` is the number of milliseconds between price points on the curve. The default interval is 15 minutes.

```typescript
const io = IO.init();
const priceCurve = await io.getAuctionPrices({
name: 'permalink',
type: 'lease',
years: 1,
intervalMs: 3600000, // 1 hour price intervals (default is 15 minutes)
});
```

<details>
<summary>Output</summary>

```json
{
"name": "permalink",
"type": "lease",
"currentPrice": 12582015000,
"years": 1,
"prices": {
"1730412841349": 1618516789,
"1729908841349": 8210426826,
"1730722441349": 592768907,
"1730859241349": 379659914,
"1730866441349": 370850139,
"1730884441349": 349705277,
"1730150041349": 3780993370,
"1730031241349": 5541718397,
"1730603641349": 872066253,
"1730715241349": 606815377,
"1730942041349": 289775172,
"1730916841349": 314621977,
"1730484841349": 1281957300,
"1730585641349": 924535164,
"1730232841349": 2895237473,
"1730675641349": 690200977,
"1730420041349": 1581242331,
"1729786441349": 12154428186,
"1730308441349": 2268298483,
"1730564041349": 991657913,
"1730081641349": 4712427282,
"1730909641349": 322102563,
"1730945641349": 286388732,
"1730024041349": 5671483398,
"1729937641349": 7485620175
// ...
}
}
```

</details>

#### `getDemandFactor()`

Retrieves the current demand factor of the network. The demand factor is a multiplier applied to the cost of ArNS interactions based on the current network demand.
Expand Down Expand Up @@ -1413,6 +1547,19 @@ const { id: txId } = await ant.setTicker(
);
```

#### `releaseName({ name, ioProcessId })`

Releases a name from the auction and makes it available for auction on the IO contract. The name must be permanently owned by the releasing wallet. 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.

_Note: Requires `signer` to be provided on `ANT.init` to sign the transaction._

```typescript
const { id: txId } = await ant.releaseName({
name: 'permalink',
ioProcessId: IO_TESTNET_PROCESS_ID, // releases the name owned by the ANT and sends it to auction on the IO contract
});
```

### Configuration

ANT clients can be configured to use custom AO process. Refer to [AO Connect] for more information on how to configure the AO process to use specific AO infrastructure.
Expand Down
2 changes: 1 addition & 1 deletion examples/esm/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
const distributions = await arIO.getDistributions({ epochIndex: 0 });
const buyRecordCost = await arIO.getTokenCost({
intent: 'Buy-Record',
purchaseType: 'lease',
type: 'lease',
name: 'ar-io-dapp-record',
years: 1,
});
Expand Down
1 change: 1 addition & 0 deletions examples/vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-markdown": "^9.0.1",
"recharts": "^2.13.0",
"remark-gfm": "^4.0.0"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion examples/vite/src/App.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.App {
text-align: center;
background-color: #282c34;
background-color: #f0f0f0;
}

.markdown {
Expand Down
101 changes: 83 additions & 18 deletions examples/vite/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,98 @@
import { ANT, ANTState } from '@ar.io/sdk/web';
import {
AoAuction,
AoAuctionPriceData,
IO,
IO_DEVNET_PROCESS_ID,
PaginationResult,
} from '@ar.io/sdk/web';
import { useEffect, useState } from 'react';
import Markdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import {
Label,
Line,
LineChart,
ReferenceLine,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from 'recharts';

import './App.css';

const contractTxId = 'ilwT4ObFQ7cGPbW-8z-h7mvvWGt_yhWNlqxNjSUgiYY';
const antContract = ANT.init({ contractTxId, strict: true });
const io = IO.init({ processId: IO_DEVNET_PROCESS_ID });

type AuctionWithPrices = AoAuction & {
prices: { timestamp: string; price: number }[];
currentPrice: number;
};

function App() {
const [contract, setContract] = useState<string>('Loading...');
const [auctions, setAuctions] = useState<AuctionWithPrices[]>([]);

useEffect(() => {
antContract
.getState()
.then((state: ANTState) => {
setContract(`\`\`\`json\n${JSON.stringify(state, null, 2)}`);
})
.catch((error: unknown) => {
console.error(error);
setContract('Error loading contract state');
io.getAuctions().then((page: PaginationResult<AoAuction>) => {
page.items.forEach((auction: AoAuction) => {
io.getAuctionPrices({
name: auction.name,
type: 'lease',
intervalMs: 1000 * 60 * 60 * 24, // 1 day
}).then((price: AoAuctionPriceData) => {
const arrayOfPrices = Object.entries(price.prices)
.sort(([timestampA], [timestampB]) => +timestampA - +timestampB)
.map(([timestamp, price]) => ({
timestamp: new Date(+timestamp).toLocaleString('en-US', {
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
hour12: false,
}),
price: price / 10 ** 6,
}));
const auctionWithPrices = {
...auction,
prices: arrayOfPrices,
currentPrice: price.currentPrice / 10 ** 6,
};
setAuctions((prev) => [...prev, auctionWithPrices]);
});
});
});
}, []);

return (
<div className="App">
<Markdown className="markdown" remarkPlugins={[remarkGfm]}>
{contract}
</Markdown>
<div className="App" style={{ padding: '50px' }}>
{auctions.length > 0 && (
<ResponsiveContainer width="50%" height={500}>
<LineChart
data={auctions[0].prices}
title={`Auction Prices for ${auctions[0].name}`}
>
<XAxis dataKey="timestamp" tick={{ fontSize: 12 }}>
<Label value="Date" offset={-5} position="insideBottom" />
</XAxis>
<YAxis dataKey="price" tick={{ fontSize: 12 }}>
<Label value="Price" offset={10} position="top" />
</YAxis>
<Tooltip />
<Line
type="monotone"
dataKey="price"
stroke="#222222"
strokeWidth={1}
dot={false}
>
<Label value="Price" offset={10} position="top" />
</Line>
<ReferenceLine
y={auctions[0].prices[auctions[0].prices.length - 1].price}
label={`Floor Price: ${auctions[0].prices[auctions[0].prices.length - 1].price}`}
stroke="red"
strokeDasharray="3 3"
/>
</LineChart>
</ResponsiveContainer>
)}
</div>
);
}
Expand Down
2 changes: 1 addition & 1 deletion examples/vite/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ body {
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: #282c34;
background-color: #f0f0f0;
}

code {
Expand Down
Loading

0 comments on commit 7490a95

Please sign in to comment.