Skip to content

Commit

Permalink
Merge pull request #40 from harmony-one/1country-rent-renew
Browse files Browse the repository at this point in the history
1country rent renew
  • Loading branch information
theofandrich authored Aug 2, 2023
2 parents 0e63ddb + d2e3dd8 commit 87d4ded
Show file tree
Hide file tree
Showing 24 changed files with 1,665 additions and 959 deletions.
1,177 changes: 375 additions & 802 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"axios": "^1.4.0",
"bignumber.js": "^9.1.1",
"dotenv": "^16.0.3",
"ethers": "^5.7.2",
"express": "^4.18.2",
"grammy": "^1.17.1",
"jsqr": "^1.4.0",
Expand Down
27 changes: 20 additions & 7 deletions src/bot.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import express from "express";
import {
Bot,
BotError,
GrammyError,
HttpError,
MemorySessionStorage,
session,
} from "grammy";
import config from "./config";
import { pino } from "pino";

import {
BotContext,
BotSessionData,
Expand All @@ -19,13 +19,26 @@ import { VoiceMemo } from "./modules/voice-memo";
import { QRCodeBot } from "./modules/qrcode/QRCodeBot";
import { SDImagesBot } from "./modules/sd-images";
import { imageGen } from "./modules/open-ai/ImageGenBot";
import { chatGpt } from "./modules/open-ai/chatGptBot";
import { oneCountry } from "./modules/1country/oneCountryBot";
import { Wallet } from "./modules/wallet";
import { WalletConnect } from "./modules/walletconnect";
import {BotPayments} from "./modules/payment";
import {BotSchedule} from "./modules/schedule";
import {Api} from "telegram";
import { conversationHandler } from './modules/conversation-handler/conversationHandler'

import config from "./config";


const logger = pino({
name: "bot",
transport: {
target: "pino-pretty",
options: {
colorize: true,
},
},
});

export const bot = new Bot<BotContext>(config.telegramBotAuthToken);

Expand Down Expand Up @@ -54,6 +67,7 @@ bot.use(
})
);


bot.use(mainMenu);

const voiceMemo = new VoiceMemo();
Expand Down Expand Up @@ -118,16 +132,15 @@ const onCallback = async (ctx: OnCallBackQueryData) => {
bot.command("start", (ctx) => ctx.reply("Welcome! Up and running."));

bot.command("help", async (ctx) => {
console.log("help command", ctx.session);
await ctx.reply("Menu", {
parse_mode: "HTML",
reply_markup: mainMenu,
});
});

bot.use(conversationHandler)
bot.use(oneCountry);
bot.use(imageGen);
bot.use(chatGpt);

bot.on("message", onMessage);
bot.on("callback_query:data", onCallback);
Expand All @@ -146,7 +159,7 @@ bot.catch((err) => {
});

bot.errorBoundary((error) => {
console.log("### error", error);
logger.error("### error", error);
});

const app = express();
Expand All @@ -155,7 +168,7 @@ app.use(express.json());
app.use(express.static("./public")); // Public directory, used in voice-memo bot

app.listen(config.port, () => {
console.log(`Bot listening on port ${config.port}`);
logger.info(`Bot listening on port ${config.port}`);
bot.start();
// bot.start({
// allowed_updates: ["callback_query"], // Needs to be set for menu middleware, but bot doesn't work with current configuration.
Expand Down
10 changes: 8 additions & 2 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,14 @@ export default {
},
},
country: {
relayApiUrl: "https://1ns-registrar-relayer.hiddenstate.xyz",
tld: ".country",
hostname: 'https://1.country',
relayApiUrl: 'https://1ns-registrar-relayer.hiddenstate.xyz',
tld: '.country',
contract: process.env.DC_CONTRACT || '',
defaultRPC: 'https://api.harmony.one',
restrictedPhrases: process.env.RESTRICTED_PHRASES
? process.env.RESTRICTED_PHRASES.split(', ')
: ['metamask', 'walletconnect'],
},
voiceMemo: {
isEnabled: Boolean(parseInt(process.env.VOICE_MEMO_ENABLED || "1")),
Expand Down
25 changes: 25 additions & 0 deletions src/modules/1country/api/coingecko.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import axios from "axios";

import config from "../../../config";
import { formatUSDAmount } from "../utils";

const base = axios.create({
baseURL:
"https://api.coingecko.com/api/v3/simple/price?ids=harmony&vs_currencies=usd",
timeout: 10000,
});

export const getUSDPrice = async (
onePrice: string
): Promise<{ price: string | null; error: string | null }> => {
try {
const response = await axios.get(
"https://api.coingecko.com/api/v3/simple/price?ids=harmony&vs_currencies=usd"
);
const usdPrice = response.data["harmony"].usd;
return { price: formatUSDAmount(Number(onePrice) * usdPrice), error: null };
} catch (e) {
console.log(e);
return { price: null, error: "Can't retrieve USD price" };
}
};
151 changes: 151 additions & 0 deletions src/modules/1country/api/d1dc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import { ethers } from "ethers";
import web3Utils from "web3-utils";
import pino, {Logger} from "pino";

import DCv2Abi from "../contracts/DCv2";
import config from "../../../config";

const logger = pino({
name: "OneCountryBot",
transport: {
target: "pino-pretty",
options: {
colorize: true,
},
},
});

export interface DomainRecord {
renter: string;
rentTime: number;
lastPrice: {
amount: string;
formatted: string;
};
expirationTime: number;
url: string;
prev: string;
next: string;
}

export interface DomainPrice {
amount: string;
formatted: string;
}

export interface SendNameExpired {
isExpired: boolean;
expirationDate: number;
isInGracePeriod: boolean;
}

const defaultProvider = new ethers.providers.JsonRpcProvider(
config.country.defaultRPC
);

const EmptyAddress = "0x0000000000000000000000000000000000000000";

class DcClient {
private logger: Logger;
private provider:
| ethers.providers.Web3Provider
| ethers.providers.JsonRpcProvider;
private contractReadOnly: ethers.Contract;

constructor({
provider,
}: // address,
{
provider: ethers.providers.Web3Provider | ethers.providers.JsonRpcProvider;
}) {

if (!provider) {
throw new Error("Provider is required");
}
this.provider = provider;

this.contractReadOnly = new ethers.Contract(
config.country.contract,
DCv2Abi,
defaultProvider
);
this.logger = pino({
name: 'DcClient',
transport: {
target: 'pino-pretty',
options: {
colorize: true
}
}
})
this.logger.info(`DC Contract ${config.country.contract} initialized`)
}

async duration() {
return this.contractReadOnly.duration();
}

async getPrice({ name }: { name: string }): Promise<DomainPrice> {
const price = await this.contractReadOnly.getPrice(name);
const amount = price.toString();
return {
amount,
formatted: web3Utils.fromWei(amount),
};
}

async getRecord({ name }: { name: string }): Promise<DomainRecord> {
if (!name) {
throw new Error("name is empty");
}
let lastPrice = "0",
url = "",
prev = "",
next = "";

const [ownerAddress, rentTime, expirationTime] = await Promise.all([
this.contractReadOnly.ownerOf(name).catch(() => ""),
this.contractReadOnly.duration(),
this.contractReadOnly.nameExpires(name),
]);
return {
renter:
!ownerAddress || ownerAddress === EmptyAddress ? null : ownerAddress,
rentTime: rentTime.toNumber() * 1000,
expirationTime: expirationTime.toNumber() * 1000,
lastPrice: {
amount: lastPrice,
formatted: web3Utils.fromWei(lastPrice),
},
url,
prev,
next,
};
}

async checkNameExpired({ name }: { name: string }): Promise<SendNameExpired> {
const nameExpires = await this.contractReadOnly.nameExpires('fegloff.country');
const epochSecondsDec = parseInt(nameExpires);
const expirationDate = new Date(epochSecondsDec * 1000);
const currentDate = new Date();
const timeDifferenceMs = currentDate.getTime() - expirationDate.getTime();
const daysDifference = Math.abs(
Math.ceil(timeDifferenceMs / (1000 * 60 * 60 * 24))
);
const currentTimestamp = Math.floor(Date.now() / 1000);
return {
isExpired:
epochSecondsDec === 0 ? false : currentTimestamp > epochSecondsDec,
expirationDate: parseInt(nameExpires),
isInGracePeriod: daysDifference <= 7,
};
}

async checkAvailable({ name }: { name: string }) {
const isAvailable = await this.contractReadOnly.available(name);
return isAvailable?.toString()?.toLowerCase() === "true";
}
}

export const dcClient = new DcClient({ provider: defaultProvider });

11 changes: 1 addition & 10 deletions src/modules/1country/api/relayApi.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import axios from "axios";

import config from "../../../config";

const base = axios.create({
Expand All @@ -8,16 +9,6 @@ const base = axios.create({

export const relayApi = () => {
return {
enableSubdomains: async (domainName: string) => {
try {
const { data } = await base.post("/enable-subdomains", {
domain: `${domainName}${config.country.tld}`,
});
console.log("enableSubdomains", data);
} catch (e) {
console.log("enableSubdomains error", e);
}
},
checkDomain: async ({ sld }: { sld: string }) => {
try {
const {
Expand Down
Loading

0 comments on commit 87d4ded

Please sign in to comment.