Initial @aere/sdk v0.1.0 — typed contract clients for AERE L1
This commit is contained in:
commit
83f837b9b0
79
README.md
Normal file
79
README.md
Normal file
@ -0,0 +1,79 @@
|
||||
# @aere/sdk
|
||||
|
||||
Official AERE Network TypeScript SDK. Wraps `ethers v6` with typed contract clients for every deployed AERE L1 contract — staking, lending, stablecoin, swap, bridge, identity (KYC), Lightning channels, ZK rollup, faucet.
|
||||
|
||||
Designed for **Bank28-class neobank backends**: a single `AereClient` gives you everything you need to integrate AERE as the on-chain layer of a regulated neobank.
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm i @aere/sdk ethers
|
||||
```
|
||||
|
||||
## Quickstart
|
||||
|
||||
```ts
|
||||
import { AereClient } from '@aere/sdk';
|
||||
import { ethers } from 'ethers';
|
||||
|
||||
const aere = new AereClient({ privateKey: process.env.OPS_PRIVATE_KEY });
|
||||
|
||||
// Multi-asset balance for a user
|
||||
const portfolio = await aere.getPortfolio('0xUser…');
|
||||
console.log(ethers.formatEther(portfolio.aere), 'AERE');
|
||||
console.log(ethers.formatEther(portfolio.aereUsd), 'AereUSD');
|
||||
|
||||
// Lock 100 AERE for 90 days at 15% APY (tier 1)
|
||||
await aere.staking.lockTier90(ethers.parseEther('100'));
|
||||
|
||||
// Attest that the user cleared KYC tier 1 (writes to AereIdentity)
|
||||
const oneYear = Math.floor(Date.now() / 1000) + 365 * 86400;
|
||||
await aere.identity.addClaim(
|
||||
'0xUser…',
|
||||
'kyc-tier-1',
|
||||
ethers.keccak256(ethers.toUtf8Bytes('SUMSUB:applicant-id-12345')),
|
||||
oneYear,
|
||||
);
|
||||
|
||||
// Watch for incoming AERE deposits — for a Bank28 webhook
|
||||
const unsubscribe = await aere.watchTransfersTo('0xUser…', tx => {
|
||||
console.log(`User received ${ethers.formatEther(tx.value)} AERE in tx ${tx.hash}`);
|
||||
// → credit Bank28 user account, fire webhook to UI
|
||||
});
|
||||
```
|
||||
|
||||
## What's in the box
|
||||
|
||||
- `AereClient` — top-level handle; pass a `privateKey` or `signer`.
|
||||
- `aere.staking` — locked staking V2 (4 tiers, 10–30% APY).
|
||||
- `aere.stakingV1` — delegated 8% APY staking.
|
||||
- `aere.lending` — supply / borrow against AERE collateral.
|
||||
- `aere.stable` — AereUSD CDP-style stablecoin (AERE-collateralised, NOT USD-reserve-backed).
|
||||
- `aere.identity` — KYC attestation registry (`addClaim` / `revokeClaim` / `hasValidClaim`).
|
||||
- `aere.bridge` — federated lock-and-release to ETH/BSC/Polygon/etc.
|
||||
- `aere.swap` — AMM (Uniswap V2 fork) with pair handles.
|
||||
- `aere.lightning` — off-chain payment channels.
|
||||
- `aere.faucet` — programmatic faucet (rarely needed in production).
|
||||
- `aere.waere` — wrapped native AERE for DeFi.
|
||||
- `AERE_MAINNET` — canonical address book + RPC URLs.
|
||||
|
||||
## Network parameters
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| Chain ID | 2800 (`0xAF0`) |
|
||||
| RPC | `https://rpc.aere.network` |
|
||||
| WSS | `wss://wss.aere.network` |
|
||||
| Indexer | `https://api.aere.network` |
|
||||
| Explorer | `https://explorer.aere.network` |
|
||||
|
||||
## Honest constraints
|
||||
|
||||
- **Non-custodial.** End users hold their own keys. For consumer neobanks use Privy / Magic / Web3Auth to provision wallets via email/social, then pass that signer into `AereClient`.
|
||||
- **No fiat rails.** AERE is the crypto layer. For fiat IBANs / cards / SEPA / KYC ops you need a BaaS partner (Striga, Dipocket, Modulr, Solaris…).
|
||||
- **AereUSD is AERE-collateralised**, not redeemable for fiat. For real USD on-chain, integrate USDC bridged from Ethereum.
|
||||
- **3 validators today** (path to 7 staged). 0-of-3 fault tolerance — production-but-fragile. Plan accordingly.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
167
package-lock.json
generated
Normal file
167
package-lock.json
generated
Normal file
@ -0,0 +1,167 @@
|
||||
{
|
||||
"name": "@aere/sdk",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@aere/sdk",
|
||||
"version": "0.1.0",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.5.0",
|
||||
"ethers": "^6.13.4",
|
||||
"typescript": "^5.6.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ethers": "^6.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@adraffy/ens-normalize": {
|
||||
"version": "1.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz",
|
||||
"integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@noble/curves": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz",
|
||||
"integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "1.3.2"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/hashes": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz",
|
||||
"integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.19.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.17.tgz",
|
||||
"integrity": "sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/aes-js": {
|
||||
"version": "4.0.0-beta.5",
|
||||
"resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz",
|
||||
"integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ethers": {
|
||||
"version": "6.16.0",
|
||||
"resolved": "https://registry.npmjs.org/ethers/-/ethers-6.16.0.tgz",
|
||||
"integrity": "sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/ethers-io/"
|
||||
},
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@adraffy/ens-normalize": "1.10.1",
|
||||
"@noble/curves": "1.2.0",
|
||||
"@noble/hashes": "1.3.2",
|
||||
"@types/node": "22.7.5",
|
||||
"aes-js": "4.0.0-beta.5",
|
||||
"tslib": "2.7.0",
|
||||
"ws": "8.17.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ethers/node_modules/@types/node": {
|
||||
"version": "22.7.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz",
|
||||
"integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.19.2"
|
||||
}
|
||||
},
|
||||
"node_modules/ethers/node_modules/undici-types": {
|
||||
"version": "6.19.8",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
|
||||
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
|
||||
"integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
|
||||
"dev": true,
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
31
package.json
Normal file
31
package.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "@aere/sdk",
|
||||
"version": "0.1.0",
|
||||
"description": "Official AERE Network SDK — wraps ethers v6 with typed contract clients for the deployed AERE L1 contracts (stablecoin, lending, staking, swap, bridge, identity, Lightning, ZK rollup).",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"files": ["dist", "README.md"],
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "node --test dist/test/*.js"
|
||||
},
|
||||
"keywords": ["aere", "blockchain", "ethereum", "evm", "defi", "neobank", "sdk"],
|
||||
"homepage": "https://aere.network/docs.html",
|
||||
"repository": "https://git.aere.network/aere-network/sdk-js",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"ethers": "^6.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.5.0",
|
||||
"ethers": "^6.13.4",
|
||||
"typescript": "^5.6.0"
|
||||
}
|
||||
}
|
||||
112
src/abis.ts
Normal file
112
src/abis.ts
Normal file
@ -0,0 +1,112 @@
|
||||
/**
|
||||
* Hand-curated ABI fragments — only the methods Bank28-class integrations actually call.
|
||||
* Full ABIs are at https://aere.network/abis/<ContractName>.json
|
||||
*/
|
||||
export const ERC20_ABI = [
|
||||
'function balanceOf(address) view returns (uint256)',
|
||||
'function transfer(address to, uint256 amount) returns (bool)',
|
||||
'function approve(address spender, uint256 amount) returns (bool)',
|
||||
'function allowance(address owner, address spender) view returns (uint256)',
|
||||
'function totalSupply() view returns (uint256)',
|
||||
'function decimals() view returns (uint8)',
|
||||
'function symbol() view returns (string)',
|
||||
'function name() view returns (string)',
|
||||
'event Transfer(address indexed from, address indexed to, uint256 value)',
|
||||
'event Approval(address indexed owner, address indexed spender, uint256 value)',
|
||||
] as const;
|
||||
|
||||
export const WAERE_ABI = [
|
||||
...ERC20_ABI,
|
||||
'function deposit() payable',
|
||||
'function withdraw(uint256 amount)',
|
||||
] as const;
|
||||
|
||||
export const STAKING_V2_ABI = [
|
||||
'function lock(uint256 tier) external payable', // tier 0..3 → 30/90/180/365 days
|
||||
'function withdraw(uint256 lockId) external',
|
||||
'function earlyExit(uint256 lockId) external',
|
||||
'function getLocks(address user) external view returns (tuple(uint256 amount, uint64 startTime, uint64 unlockTime, uint8 tier, bool withdrawn)[])',
|
||||
'function tierAPY(uint256 tier) external view returns (uint256)', // basis points
|
||||
'function pendingRewards(address user, uint256 lockId) external view returns (uint256)',
|
||||
] as const;
|
||||
|
||||
export const STAKING_V1_ABI = [
|
||||
'function delegate(address validator) external payable',
|
||||
'function undelegate(address validator, uint256 amount) external',
|
||||
'function claimRewards(address validator) external',
|
||||
'function balanceOf(address user) external view returns (uint256)',
|
||||
'function pendingRewards(address user, address validator) external view returns (uint256)',
|
||||
'function currentAPR() external view returns (uint256)', // basis points
|
||||
] as const;
|
||||
|
||||
export const LENDING_ABI = [
|
||||
'function supply(uint256 amount) external payable',
|
||||
'function withdraw(uint256 amount) external',
|
||||
'function lockCollateral(uint256 amount) external payable',
|
||||
'function borrow(uint256 amount) external',
|
||||
'function repay(uint256 amount) external payable',
|
||||
'function getAccount(address user) external view returns (tuple(uint256 supplied, uint256 borrowed, uint256 collateral))',
|
||||
'function supplyAPY() external view returns (uint256)', // basis points
|
||||
'function borrowAPY() external view returns (uint256)',
|
||||
'function ltvLimit() external view returns (uint256)', // basis points (e.g. 7500 = 75%)
|
||||
] as const;
|
||||
|
||||
export const STABLE_ABI = [
|
||||
...ERC20_ABI,
|
||||
'function depositCollateral() external payable',
|
||||
'function withdrawCollateral(uint256 amount) external',
|
||||
'function mint(uint256 amount) external',
|
||||
'function burn(uint256 amount) external',
|
||||
'function getVault(address user) external view returns (tuple(uint256 collateral, uint256 debt))',
|
||||
'function collateralRatio(address user) external view returns (uint256)', // basis points
|
||||
'function liquidationThreshold() external view returns (uint256)',
|
||||
'function minCollateralRatio() external view returns (uint256)',
|
||||
] as const;
|
||||
|
||||
export const IDENTITY_ABI = [
|
||||
'function addClaim(address subject, bytes32 claimType, bytes32 valueHash, uint64 expires) external',
|
||||
'function revokeClaim(address subject, bytes32 claimType) external',
|
||||
'function getClaim(address subject, bytes32 claimType, address attestor) external view returns (tuple(bytes32 valueHash, uint64 issued, uint64 expires, bool revoked))',
|
||||
'function hasValidClaim(address subject, bytes32 claimType, address attestor) external view returns (bool)',
|
||||
'event ClaimAdded(address indexed subject, bytes32 indexed claimType, address indexed attestor, uint64 expires)',
|
||||
'event ClaimRevoked(address indexed subject, bytes32 indexed claimType, address indexed attestor)',
|
||||
] as const;
|
||||
|
||||
export const BRIDGE_ABI = [
|
||||
'function lockAndBridge(uint256 toChainId, address recipient) external payable',
|
||||
'function release(uint256 srcChainId, uint256 nonce, address recipient, uint256 amount, bytes[] calldata signatures) external',
|
||||
'function isReleased(uint256 srcChainId, uint256 nonce) external view returns (bool)',
|
||||
'function threshold() external view returns (uint256)',
|
||||
'event Locked(uint256 indexed nonce, uint256 indexed toChainId, address indexed recipient, uint256 amount)',
|
||||
'event Released(uint256 indexed srcChainId, uint256 indexed nonce, address indexed recipient, uint256 amount)',
|
||||
] as const;
|
||||
|
||||
export const FAUCET_ABI = [
|
||||
'function claim() external',
|
||||
'function lastClaim(address user) external view returns (uint64)',
|
||||
'function dripAmount() external view returns (uint256)',
|
||||
'function cooldown() external view returns (uint64)',
|
||||
] as const;
|
||||
|
||||
export const SWAP_FACTORY_ABI = [
|
||||
'function getPair(address tokenA, address tokenB) external view returns (address)',
|
||||
'function createPair(address tokenA, address tokenB) external returns (address)',
|
||||
'function allPairsLength() external view returns (uint256)',
|
||||
'function allPairs(uint256) external view returns (address)',
|
||||
] as const;
|
||||
|
||||
export const SWAP_PAIR_ABI = [
|
||||
'function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast)',
|
||||
'function token0() external view returns (address)',
|
||||
'function token1() external view returns (address)',
|
||||
'function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external',
|
||||
] as const;
|
||||
|
||||
export const LIGHTNING_CHANNELS_ABI = [
|
||||
'function open(address counterparty) external payable returns (uint256 id)',
|
||||
'function fund(uint256 id) external payable',
|
||||
'function closeWithState(uint256 id, uint256 balanceA, uint256 balanceB, uint256 nonce, tuple(address payer, address payee, uint256 amount, bytes32 hashlock, uint64 timeout, uint8 status)[] htlcs, bytes sigA, bytes sigB) external',
|
||||
'function settle(uint256 id) external',
|
||||
'function channels(uint256) view returns (address partyA, address partyB, uint256 balanceA, uint256 balanceB, uint256 nonce, uint64 challengeDeadline, uint8 status)',
|
||||
'function getHTLCs(uint256 id) view returns (tuple(address payer, address payee, uint256 amount, bytes32 hashlock, uint64 timeout, uint8 status)[])',
|
||||
] as const;
|
||||
77
src/addresses.ts
Normal file
77
src/addresses.ts
Normal file
@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Canonical AERE Network mainnet contract addresses (chain 2800).
|
||||
* Last updated: 2026-05-03. Source of truth: https://aere.network/docs.html
|
||||
*/
|
||||
export const AERE_MAINNET = {
|
||||
chainId: 2800,
|
||||
rpc: 'https://rpc.aere.network',
|
||||
ws: 'wss://wss.aere.network',
|
||||
explorer: 'https://explorer.aere.network',
|
||||
indexer: 'https://api.aere.network',
|
||||
|
||||
// Core
|
||||
WAERE: '0x805193E3d03AFbffced984f43C10b56D7F7E0b35',
|
||||
AereToken: '0xf0A13823A4bFa86358Fe30aaf1f44A36AcbCf399',
|
||||
AereGovernance: '0x3280518e571fBaB2eF9C7138c1251a89A849f773',
|
||||
AereGovernanceV2: '0xc0F76914d1538c079f07BDeBDd00Ce5b9f791d83',
|
||||
AereTreasury: '0x658dD2CD1F798AAb19fEc8FF69A270B2d192CaD1',
|
||||
AereSecurity: '0x687933AE7ea4927867AC227F1b60d476003e6119',
|
||||
AereConsensus: '0xf0a8df7BDc25721892475B21271e52D77B0e84DC',
|
||||
|
||||
// Staking
|
||||
AereStaking: '0x78a72669a8C48FaC02E7BD8C76baEca6e6a809A7',
|
||||
AereStakingV2: '0x1d4444AaD20Beb034c0A97D2E32cdAD06E80e28D',
|
||||
AereYieldFarm: '0xf7C78Cfad1c2CB92051CB1fF7afeaae1A96A7D62',
|
||||
|
||||
// DeFi
|
||||
AereSwapFactory: '0xDdBe942aD9eB0F3E7C541BdCF7CC2cfA29d35aE4',
|
||||
AereLending: '0xdAd25D2163187dF8aaecf9eA31b6355315bb69F1',
|
||||
AereStable: '0xa44178085387bcCED29C8d51b05976D5e04D5C0E',
|
||||
AereOracle: '0xebFb8BBc2955719bb11AC460b6fc47f46F3356EB',
|
||||
|
||||
// Identity / KYC attestation
|
||||
AereIdentity: '0xfd8dF7fc2FB7bA2019c5ef7df31c204589B6DAEe',
|
||||
|
||||
// Bridge
|
||||
AereBridge: '0x71944DD6A57B9e0530ea86aC577a4F8F57037D7E',
|
||||
AereBridgeCounterparty: '0xda6F00570090eC7759582f0b574269F1d96a7613',
|
||||
WAEREForeign: '0xd7190f47FA7e8D95E5f09f249E479E836CcC1b3f',
|
||||
|
||||
// Faucet / Mining
|
||||
AereFaucet: '0xaD305e4D91e0a9160Bd338Fd1ecb2Ee1645daC44',
|
||||
AereMiningSubscription: '0x267035e16f6F34633fC91f8a410d21A24EB1403E',
|
||||
AereMiningPool: '0x772089A61E9d0C7745bA98487159C688CD9aED5C',
|
||||
|
||||
// Burn / supply
|
||||
AereFeeBurnVault: '0xF0a90fEA2FDA12CC2545ddAa817F5C253F348801',
|
||||
AereDAOBurner: '0x31642bD7901A0405950026072c121bC3Cf25F4fC',
|
||||
|
||||
// NFT
|
||||
AereNFT: '0xeb5420EdabD616499acD037E812cbb6911a890bC',
|
||||
AereNFTMarketplace: '0xF8bDDad4aDACF9d38711e8f9aFC8a2697aBF0d47',
|
||||
|
||||
// Layer 2
|
||||
AerePaymentChannels: '0xAbDb01d9A4f41792129b2654Fb6DDB9689360DEc',
|
||||
AereLightningChannels: '0xc58Fc171C962C1C8AC356538FdFd2E3f04c15B62',
|
||||
AereChannelRegistry: '0x8Eba6a0E0875FE5b02A75cfF09E0fB7ACa9CeDfE',
|
||||
AereHTLC: '0x71851094e5bAaC3e70Ca76A399510B2Ed9100988',
|
||||
AereShardCoordinator: '0x852e07F2619F7F4Ad10D9F2AC681310301d99528',
|
||||
|
||||
// ZK
|
||||
AereZKVerifierGroth16: '0x94AF0740ad4b149F0bb860b0Dda61027322Bc29F',
|
||||
AereZKCommitments: '0x34F7b38dDC6b9d4f2ADC165AcF2b22B2349AA299',
|
||||
AereZKRollup8Verifier: '0xC6936869D0F2eA227d92e0DdC709c6BCB1Cf4548',
|
||||
AereZKRollup8: '0x74cdEbdd929A430037f68CBDB85EC04a89cb623e',
|
||||
AereZKRollup: '0x6F5c279A3436d8b21AF6f8f7E48174A12D4a94a1',
|
||||
AereZKRollupVerifier: '0x99fe69077B3DDaA81B94D0F95f6724F6819CC320',
|
||||
|
||||
// Plasma — 6 production chains
|
||||
AerePlasmaChain1: '0xFBd34Ad45ef07b0B7616E77a8a6cef2cb62f98d4',
|
||||
AerePlasmaChain2: '0xE4E53a1eb1F6C40bbD334C191901dBF99BCb8af0',
|
||||
AerePlasmaChain3: '0x584b89a91445BD69F214d30F040E09cA6db9c5c8',
|
||||
AerePlasmaChain4: '0xb5456D48Bfda70635c13b6cBE1ad0310Dc0171aD',
|
||||
AerePlasmaChain5: '0x9CA479c8c52c0EBb4599319a36a5a017BCC70628',
|
||||
AerePlasmaChain6: '0xA6BFECa9f5d6E7728883e71A10006Cd522Fe40b3',
|
||||
} as const;
|
||||
|
||||
export type AereContractName = keyof Omit<typeof AERE_MAINNET, 'chainId' | 'rpc' | 'ws' | 'explorer' | 'indexer'>;
|
||||
261
src/client.ts
Normal file
261
src/client.ts
Normal file
@ -0,0 +1,261 @@
|
||||
import {
|
||||
Contract, JsonRpcProvider, Wallet, ethers, type Provider, type Signer,
|
||||
type ContractRunner, WebSocketProvider, keccak256, toUtf8Bytes,
|
||||
} from 'ethers';
|
||||
import { AERE_MAINNET } from './addresses.js';
|
||||
import {
|
||||
ERC20_ABI, WAERE_ABI, STAKING_V2_ABI, STAKING_V1_ABI, LENDING_ABI, STABLE_ABI,
|
||||
IDENTITY_ABI, BRIDGE_ABI, FAUCET_ABI, SWAP_FACTORY_ABI, SWAP_PAIR_ABI, LIGHTNING_CHANNELS_ABI,
|
||||
} from './abis.js';
|
||||
|
||||
export interface AereClientOptions {
|
||||
rpcUrl?: string; // default https://rpc.aere.network
|
||||
wsUrl?: string; // default wss://wss.aere.network
|
||||
privateKey?: string; // optional — if provided, becomes the default signer
|
||||
signer?: Signer; // alternatively pass a pre-built signer (e.g. browser wallet)
|
||||
}
|
||||
|
||||
/**
|
||||
* Top-level AERE Network client. Provides a typed handle to every deployed contract
|
||||
* Bank28-class integrations need.
|
||||
*
|
||||
* @example
|
||||
* const aere = new AereClient({ privateKey: process.env.PK });
|
||||
* const bal = await aere.getNativeBalance(userAddr);
|
||||
* await aere.staking.lockTier1(ethers.parseEther('100')); // 90-day lock
|
||||
*/
|
||||
export class AereClient {
|
||||
readonly provider: Provider;
|
||||
readonly signer?: Signer;
|
||||
readonly chainId = AERE_MAINNET.chainId;
|
||||
readonly addresses = AERE_MAINNET;
|
||||
|
||||
constructor(opts: AereClientOptions = {}) {
|
||||
const rpc = opts.rpcUrl ?? AERE_MAINNET.rpc;
|
||||
this.provider = new JsonRpcProvider(rpc, {
|
||||
name: 'aere', chainId: AERE_MAINNET.chainId,
|
||||
});
|
||||
if (opts.signer) this.signer = opts.signer;
|
||||
else if (opts.privateKey) this.signer = new Wallet(opts.privateKey, this.provider);
|
||||
}
|
||||
|
||||
// ────────────────────────────── Chain primitives ──────────────────────────────
|
||||
|
||||
async getBlockNumber(): Promise<number> {
|
||||
return Number(await this.provider.getBlockNumber());
|
||||
}
|
||||
async getNativeBalance(addr: string): Promise<bigint> {
|
||||
return this.provider.getBalance(addr);
|
||||
}
|
||||
async getValidators(): Promise<string[]> {
|
||||
const res: any = await (this.provider as any).send('qbft_getValidatorsByBlockNumber', ['latest']);
|
||||
return Array.isArray(res) ? res : [];
|
||||
}
|
||||
async sendNative(to: string, amountWei: bigint, sigOverride?: Signer): Promise<string> {
|
||||
const s = sigOverride ?? this.signer;
|
||||
if (!s) throw new Error('AereClient: no signer configured');
|
||||
const tx = await s.sendTransaction({ to, value: amountWei });
|
||||
return tx.hash;
|
||||
}
|
||||
|
||||
// ────────────────────────────── Contract handles ──────────────────────────────
|
||||
|
||||
private contract(addr: string, abi: readonly string[], signer = false): Contract {
|
||||
const runner: ContractRunner = (signer ? this.signer ?? this.provider : this.provider) as ContractRunner;
|
||||
return new Contract(addr, abi as any, runner);
|
||||
}
|
||||
|
||||
/** WAERE — wrapped native AERE (ERC-20) */
|
||||
get waere() {
|
||||
const c = this.contract(this.addresses.WAERE, WAERE_ABI, true);
|
||||
return {
|
||||
contract: c,
|
||||
balanceOf: (a: string) => c.balanceOf(a) as Promise<bigint>,
|
||||
deposit: (amountWei: bigint) => c.deposit({ value: amountWei }),
|
||||
withdraw: (amountWei: bigint) => c.withdraw(amountWei),
|
||||
transfer: (to: string, amount: bigint) => c.transfer(to, amount),
|
||||
};
|
||||
}
|
||||
|
||||
/** AereStakingV2 — locked-period staking with 4 tiers (30/90/180/365 days, 10/15/22/30% APY) */
|
||||
get staking() {
|
||||
const c = this.contract(this.addresses.AereStakingV2, STAKING_V2_ABI, true);
|
||||
return {
|
||||
contract: c,
|
||||
tierAPY: (tier: 0 | 1 | 2 | 3) => c.tierAPY(tier) as Promise<bigint>,
|
||||
lock: (tier: 0 | 1 | 2 | 3, amountWei: bigint) => c.lock(tier, { value: amountWei }),
|
||||
lockTier30: (a: bigint) => c.lock(0, { value: a }),
|
||||
lockTier90: (a: bigint) => c.lock(1, { value: a }),
|
||||
lockTier180: (a: bigint) => c.lock(2, { value: a }),
|
||||
lockTier365: (a: bigint) => c.lock(3, { value: a }),
|
||||
withdraw: (lockId: number) => c.withdraw(lockId),
|
||||
earlyExit: (lockId: number) => c.earlyExit(lockId),
|
||||
getLocks: (user: string) => c.getLocks(user),
|
||||
pendingRewards: (user: string, lockId: number) => c.pendingRewards(user, lockId) as Promise<bigint>,
|
||||
};
|
||||
}
|
||||
|
||||
/** AereStaking V1 — delegated 8% APY staking */
|
||||
get stakingV1() {
|
||||
const c = this.contract(this.addresses.AereStaking, STAKING_V1_ABI, true);
|
||||
return {
|
||||
contract: c,
|
||||
delegate: (validator: string, amountWei: bigint) => c.delegate(validator, { value: amountWei }),
|
||||
undelegate: (validator: string, amount: bigint) => c.undelegate(validator, amount),
|
||||
claimRewards: (validator: string) => c.claimRewards(validator),
|
||||
balanceOf: (user: string) => c.balanceOf(user) as Promise<bigint>,
|
||||
pendingRewards: (user: string, validator: string) => c.pendingRewards(user, validator) as Promise<bigint>,
|
||||
currentAPR: () => c.currentAPR() as Promise<bigint>,
|
||||
};
|
||||
}
|
||||
|
||||
/** AereLending — supply / borrow against AERE collateral */
|
||||
get lending() {
|
||||
const c = this.contract(this.addresses.AereLending, LENDING_ABI, true);
|
||||
return {
|
||||
contract: c,
|
||||
supply: (amountWei: bigint) => c.supply(amountWei, { value: amountWei }),
|
||||
withdraw: (amount: bigint) => c.withdraw(amount),
|
||||
lockCollateral: (amountWei: bigint) => c.lockCollateral(amountWei, { value: amountWei }),
|
||||
borrow: (amount: bigint) => c.borrow(amount),
|
||||
repay: (amountWei: bigint) => c.repay(amountWei, { value: amountWei }),
|
||||
getAccount: (user: string) => c.getAccount(user),
|
||||
supplyAPY: () => c.supplyAPY() as Promise<bigint>,
|
||||
borrowAPY: () => c.borrowAPY() as Promise<bigint>,
|
||||
ltvLimit: () => c.ltvLimit() as Promise<bigint>,
|
||||
};
|
||||
}
|
||||
|
||||
/** AereStable (AereUSD) — CDP-style stablecoin · AERE-collateralised, NOT USD-reserve-backed */
|
||||
get stable() {
|
||||
const c = this.contract(this.addresses.AereStable, STABLE_ABI, true);
|
||||
return {
|
||||
contract: c,
|
||||
balanceOf: (a: string) => c.balanceOf(a) as Promise<bigint>,
|
||||
depositCollateral: (amountWei: bigint) => c.depositCollateral({ value: amountWei }),
|
||||
withdrawCollateral: (amount: bigint) => c.withdrawCollateral(amount),
|
||||
mint: (amount: bigint) => c.mint(amount),
|
||||
burn: (amount: bigint) => c.burn(amount),
|
||||
getVault: (user: string) => c.getVault(user),
|
||||
collateralRatio: (user: string) => c.collateralRatio(user) as Promise<bigint>,
|
||||
};
|
||||
}
|
||||
|
||||
/** AereIdentity — DID / KYC attestation registry */
|
||||
get identity() {
|
||||
const c = this.contract(this.addresses.AereIdentity, IDENTITY_ABI, true);
|
||||
return {
|
||||
contract: c,
|
||||
/** Attest that `subject` has cleared a KYC tier. `claimType` is hashed via keccak256. */
|
||||
addClaim: (subject: string, claimType: string, valueHash: string, expiresUnix: number) =>
|
||||
c.addClaim(subject, keccak256(toUtf8Bytes(claimType)), valueHash, expiresUnix),
|
||||
revokeClaim: (subject: string, claimType: string) =>
|
||||
c.revokeClaim(subject, keccak256(toUtf8Bytes(claimType))),
|
||||
getClaim: (subject: string, claimType: string, attestor: string) =>
|
||||
c.getClaim(subject, keccak256(toUtf8Bytes(claimType)), attestor),
|
||||
hasValidClaim: (subject: string, claimType: string, attestor: string) =>
|
||||
c.hasValidClaim(subject, keccak256(toUtf8Bytes(claimType)), attestor) as Promise<boolean>,
|
||||
};
|
||||
}
|
||||
|
||||
/** AereBridge — federated lock-and-release to 8 EVM chains */
|
||||
get bridge() {
|
||||
const c = this.contract(this.addresses.AereBridge, BRIDGE_ABI, true);
|
||||
return {
|
||||
contract: c,
|
||||
lockAndBridge: (toChainId: number, recipient: string, amountWei: bigint) =>
|
||||
c.lockAndBridge(toChainId, recipient, { value: amountWei }),
|
||||
isReleased: (srcChainId: number, nonce: bigint) =>
|
||||
c.isReleased(srcChainId, nonce) as Promise<boolean>,
|
||||
threshold: () => c.threshold() as Promise<bigint>,
|
||||
};
|
||||
}
|
||||
|
||||
/** AereFaucet — 0.05 AERE drip per address per 24h */
|
||||
get faucet() {
|
||||
const c = this.contract(this.addresses.AereFaucet, FAUCET_ABI, true);
|
||||
return {
|
||||
contract: c,
|
||||
claim: () => c.claim(),
|
||||
lastClaim: (user: string) => c.lastClaim(user) as Promise<bigint>,
|
||||
dripAmount: () => c.dripAmount() as Promise<bigint>,
|
||||
cooldown: () => c.cooldown() as Promise<bigint>,
|
||||
};
|
||||
}
|
||||
|
||||
/** AereSwapFactory + on-demand pair handles */
|
||||
get swap() {
|
||||
const factory = this.contract(this.addresses.AereSwapFactory, SWAP_FACTORY_ABI, true);
|
||||
return {
|
||||
factory,
|
||||
getPair: (tokenA: string, tokenB: string) => factory.getPair(tokenA, tokenB) as Promise<string>,
|
||||
pair: (pairAddr: string) => this.contract(pairAddr, SWAP_PAIR_ABI, true),
|
||||
};
|
||||
}
|
||||
|
||||
/** AereLightningChannels — off-chain payment channels with HTLCs */
|
||||
get lightning() {
|
||||
const c = this.contract(this.addresses.AereLightningChannels, LIGHTNING_CHANNELS_ABI, true);
|
||||
return {
|
||||
contract: c,
|
||||
open: (counterparty: string, depositWei: bigint) =>
|
||||
c.open(counterparty, { value: depositWei }),
|
||||
fund: (id: bigint, amountWei: bigint) => c.fund(id, { value: amountWei }),
|
||||
channels: (id: bigint) => c.channels(id),
|
||||
getHTLCs: (id: bigint) => c.getHTLCs(id),
|
||||
};
|
||||
}
|
||||
|
||||
// ────────────────────────────── Higher-level helpers ──────────────────────────────
|
||||
|
||||
/** Convenience: ERC-20 balance for any token (USDC bridged from Ethereum, etc.) */
|
||||
async erc20BalanceOf(tokenAddr: string, holder: string): Promise<bigint> {
|
||||
const c = new Contract(tokenAddr, ERC20_ABI, this.provider);
|
||||
return c.balanceOf(holder) as Promise<bigint>;
|
||||
}
|
||||
|
||||
/** Convenience: send any ERC-20 token */
|
||||
async erc20Transfer(tokenAddr: string, to: string, amount: bigint): Promise<string> {
|
||||
if (!this.signer) throw new Error('no signer');
|
||||
const c = new Contract(tokenAddr, ERC20_ABI, this.signer);
|
||||
const tx = await c.transfer(to, amount);
|
||||
return tx.hash;
|
||||
}
|
||||
|
||||
/** Convenience: aggregate a Bank28-style multi-asset balance for a user */
|
||||
async getPortfolio(user: string): Promise<{
|
||||
aere: bigint;
|
||||
waere: bigint;
|
||||
aereUsd: bigint;
|
||||
}> {
|
||||
const [aere, waere, aereUsd] = await Promise.all([
|
||||
this.getNativeBalance(user),
|
||||
this.waere.balanceOf(user),
|
||||
this.stable.balanceOf(user),
|
||||
]);
|
||||
return { aere, waere, aereUsd };
|
||||
}
|
||||
|
||||
/** Subscribe to new blocks via WebSocket. Returns an unsubscribe fn. */
|
||||
watchBlocks(handler: (blockNumber: number) => void, wsUrl?: string): () => void {
|
||||
const ws = new WebSocketProvider(wsUrl ?? AERE_MAINNET.ws);
|
||||
ws.on('block', handler);
|
||||
return () => { ws.removeAllListeners('block'); ws.destroy(); };
|
||||
}
|
||||
|
||||
/** Watch native AERE deposits to a specific address. Useful for "credit user's neobank account when they receive AERE". */
|
||||
async watchTransfersTo(addr: string, handler: (tx: { hash: string; value: bigint; from: string; blockNumber: number }) => void, wsUrl?: string): Promise<() => void> {
|
||||
const ws = new WebSocketProvider(wsUrl ?? AERE_MAINNET.ws);
|
||||
const onBlock = async (blockNumber: number) => {
|
||||
const block = await ws.getBlock(blockNumber, true);
|
||||
if (!block) return;
|
||||
for (const tx of block.prefetchedTransactions ?? []) {
|
||||
if (tx.to?.toLowerCase() === addr.toLowerCase() && tx.value > 0n) {
|
||||
handler({ hash: tx.hash, value: tx.value, from: tx.from, blockNumber });
|
||||
}
|
||||
}
|
||||
};
|
||||
ws.on('block', onBlock);
|
||||
return () => { ws.off('block', onBlock); ws.destroy(); };
|
||||
}
|
||||
}
|
||||
6
src/index.ts
Normal file
6
src/index.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export { AereClient, type AereClientOptions } from './client.js';
|
||||
export { AERE_MAINNET, type AereContractName } from './addresses.js';
|
||||
export {
|
||||
ERC20_ABI, WAERE_ABI, STAKING_V2_ABI, STAKING_V1_ABI, LENDING_ABI, STABLE_ABI,
|
||||
IDENTITY_ABI, BRIDGE_ABI, FAUCET_ABI, SWAP_FACTORY_ABI, SWAP_PAIR_ABI, LIGHTNING_CHANNELS_ABI,
|
||||
} from './abis.js';
|
||||
16
tsconfig.json
Normal file
16
tsconfig.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2022",
|
||||
"module": "es2022",
|
||||
"moduleResolution": "node",
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"strict": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user