Skip to content

Commit

Permalink
Merge pull request #439 from blinklabs-io/feat/native-token
Browse files Browse the repository at this point in the history
feat: support a native platform token
  • Loading branch information
reqlez authored Dec 7, 2023
2 parents 87623f2 + 842bfcb commit 9312cc4
Show file tree
Hide file tree
Showing 13 changed files with 115 additions and 12 deletions.
8 changes: 7 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@
# Log output format for Express/morgan (default: dev)
#LOG_TYPE=combined

# Fee for native platform token (default: 500000)
#NATIVE_TOKEN_FEE=500000

# Native platform token (optional)
#NATIVE_TOKEN_ID=a8a1dccea2e378081f2d500d98d022dd3c0bd77afd9dbc7b55a9d21b.63544f5349

# Premium token fee (default: 500000)
#TOSIFEE=500000

Expand All @@ -50,4 +56,4 @@
#VM_URL="https://vm.adaseal.eu"

# enable ergo side
#ERGO_ENABLED=false
#ERGO_ENABLED=false
9 changes: 8 additions & 1 deletion client/src/components/Claim/ClaimableTokenBox/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// import TokenInfoTooltip from "../TokenInfoTooltip";
import NativefeeTooltip from "../NativefeeTooltip";
import TosifeeTooltip from "../TosifeeTooltip";
import "./index.scss";

Expand All @@ -14,6 +15,7 @@ interface Props {
logo: string;
assetId: string;
premium: boolean;
native: boolean;
}

const ClaimableTokenBox = ({
Expand All @@ -26,6 +28,7 @@ const ClaimableTokenBox = ({
amount,
logo,
premium,
native,
}: Props) => {
return (
<div
Expand All @@ -39,7 +42,11 @@ const ClaimableTokenBox = ({
<div className="text-sm">{amount} available</div>
<div className="ml-auto flex flex-row align-center gap-2">
{/* Disabled <TokenInfoTooltip price={price} total={total}></TokenInfoTooltip> */}
{premium ? <TosifeeTooltip></TosifeeTooltip> : null}
{native ? (
<NativefeeTooltip></NativefeeTooltip>
) : premium ? (
<TosifeeTooltip></TosifeeTooltip>
) : null}
</div>
</div>
<img alt="logo" src={logo} className="h-24"></img>
Expand Down
3 changes: 3 additions & 0 deletions client/src/components/Claim/DepositInfo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ interface Params {
setTransactionId: Function;
setTransactionStatus: Function;
unlock: boolean;
native: boolean;
}

const DepositInfo = ({
Expand All @@ -27,6 +28,7 @@ const DepositInfo = ({
setTransactionId,
setTransactionStatus,
unlock,
native,
}: Params) => {
return (
<div className="flex flex-col gap-4">
Expand Down Expand Up @@ -64,6 +66,7 @@ const DepositInfo = ({
numberOfTokens={checkedCount}
deposit={txDetail.deposit}
unlock={unlock}
native={native}
isWhitelisted={txDetail.is_whitelisted}
></TransactionDetail>
) : null}
Expand Down
16 changes: 16 additions & 0 deletions client/src/components/Claim/NativefeeTooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { faCoins } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";

export default function NativefeeTooltip() {
return (
<span className="premium-token tooltip-activator">
<FontAwesomeIcon
className="text-premium cursor-help premium-pulse"
icon={faCoins}
/>
<div className="tooltip w-64 p-3.5 rounded-2xl right-5 bottom-5 absolute">
Native Token Fee is applied to our native platform token.
</div>
</span>
);
}
1 change: 1 addition & 0 deletions client/src/components/Claim/RewardsView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export default function RewardsView({
logo={token.logo}
assetId={token.assetId}
premium={token.premium}
native={token.native}
/>
);
})}
Expand Down
17 changes: 14 additions & 3 deletions client/src/components/Claim/TransactionDetail/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ interface Props {
numberOfTokens: number;
deposit: number;
unlock: boolean;
native: boolean;
isWhitelisted: boolean;
}

interface ISettings {
nativeFee: number;
vmFee: number;
txFee: number;
tosiFee: number;
Expand All @@ -22,9 +24,11 @@ const TransactionDetail = ({
numberOfTokens,
deposit,
unlock,
native,
isWhitelisted,
}: Props) => {
const [settings, setSettings] = useState<ISettings>({
nativeFee: 500000,
vmFee: 0,
txFee: 440000,
tosiFee: 500000,
Expand All @@ -36,6 +40,7 @@ const TransactionDetail = ({
const settingsFromFeatures = await getFeatures();
setSettings({
...settings,
nativeFee: settingsFromFeatures.native_token_fee,
tosiFee: settingsFromFeatures.tosi_fee,
vmFee: settingsFromVM.withdrawal_fee,
});
Expand All @@ -52,7 +57,13 @@ const TransactionDetail = ({

const calcReturnedAda = () => {
let returnedAda = deposit - settings.vmFee - calcTxFee();
if (unlock && !isWhitelisted) returnedAda -= settings.tosiFee;
if (unlock || native) {
// unlock
if (unlock && !isWhitelisted) returnedAda -= settings.tosiFee;
// only native, charging native fee
if (native && !unlock && !isWhitelisted)
returnedAda -= settings.nativeFee;
}
return returnedAda;
};

Expand All @@ -73,10 +84,10 @@ const TransactionDetail = ({
<div className="w-28 text-right">{lovelaceToAda(calcTxFee())} ADA</div>
<div className="text-right">Transaction fee</div>
</div>
{unlock && !isWhitelisted ? (
{(unlock || native) && !isWhitelisted ? (
<div className="p-1 flex items-center flex-row-reverse border-b border-color text-premium">
<div className="w-28 text-right">
{lovelaceToAda(settings.tosiFee)} ADA
{lovelaceToAda(unlock ? settings.tosiFee : settings.nativeFee)} ADA
</div>
<div className="tooltip-activator cursor-help text-right">
TosiFee <FontAwesomeIcon icon={faQuestionCircle} />
Expand Down
1 change: 1 addition & 0 deletions client/src/entities/vm.entities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export interface ClaimableToken {
decimals: number;
amount: number;
premium: boolean;
native: boolean;
price: string;
total: string;
selected?: boolean;
Expand Down
8 changes: 6 additions & 2 deletions client/src/hooks/cardano/claim/useClaimReward.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,12 +148,15 @@ export default function useClaimReward() {
if (numberOfSelectedTokens === 0) return;

setIsClaimRewardLoading(true);
let selectedNativeToken = false;
let selectedPremiumToken = false;

const selectedTokenId: string[] = [];
claimableTokens.forEach((token) => {
if (token.selected) {
if (token.premium) {
if (token.native) {
selectedNativeToken = true;
} else if (token.premium) {
selectedPremiumToken = true;
}
selectedTokenId.push(token.assetId);
Expand All @@ -166,10 +169,11 @@ export default function useClaimReward() {
stakeAddress.slice(0, 40),
selectedTokenId.join(","),
selectedPremiumToken,
selectedNativeToken,
);
if (res == null) throw new Error();

let depositInfoUrl = `${PageRoute.depositCardano}?stakeAddress=${stakeAddress}&withdrawAddress=${res.withdrawal_address}&requestId=${res.request_id}&selectedTokens=${numberOfSelectedTokens}&unlock=${selectedPremiumToken}&isWhitelisted=${res.is_whitelisted}`;
let depositInfoUrl = `${PageRoute.depositCardano}?stakeAddress=${stakeAddress}&withdrawAddress=${res.withdrawal_address}&requestId=${res.request_id}&selectedTokens=${numberOfSelectedTokens}&unlock=${selectedPremiumToken}&native=${selectedNativeToken}&isWhitelisted=${res.is_whitelisted}`;
navigate(depositInfoUrl, { replace: true });
} catch (e) {
handleError(e);
Expand Down
3 changes: 3 additions & 0 deletions client/src/pages/Cardano/Deposit/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ enum QueryKey {
requestId = "requestId",
isWhitelisted = "isWhitelisted",
unlock = "unlock",
native = "native",
}

export enum TransactionStatusDetail {
Expand All @@ -45,6 +46,7 @@ const DepositInfoPage = () => {
const isWhitelisted =
searchParams.get(QueryKey.isWhitelisted) === "true" ? true : false;
const unlock = searchParams.get(QueryKey.unlock) === "true" ? true : false;
const native = searchParams.get(QueryKey.native) === "true" ? true : false;

const [txDetail, setTxDetail] = useState<GetCustomRewards>({
deposit: 0,
Expand Down Expand Up @@ -133,6 +135,7 @@ const DepositInfoPage = () => {
setTransactionId={setTransactionId}
setTransactionStatus={setTransactionStatus}
unlock={unlock}
native={native}
></DepositInfo>
</>
) : null;
Expand Down
3 changes: 2 additions & 1 deletion client/src/services/claim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ export async function getCustomRewards(
session_id: string,
selected: string,
unlock: boolean,
native: boolean,
): Promise<GetCustomRewards | undefined> {
const response = await axios.get(
`/api/getcustomrewards?staking_address=${staking_address}&session_id=${session_id}&selected=${selected}&unlock=${
unlock ? "true" : "false"
}`,
}&native=${native ? "true" : "false"}`,
);
if (response && response.data) {
return response.data;
Expand Down
40 changes: 39 additions & 1 deletion server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ export const TOSIDROP_ADMIN_KEY =
process.env.TOSIDROP_ADMIN_KEY || "admin key is not set";
const CLOUDFLARE_PSK = process.env.CLOUDFLARE_PSK;
const LOG_TYPE = process.env.LOG_TYPE || "dev";
const NATIVE_TOKEN_FEE = process.env.NATIVE_TOKEN_FEE || 500000;
const NATIVE_TOKEN_ID = process.env.NATIVE_TOKEN_ID;
const PORT = process.env.PORT || 3000;
const TOSIFEE = process.env.TOSIFEE || 500000;
const TOSIFEE_WHITELIST = process.env.TOSIFEE_WHITELIST;
Expand All @@ -73,7 +75,7 @@ const app = express();
app.use(express.json());
app.use(require("morgan")(LOG_TYPE));
app.use(oapi);
app.use(cors({origin: '*'}));
app.use(cors({ origin: "*" }));
app.use("/swaggerui", oapi.swaggerui);
app.use(express.static("../client/build"));

Expand Down Expand Up @@ -206,6 +208,8 @@ app.get(
tosi_fee: Number(TOSIFEE),
tosi_fee_whitelist: TOSIFEE_WHITELIST,
claim_enabled: CLAIM_ENABLED,
native_token_fee: Number(NATIVE_TOKEN_FEE),
native_token_id: NATIVE_TOKEN_ID,
network: CARDANO_NETWORK,
ergo_enabled: ERGO_ENABLED,
};
Expand Down Expand Up @@ -466,6 +470,11 @@ app.get(
in: "query",
required: false,
},
{
name: "native",
in: "query",
required: false,
},
],
responses: {
200: {
Expand Down Expand Up @@ -517,9 +526,12 @@ app.get(
session_id,
selected,
unlock,
native,
} = queryObject;
let vmArgs = `custom_request&staking_address=${stakeAddress}&session_id=${session_id}&selected=${selected}&xwallet=true`;
let isWhitelisted = false;
let isNativeSelected = false;
let isPremiumSelected = false;

if (!stakeAddress) {
throw createErrorWithCode(
Expand All @@ -542,6 +554,32 @@ app.get(
} else {
vmArgs += `&overhead_fee=${TOSIFEE}&unlocks_special=true`;
}
} else if (native === "true") {
if (TOSIFEE_WHITELIST) {
const whitelist = TOSIFEE_WHITELIST.split(",");
const accountsInfo = await getAccountsInfo(`${stakeAddress}`);
const accountInfo = accountsInfo[0];
if (whitelist.includes(accountInfo.delegated_pool)) {
vmArgs += "&unlocks_special=true";
isWhitelisted = true;
}
} else {
const claimableTokens = await getRewards(`${stakeAddress}`);
for (let token of claimableTokens) {
if (token.native) {
isNativeSelected = true;
} else if (token.premium) {
// cheeky monkey
isPremiumSelected = true;
}
}
if (isNativeSelected && !isPremiumSelected) {
vmArgs += `&overhead_fee=${NATIVE_TOKEN_FEE}&unlocks_special=true`;
} else {
// Do not unlock
vmArgs += "&unlocks_special=false";
}
}
} else {
vmArgs += "&unlocks_special=false";
}
Expand Down
16 changes: 13 additions & 3 deletions server/utils/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ let Buffer = require("buffer").Buffer;
const MIN_PAIRS_API =
process.env.MIN_PAIRS_API ||
"https://api-mainnet-prod.minswap.org/coinmarketcap/v2/pairs";
const NATIVE_TOKEN_ID = process.env.NATIVE_TOKEN_ID;
const VM_API_TOKEN =
process.env.VM_API_TOKEN_TESTNET || process.env.VM_API_TOKEN;
const VM_URL = process.env.VM_URL_TESTNET || process.env.VM_URL;
Expand Down Expand Up @@ -254,12 +255,12 @@ export async function getRewards(stakeAddress: string) {
MinswapService.getPrices(),
]);

if (getRewardsResponse == null) return;
if (tokens == null) return;
const claimableTokens: ClaimableToken[] = [];
if (getRewardsResponse == null) return claimableTokens;
if (tokens == null) return claimableTokens;

const consolidatedAvailableReward: { [key: string]: number } = {};
const consolidatedAvailableRewardPremium: { [key: string]: number } = {};
const claimableTokens: ClaimableToken[] = [];

/** handle regular tokens */
const regularRewards: Record<string, number> = {
Expand Down Expand Up @@ -316,6 +317,7 @@ export async function getRewards(stakeAddress: string) {
decimals,
amount,
premium: false,
native: false,
price,
total,
});
Expand All @@ -338,6 +340,7 @@ export async function getRewards(stakeAddress: string) {
decimals,
amount,
premium: true,
native: isNativeToken(assetId),
price,
total,
});
Expand Down Expand Up @@ -456,6 +459,13 @@ export function parseVmDeliveredRewards(
return Object.values(rewardMap);
}

export function isNativeToken(assetId: string) {
if (NATIVE_TOKEN_ID) {
if (assetId === NATIVE_TOKEN_ID) return true;
}
return false;
}

export function convertPoolIdToBech32(poolIdInHex: string) {
return converter("pool").toBech32(poolIdInHex);
}
Expand Down
2 changes: 2 additions & 0 deletions server/utils/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export interface ITosiFeatures {
tosi_fee: number;
tosi_fee_whitelist: any;
claim_enabled: boolean;
native_token_fee: number;
native_token_id: any;
network: string;
ergo_enabled: boolean;
}

0 comments on commit 9312cc4

Please sign in to comment.