diff --git a/src/apps/airswap/airswap.definition.ts b/src/apps/airswap/airswap.definition.ts new file mode 100644 index 000000000..ca33714a9 --- /dev/null +++ b/src/apps/airswap/airswap.definition.ts @@ -0,0 +1,30 @@ +import { Register } from '~app-toolkit/decorators'; +import { AppDefinition } from '~app/app.definition'; +import { GroupType, ProtocolAction, ProtocolTag } from '~app/app.interface'; +import { Network } from '~types/network.interface'; + +export const AIRSWAP_DEFINITION = { + id: 'airswap', + name: 'Airswap', + description: + 'AirSwap is an open community of developers, designers, writers, and tinkerers building decentralized trading systems. Protocol fees are automatically distributed to contributors.', + url: 'https://airswap.io', + symbol: 'AST', + groups: { + sAST: {id: 's-ast', type: GroupType.TOKEN}, + }, + tags: [ProtocolTag.EXCHANGE], + supportedNetworks: { + [Network.ETHEREUM_MAINNET]: [ProtocolAction.VIEW], + }, + primaryColor: '#2B71FF', +}; + +@Register.AppDefinition(AIRSWAP_DEFINITION.id) +export class AirswapAppDefinition extends AppDefinition { + constructor() { + super(AIRSWAP_DEFINITION); + } +} + +export default AIRSWAP_DEFINITION; diff --git a/src/apps/airswap/airswap.module.ts b/src/apps/airswap/airswap.module.ts new file mode 100644 index 000000000..6ab01a04f --- /dev/null +++ b/src/apps/airswap/airswap.module.ts @@ -0,0 +1,18 @@ +import { Module } from '@nestjs/common'; + +import { AbstractDynamicApp } from '~app/app.dynamic-module'; + +import { AirswapAppDefinition } from './airswap.definition'; +import { AirswapContractFactory } from './contracts'; +import { EthereumAirswapBalanceFetcher } from './ethereum/airswap.balance-fetcher'; +import { EthereumAirswapSAstTokenFetcher } from './ethereum/airswap.s-ast.token-fetcher'; + +@Module({ + providers: [ + AirswapAppDefinition, + AirswapContractFactory, + EthereumAirswapBalanceFetcher, + EthereumAirswapSAstTokenFetcher, + ], +}) +export class AirswapAppModule extends AbstractDynamicApp() {} diff --git a/src/apps/airswap/assets/logo.png b/src/apps/airswap/assets/logo.png new file mode 100644 index 000000000..9bab5b526 Binary files /dev/null and b/src/apps/airswap/assets/logo.png differ diff --git a/src/apps/airswap/contracts/abis/staking.json b/src/apps/airswap/contracts/abis/staking.json new file mode 100644 index 000000000..80e3d1402 --- /dev/null +++ b/src/apps/airswap/contracts/abis/staking.json @@ -0,0 +1,243 @@ +[ + { + "inputs": [ + { "internalType": "contract ERC20", "name": "_token", "type": "address" }, + { "internalType": "string", "name": "_name", "type": "string" }, + { "internalType": "string", "name": "_symbol", "type": "string" }, + { "internalType": "uint256", "name": "_duration", "type": "uint256" }, + { "internalType": "uint256", "name": "_minDelay", "type": "uint256" } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { "anonymous": false, "inputs": [], "name": "CancelDurationChange", "type": "event" }, + { + "anonymous": false, + "inputs": [{ "indexed": true, "internalType": "uint256", "name": "newDuration", "type": "uint256" }], + "name": "CompleteDurationChange", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "delegate", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "account", "type": "address" } + ], + "name": "ProposeDelegate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": true, "internalType": "uint256", "name": "unlockTimestamp", "type": "uint256" }], + "name": "ScheduleDurationChange", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "delegate", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "account", "type": "address" } + ], + "name": "SetDelegate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "from", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "tokens", "type": "uint256" } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "accountDelegates", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "available", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "balanceOf", + "outputs": [{ "internalType": "uint256", "name": "total", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "cancelDurationChange", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "decimals", + "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "delegateAccounts", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "duration", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "getStakes", + "outputs": [ + { + "components": [ + { "internalType": "uint256", "name": "duration", "type": "uint256" }, + { "internalType": "uint256", "name": "balance", "type": "uint256" }, + { "internalType": "uint256", "name": "timestamp", "type": "uint256" } + ], + "internalType": "struct IStaking.Stake", + "name": "accountStake", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "delegate", "type": "address" }], + "name": "proposeDelegate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "proposedDelegates", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [{ "internalType": "uint256", "name": "delay", "type": "uint256" }], + "name": "scheduleDurationChange", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "setDelegate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_duration", "type": "uint256" }], + "name": "setDuration", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "string", "name": "_name", "type": "string" }, + { "internalType": "string", "name": "_symbol", "type": "string" } + ], + "name": "setMetaData", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }], + "name": "stake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "account", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "stakeFor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "token", + "outputs": [{ "internalType": "contract ERC20", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "delegate", "type": "address" }], + "name": "unsetDelegate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }], + "name": "unstake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/src/apps/airswap/contracts/ethers/Staking.ts b/src/apps/airswap/contracts/ethers/Staking.ts new file mode 100644 index 000000000..06882e37a --- /dev/null +++ b/src/apps/airswap/contracts/ethers/Staking.ts @@ -0,0 +1,640 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { + BaseContract, + BigNumber, + BigNumberish, + BytesLike, + CallOverrides, + ContractTransaction, + Overrides, + PopulatedTransaction, + Signer, + utils, +} from 'ethers'; +import type { FunctionFragment, Result, EventFragment } from '@ethersproject/abi'; +import type { Listener, Provider } from '@ethersproject/providers'; +import type { TypedEventFilter, TypedEvent, TypedListener, OnEvent } from './common'; + +export declare namespace IStaking { + export type StakeStruct = { + duration: BigNumberish; + balance: BigNumberish; + timestamp: BigNumberish; + }; + + export type StakeStructOutput = [BigNumber, BigNumber, BigNumber] & { + duration: BigNumber; + balance: BigNumber; + timestamp: BigNumber; + }; +} + +export interface StakingInterface extends utils.Interface { + functions: { + 'accountDelegates(address)': FunctionFragment; + 'available(address)': FunctionFragment; + 'balanceOf(address)': FunctionFragment; + 'cancelDurationChange()': FunctionFragment; + 'decimals()': FunctionFragment; + 'delegateAccounts(address)': FunctionFragment; + 'duration()': FunctionFragment; + 'getStakes(address)': FunctionFragment; + 'name()': FunctionFragment; + 'owner()': FunctionFragment; + 'proposeDelegate(address)': FunctionFragment; + 'proposedDelegates(address)': FunctionFragment; + 'renounceOwnership()': FunctionFragment; + 'scheduleDurationChange(uint256)': FunctionFragment; + 'setDelegate(address)': FunctionFragment; + 'setDuration(uint256)': FunctionFragment; + 'setMetaData(string,string)': FunctionFragment; + 'stake(uint256)': FunctionFragment; + 'stakeFor(address,uint256)': FunctionFragment; + 'symbol()': FunctionFragment; + 'token()': FunctionFragment; + 'totalSupply()': FunctionFragment; + 'transferOwnership(address)': FunctionFragment; + 'unsetDelegate(address)': FunctionFragment; + 'unstake(uint256)': FunctionFragment; + }; + + getFunction( + nameOrSignatureOrTopic: + | 'accountDelegates' + | 'available' + | 'balanceOf' + | 'cancelDurationChange' + | 'decimals' + | 'delegateAccounts' + | 'duration' + | 'getStakes' + | 'name' + | 'owner' + | 'proposeDelegate' + | 'proposedDelegates' + | 'renounceOwnership' + | 'scheduleDurationChange' + | 'setDelegate' + | 'setDuration' + | 'setMetaData' + | 'stake' + | 'stakeFor' + | 'symbol' + | 'token' + | 'totalSupply' + | 'transferOwnership' + | 'unsetDelegate' + | 'unstake', + ): FunctionFragment; + + encodeFunctionData(functionFragment: 'accountDelegates', values: [string]): string; + encodeFunctionData(functionFragment: 'available', values: [string]): string; + encodeFunctionData(functionFragment: 'balanceOf', values: [string]): string; + encodeFunctionData(functionFragment: 'cancelDurationChange', values?: undefined): string; + encodeFunctionData(functionFragment: 'decimals', values?: undefined): string; + encodeFunctionData(functionFragment: 'delegateAccounts', values: [string]): string; + encodeFunctionData(functionFragment: 'duration', values?: undefined): string; + encodeFunctionData(functionFragment: 'getStakes', values: [string]): string; + encodeFunctionData(functionFragment: 'name', values?: undefined): string; + encodeFunctionData(functionFragment: 'owner', values?: undefined): string; + encodeFunctionData(functionFragment: 'proposeDelegate', values: [string]): string; + encodeFunctionData(functionFragment: 'proposedDelegates', values: [string]): string; + encodeFunctionData(functionFragment: 'renounceOwnership', values?: undefined): string; + encodeFunctionData(functionFragment: 'scheduleDurationChange', values: [BigNumberish]): string; + encodeFunctionData(functionFragment: 'setDelegate', values: [string]): string; + encodeFunctionData(functionFragment: 'setDuration', values: [BigNumberish]): string; + encodeFunctionData(functionFragment: 'setMetaData', values: [string, string]): string; + encodeFunctionData(functionFragment: 'stake', values: [BigNumberish]): string; + encodeFunctionData(functionFragment: 'stakeFor', values: [string, BigNumberish]): string; + encodeFunctionData(functionFragment: 'symbol', values?: undefined): string; + encodeFunctionData(functionFragment: 'token', values?: undefined): string; + encodeFunctionData(functionFragment: 'totalSupply', values?: undefined): string; + encodeFunctionData(functionFragment: 'transferOwnership', values: [string]): string; + encodeFunctionData(functionFragment: 'unsetDelegate', values: [string]): string; + encodeFunctionData(functionFragment: 'unstake', values: [BigNumberish]): string; + + decodeFunctionResult(functionFragment: 'accountDelegates', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'available', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'balanceOf', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'cancelDurationChange', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'decimals', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'delegateAccounts', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'duration', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'getStakes', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'name', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'owner', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'proposeDelegate', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'proposedDelegates', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'renounceOwnership', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'scheduleDurationChange', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'setDelegate', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'setDuration', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'setMetaData', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'stake', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'stakeFor', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'symbol', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'token', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'totalSupply', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'transferOwnership', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'unsetDelegate', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'unstake', data: BytesLike): Result; + + events: { + 'CancelDurationChange()': EventFragment; + 'CompleteDurationChange(uint256)': EventFragment; + 'OwnershipTransferred(address,address)': EventFragment; + 'ProposeDelegate(address,address)': EventFragment; + 'ScheduleDurationChange(uint256)': EventFragment; + 'SetDelegate(address,address)': EventFragment; + 'Transfer(address,address,uint256)': EventFragment; + }; + + getEvent(nameOrSignatureOrTopic: 'CancelDurationChange'): EventFragment; + getEvent(nameOrSignatureOrTopic: 'CompleteDurationChange'): EventFragment; + getEvent(nameOrSignatureOrTopic: 'OwnershipTransferred'): EventFragment; + getEvent(nameOrSignatureOrTopic: 'ProposeDelegate'): EventFragment; + getEvent(nameOrSignatureOrTopic: 'ScheduleDurationChange'): EventFragment; + getEvent(nameOrSignatureOrTopic: 'SetDelegate'): EventFragment; + getEvent(nameOrSignatureOrTopic: 'Transfer'): EventFragment; +} + +export interface CancelDurationChangeEventObject {} +export type CancelDurationChangeEvent = TypedEvent<[], CancelDurationChangeEventObject>; + +export type CancelDurationChangeEventFilter = TypedEventFilter; + +export interface CompleteDurationChangeEventObject { + newDuration: BigNumber; +} +export type CompleteDurationChangeEvent = TypedEvent<[BigNumber], CompleteDurationChangeEventObject>; + +export type CompleteDurationChangeEventFilter = TypedEventFilter; + +export interface OwnershipTransferredEventObject { + previousOwner: string; + newOwner: string; +} +export type OwnershipTransferredEvent = TypedEvent<[string, string], OwnershipTransferredEventObject>; + +export type OwnershipTransferredEventFilter = TypedEventFilter; + +export interface ProposeDelegateEventObject { + delegate: string; + account: string; +} +export type ProposeDelegateEvent = TypedEvent<[string, string], ProposeDelegateEventObject>; + +export type ProposeDelegateEventFilter = TypedEventFilter; + +export interface ScheduleDurationChangeEventObject { + unlockTimestamp: BigNumber; +} +export type ScheduleDurationChangeEvent = TypedEvent<[BigNumber], ScheduleDurationChangeEventObject>; + +export type ScheduleDurationChangeEventFilter = TypedEventFilter; + +export interface SetDelegateEventObject { + delegate: string; + account: string; +} +export type SetDelegateEvent = TypedEvent<[string, string], SetDelegateEventObject>; + +export type SetDelegateEventFilter = TypedEventFilter; + +export interface TransferEventObject { + from: string; + to: string; + tokens: BigNumber; +} +export type TransferEvent = TypedEvent<[string, string, BigNumber], TransferEventObject>; + +export type TransferEventFilter = TypedEventFilter; + +export interface Staking extends BaseContract { + connect(signerOrProvider: Signer | Provider | string): this; + attach(addressOrName: string): this; + deployed(): Promise; + + interface: StakingInterface; + + queryFilter( + event: TypedEventFilter, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined, + ): Promise>; + + listeners(eventFilter?: TypedEventFilter): Array>; + listeners(eventName?: string): Array; + removeAllListeners(eventFilter: TypedEventFilter): this; + removeAllListeners(eventName?: string): this; + off: OnEvent; + on: OnEvent; + once: OnEvent; + removeListener: OnEvent; + + functions: { + accountDelegates(arg0: string, overrides?: CallOverrides): Promise<[string]>; + + available(account: string, overrides?: CallOverrides): Promise<[BigNumber]>; + + balanceOf(account: string, overrides?: CallOverrides): Promise<[BigNumber] & { total: BigNumber }>; + + cancelDurationChange(overrides?: Overrides & { from?: string | Promise }): Promise; + + decimals(overrides?: CallOverrides): Promise<[number]>; + + delegateAccounts(arg0: string, overrides?: CallOverrides): Promise<[string]>; + + duration(overrides?: CallOverrides): Promise<[BigNumber]>; + + getStakes( + account: string, + overrides?: CallOverrides, + ): Promise< + [IStaking.StakeStructOutput] & { + accountStake: IStaking.StakeStructOutput; + } + >; + + name(overrides?: CallOverrides): Promise<[string]>; + + owner(overrides?: CallOverrides): Promise<[string]>; + + proposeDelegate( + delegate: string, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + proposedDelegates(arg0: string, overrides?: CallOverrides): Promise<[string]>; + + renounceOwnership(overrides?: Overrides & { from?: string | Promise }): Promise; + + scheduleDurationChange( + delay: BigNumberish, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + setDelegate( + account: string, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + setDuration( + _duration: BigNumberish, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + setMetaData( + _name: string, + _symbol: string, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + stake( + amount: BigNumberish, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + stakeFor( + account: string, + amount: BigNumberish, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + symbol(overrides?: CallOverrides): Promise<[string]>; + + token(overrides?: CallOverrides): Promise<[string]>; + + totalSupply(overrides?: CallOverrides): Promise<[BigNumber]>; + + transferOwnership( + newOwner: string, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + unsetDelegate( + delegate: string, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + unstake( + amount: BigNumberish, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + }; + + accountDelegates(arg0: string, overrides?: CallOverrides): Promise; + + available(account: string, overrides?: CallOverrides): Promise; + + balanceOf(account: string, overrides?: CallOverrides): Promise; + + cancelDurationChange(overrides?: Overrides & { from?: string | Promise }): Promise; + + decimals(overrides?: CallOverrides): Promise; + + delegateAccounts(arg0: string, overrides?: CallOverrides): Promise; + + duration(overrides?: CallOverrides): Promise; + + getStakes(account: string, overrides?: CallOverrides): Promise; + + name(overrides?: CallOverrides): Promise; + + owner(overrides?: CallOverrides): Promise; + + proposeDelegate( + delegate: string, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + proposedDelegates(arg0: string, overrides?: CallOverrides): Promise; + + renounceOwnership(overrides?: Overrides & { from?: string | Promise }): Promise; + + scheduleDurationChange( + delay: BigNumberish, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + setDelegate( + account: string, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + setDuration( + _duration: BigNumberish, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + setMetaData( + _name: string, + _symbol: string, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + stake( + amount: BigNumberish, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + stakeFor( + account: string, + amount: BigNumberish, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + symbol(overrides?: CallOverrides): Promise; + + token(overrides?: CallOverrides): Promise; + + totalSupply(overrides?: CallOverrides): Promise; + + transferOwnership( + newOwner: string, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + unsetDelegate( + delegate: string, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + unstake( + amount: BigNumberish, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + callStatic: { + accountDelegates(arg0: string, overrides?: CallOverrides): Promise; + + available(account: string, overrides?: CallOverrides): Promise; + + balanceOf(account: string, overrides?: CallOverrides): Promise; + + cancelDurationChange(overrides?: CallOverrides): Promise; + + decimals(overrides?: CallOverrides): Promise; + + delegateAccounts(arg0: string, overrides?: CallOverrides): Promise; + + duration(overrides?: CallOverrides): Promise; + + getStakes(account: string, overrides?: CallOverrides): Promise; + + name(overrides?: CallOverrides): Promise; + + owner(overrides?: CallOverrides): Promise; + + proposeDelegate(delegate: string, overrides?: CallOverrides): Promise; + + proposedDelegates(arg0: string, overrides?: CallOverrides): Promise; + + renounceOwnership(overrides?: CallOverrides): Promise; + + scheduleDurationChange(delay: BigNumberish, overrides?: CallOverrides): Promise; + + setDelegate(account: string, overrides?: CallOverrides): Promise; + + setDuration(_duration: BigNumberish, overrides?: CallOverrides): Promise; + + setMetaData(_name: string, _symbol: string, overrides?: CallOverrides): Promise; + + stake(amount: BigNumberish, overrides?: CallOverrides): Promise; + + stakeFor(account: string, amount: BigNumberish, overrides?: CallOverrides): Promise; + + symbol(overrides?: CallOverrides): Promise; + + token(overrides?: CallOverrides): Promise; + + totalSupply(overrides?: CallOverrides): Promise; + + transferOwnership(newOwner: string, overrides?: CallOverrides): Promise; + + unsetDelegate(delegate: string, overrides?: CallOverrides): Promise; + + unstake(amount: BigNumberish, overrides?: CallOverrides): Promise; + }; + + filters: { + 'CancelDurationChange()'(): CancelDurationChangeEventFilter; + CancelDurationChange(): CancelDurationChangeEventFilter; + + 'CompleteDurationChange(uint256)'(newDuration?: BigNumberish | null): CompleteDurationChangeEventFilter; + CompleteDurationChange(newDuration?: BigNumberish | null): CompleteDurationChangeEventFilter; + + 'OwnershipTransferred(address,address)'( + previousOwner?: string | null, + newOwner?: string | null, + ): OwnershipTransferredEventFilter; + OwnershipTransferred(previousOwner?: string | null, newOwner?: string | null): OwnershipTransferredEventFilter; + + 'ProposeDelegate(address,address)'(delegate?: string | null, account?: string | null): ProposeDelegateEventFilter; + ProposeDelegate(delegate?: string | null, account?: string | null): ProposeDelegateEventFilter; + + 'ScheduleDurationChange(uint256)'(unlockTimestamp?: BigNumberish | null): ScheduleDurationChangeEventFilter; + ScheduleDurationChange(unlockTimestamp?: BigNumberish | null): ScheduleDurationChangeEventFilter; + + 'SetDelegate(address,address)'(delegate?: string | null, account?: string | null): SetDelegateEventFilter; + SetDelegate(delegate?: string | null, account?: string | null): SetDelegateEventFilter; + + 'Transfer(address,address,uint256)'(from?: string | null, to?: string | null, tokens?: null): TransferEventFilter; + Transfer(from?: string | null, to?: string | null, tokens?: null): TransferEventFilter; + }; + + estimateGas: { + accountDelegates(arg0: string, overrides?: CallOverrides): Promise; + + available(account: string, overrides?: CallOverrides): Promise; + + balanceOf(account: string, overrides?: CallOverrides): Promise; + + cancelDurationChange(overrides?: Overrides & { from?: string | Promise }): Promise; + + decimals(overrides?: CallOverrides): Promise; + + delegateAccounts(arg0: string, overrides?: CallOverrides): Promise; + + duration(overrides?: CallOverrides): Promise; + + getStakes(account: string, overrides?: CallOverrides): Promise; + + name(overrides?: CallOverrides): Promise; + + owner(overrides?: CallOverrides): Promise; + + proposeDelegate(delegate: string, overrides?: Overrides & { from?: string | Promise }): Promise; + + proposedDelegates(arg0: string, overrides?: CallOverrides): Promise; + + renounceOwnership(overrides?: Overrides & { from?: string | Promise }): Promise; + + scheduleDurationChange( + delay: BigNumberish, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + setDelegate(account: string, overrides?: Overrides & { from?: string | Promise }): Promise; + + setDuration( + _duration: BigNumberish, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + setMetaData( + _name: string, + _symbol: string, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + stake(amount: BigNumberish, overrides?: Overrides & { from?: string | Promise }): Promise; + + stakeFor( + account: string, + amount: BigNumberish, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + symbol(overrides?: CallOverrides): Promise; + + token(overrides?: CallOverrides): Promise; + + totalSupply(overrides?: CallOverrides): Promise; + + transferOwnership( + newOwner: string, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + unsetDelegate(delegate: string, overrides?: Overrides & { from?: string | Promise }): Promise; + + unstake(amount: BigNumberish, overrides?: Overrides & { from?: string | Promise }): Promise; + }; + + populateTransaction: { + accountDelegates(arg0: string, overrides?: CallOverrides): Promise; + + available(account: string, overrides?: CallOverrides): Promise; + + balanceOf(account: string, overrides?: CallOverrides): Promise; + + cancelDurationChange(overrides?: Overrides & { from?: string | Promise }): Promise; + + decimals(overrides?: CallOverrides): Promise; + + delegateAccounts(arg0: string, overrides?: CallOverrides): Promise; + + duration(overrides?: CallOverrides): Promise; + + getStakes(account: string, overrides?: CallOverrides): Promise; + + name(overrides?: CallOverrides): Promise; + + owner(overrides?: CallOverrides): Promise; + + proposeDelegate( + delegate: string, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + proposedDelegates(arg0: string, overrides?: CallOverrides): Promise; + + renounceOwnership(overrides?: Overrides & { from?: string | Promise }): Promise; + + scheduleDurationChange( + delay: BigNumberish, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + setDelegate( + account: string, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + setDuration( + _duration: BigNumberish, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + setMetaData( + _name: string, + _symbol: string, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + stake( + amount: BigNumberish, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + stakeFor( + account: string, + amount: BigNumberish, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + symbol(overrides?: CallOverrides): Promise; + + token(overrides?: CallOverrides): Promise; + + totalSupply(overrides?: CallOverrides): Promise; + + transferOwnership( + newOwner: string, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + unsetDelegate( + delegate: string, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + + unstake( + amount: BigNumberish, + overrides?: Overrides & { from?: string | Promise }, + ): Promise; + }; +} diff --git a/src/apps/airswap/contracts/ethers/common.ts b/src/apps/airswap/contracts/ethers/common.ts new file mode 100644 index 000000000..6cfb10425 --- /dev/null +++ b/src/apps/airswap/contracts/ethers/common.ts @@ -0,0 +1,30 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { Listener } from '@ethersproject/providers'; +import type { Event, EventFilter } from 'ethers'; + +export interface TypedEvent = any, TArgsObject = any> extends Event { + args: TArgsArray & TArgsObject; +} + +export interface TypedEventFilter<_TEvent extends TypedEvent> extends EventFilter {} + +export interface TypedListener { + (...listenerArg: [...__TypechainArgsArray, TEvent]): void; +} + +type __TypechainArgsArray = T extends TypedEvent ? U : never; + +export interface OnEvent { + (eventFilter: TypedEventFilter, listener: TypedListener): TRes; + (eventName: string, listener: Listener): TRes; +} + +export type MinEthersFactory = { + deploy(...a: ARGS[]): Promise; +}; + +export type GetContractTypeFromFactory = F extends MinEthersFactory ? C : never; + +export type GetARGsTypeFromFactory = F extends MinEthersFactory ? Parameters : never; diff --git a/src/apps/airswap/contracts/ethers/factories/Staking__factory.ts b/src/apps/airswap/contracts/ethers/factories/Staking__factory.ts new file mode 100644 index 000000000..912422262 --- /dev/null +++ b/src/apps/airswap/contracts/ethers/factories/Staking__factory.ts @@ -0,0 +1,541 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ + +import { Contract, Signer, utils } from 'ethers'; +import type { Provider } from '@ethersproject/providers'; +import type { Staking, StakingInterface } from '../Staking'; + +const _abi = [ + { + inputs: [ + { + internalType: 'contract ERC20', + name: '_token', + type: 'address', + }, + { + internalType: 'string', + name: '_name', + type: 'string', + }, + { + internalType: 'string', + name: '_symbol', + type: 'string', + }, + { + internalType: 'uint256', + name: '_duration', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_minDelay', + type: 'uint256', + }, + ], + stateMutability: 'nonpayable', + type: 'constructor', + }, + { + anonymous: false, + inputs: [], + name: 'CancelDurationChange', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'uint256', + name: 'newDuration', + type: 'uint256', + }, + ], + name: 'CompleteDurationChange', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'previousOwner', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'newOwner', + type: 'address', + }, + ], + name: 'OwnershipTransferred', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'delegate', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'account', + type: 'address', + }, + ], + name: 'ProposeDelegate', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'uint256', + name: 'unlockTimestamp', + type: 'uint256', + }, + ], + name: 'ScheduleDurationChange', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'delegate', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'account', + type: 'address', + }, + ], + name: 'SetDelegate', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'from', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'to', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'tokens', + type: 'uint256', + }, + ], + name: 'Transfer', + type: 'event', + }, + { + inputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + name: 'accountDelegates', + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'account', + type: 'address', + }, + ], + name: 'available', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'account', + type: 'address', + }, + ], + name: 'balanceOf', + outputs: [ + { + internalType: 'uint256', + name: 'total', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'cancelDurationChange', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'decimals', + outputs: [ + { + internalType: 'uint8', + name: '', + type: 'uint8', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + name: 'delegateAccounts', + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'duration', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'account', + type: 'address', + }, + ], + name: 'getStakes', + outputs: [ + { + components: [ + { + internalType: 'uint256', + name: 'duration', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'balance', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'timestamp', + type: 'uint256', + }, + ], + internalType: 'struct IStaking.Stake', + name: 'accountStake', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'name', + outputs: [ + { + internalType: 'string', + name: '', + type: 'string', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'owner', + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'delegate', + type: 'address', + }, + ], + name: 'proposeDelegate', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + name: 'proposedDelegates', + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'renounceOwnership', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'delay', + type: 'uint256', + }, + ], + name: 'scheduleDurationChange', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'account', + type: 'address', + }, + ], + name: 'setDelegate', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_duration', + type: 'uint256', + }, + ], + name: 'setDuration', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'string', + name: '_name', + type: 'string', + }, + { + internalType: 'string', + name: '_symbol', + type: 'string', + }, + ], + name: 'setMetaData', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'stake', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'account', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'stakeFor', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'symbol', + outputs: [ + { + internalType: 'string', + name: '', + type: 'string', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'token', + outputs: [ + { + internalType: 'contract ERC20', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'totalSupply', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'newOwner', + type: 'address', + }, + ], + name: 'transferOwnership', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'delegate', + type: 'address', + }, + ], + name: 'unsetDelegate', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'unstake', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, +]; + +export class Staking__factory { + static readonly abi = _abi; + static createInterface(): StakingInterface { + return new utils.Interface(_abi) as StakingInterface; + } + static connect(address: string, signerOrProvider: Signer | Provider): Staking { + return new Contract(address, _abi, signerOrProvider) as Staking; + } +} diff --git a/src/apps/airswap/contracts/ethers/factories/index.ts b/src/apps/airswap/contracts/ethers/factories/index.ts new file mode 100644 index 000000000..7a01e5214 --- /dev/null +++ b/src/apps/airswap/contracts/ethers/factories/index.ts @@ -0,0 +1,4 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +export { Staking__factory } from './Staking__factory'; diff --git a/src/apps/airswap/contracts/ethers/index.ts b/src/apps/airswap/contracts/ethers/index.ts new file mode 100644 index 000000000..3c336f63e --- /dev/null +++ b/src/apps/airswap/contracts/ethers/index.ts @@ -0,0 +1,6 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +export type { Staking } from './Staking'; +export * as factories from './factories'; +export { Staking__factory } from './factories/Staking__factory'; diff --git a/src/apps/airswap/contracts/index.ts b/src/apps/airswap/contracts/index.ts new file mode 100644 index 000000000..1d105a444 --- /dev/null +++ b/src/apps/airswap/contracts/index.ts @@ -0,0 +1,23 @@ +import { Injectable, Inject } from '@nestjs/common'; + +import { IAppToolkit, APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface'; +import { ContractFactory } from '~contract/contracts'; +import { Network } from '~types/network.interface'; + +import { Staking__factory } from './ethers'; + +// eslint-disable-next-line +type ContractOpts = { address: string; network: Network }; + +@Injectable() +export class AirswapContractFactory extends ContractFactory { + constructor(@Inject(APP_TOOLKIT) protected readonly appToolkit: IAppToolkit) { + super((network: Network) => appToolkit.getNetworkProvider(network)); + } + + staking({ address, network }: ContractOpts) { + return Staking__factory.connect(address, this.appToolkit.getNetworkProvider(network)); + } +} + +export type { Staking } from './ethers'; diff --git a/src/apps/airswap/ethereum/airswap.balance-fetcher.ts b/src/apps/airswap/ethereum/airswap.balance-fetcher.ts new file mode 100644 index 000000000..149f46f1a --- /dev/null +++ b/src/apps/airswap/ethereum/airswap.balance-fetcher.ts @@ -0,0 +1,38 @@ +import { Inject } from '@nestjs/common'; + +import { IAppToolkit, APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface'; +import { Register } from '~app-toolkit/decorators'; +import { presentBalanceFetcherResponse } from '~app-toolkit/helpers/presentation/balance-fetcher-response.present'; +import { BalanceFetcher } from '~balance/balance-fetcher.interface'; +import { Network } from '~types/network.interface'; + +import { AIRSWAP_DEFINITION } from '../airswap.definition'; + +const appId = AIRSWAP_DEFINITION.id; +const groupId = AIRSWAP_DEFINITION.groups.sAST.id; +const network = Network.ETHEREUM_MAINNET; + +@Register.BalanceFetcher(AIRSWAP_DEFINITION.id, network) +export class EthereumAirswapBalanceFetcher implements BalanceFetcher { + constructor(@Inject(APP_TOOLKIT) private readonly appToolkit: IAppToolkit) {} + + async getAirswapTokenBalances(address: string) { + return this.appToolkit.helpers.tokenBalanceHelper.getTokenBalances({ + address, + appId, + groupId, + network: Network.ETHEREUM_MAINNET, + }); + } + + async getBalances(address: string) { + const [airswapTokenBalances] = await Promise.all([this.getAirswapTokenBalances(address)]); + + return presentBalanceFetcherResponse([ + { + label: AIRSWAP_DEFINITION.name, + assets: airswapTokenBalances, + }, + ]); + } +} diff --git a/src/apps/airswap/ethereum/airswap.s-ast.token-fetcher.ts b/src/apps/airswap/ethereum/airswap.s-ast.token-fetcher.ts new file mode 100644 index 000000000..a83c1e839 --- /dev/null +++ b/src/apps/airswap/ethereum/airswap.s-ast.token-fetcher.ts @@ -0,0 +1,68 @@ +import { Inject } from '@nestjs/common'; + +import { IAppToolkit, APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface'; +import { Register } from '~app-toolkit/decorators'; +import { PositionFetcher } from '~position/position-fetcher.interface'; +import { AppTokenPosition } from '~position/position.interface'; +import { Network } from '~types/network.interface'; + +import { AirswapContractFactory } from '../contracts'; +import { AIRSWAP_DEFINITION } from '../airswap.definition'; +import { ContractType } from '~position/contract.interface'; +import { buildDollarDisplayItem } from '~app-toolkit/helpers/presentation/display-item.present'; +import { getTokenImg } from '~app-toolkit/helpers/presentation/image.present'; + +const appId = AIRSWAP_DEFINITION.id; +const groupId = AIRSWAP_DEFINITION.groups.sAST.id; +const network = Network.ETHEREUM_MAINNET; + +@Register.TokenPositionFetcher({ appId, groupId, network }) +export class EthereumAirswapSAstTokenFetcher implements PositionFetcher { + constructor( + @Inject(APP_TOOLKIT) private readonly appToolkit: IAppToolkit, + @Inject(AirswapContractFactory) private readonly airswapContractFactory: AirswapContractFactory, + ) {} + + async getPositions() { + const address = '0x579120871266ccd8De6c85EF59E2fF6743E7CD15'; + const multicall = this.appToolkit.getMulticall(network); + const contract = this.airswapContractFactory.staking({ address, network }); + + const [symbol, decimals, supplyRaw] = await Promise.all([ + multicall.wrap(contract).symbol(), + multicall.wrap(contract).decimals(), + multicall.wrap(contract).totalSupply(), + ]); + + const baseTokenDependencies = await this.appToolkit.getBaseTokenPrices(network); + const underlyingToken = baseTokenDependencies.find(v => v.symbol === AIRSWAP_DEFINITION.symbol); + + if (!underlyingToken) { + return []; + } + + const supply = Number(supplyRaw) / 10 ** decimals; + + const token: AppTokenPosition = { + type: ContractType.APP_TOKEN, + appId, + groupId, + address, + network, + symbol, + decimals, + supply, + tokens: [underlyingToken], + price: underlyingToken.price, + pricePerShare: 1, + dataProps: {}, + displayProps: { + label: 'sAST', + secondaryLabel: buildDollarDisplayItem(underlyingToken.price), + images: [getTokenImg(underlyingToken.address, network)], + }, + }; + + return [token]; + } +}