Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Unreleased

- added: Cardano staking through Kiln staking pools
- added: Support for `isLiquidStaking` field on staking policies
- changed: Some unecessary `showError` dropdowns demoted to hidden `showDevError`
- changed: Restrict Bity buy/sell to no-KYC asset
- changed: Determine Moonpay asset support using chainCode/contractAddress
Expand Down
14 changes: 13 additions & 1 deletion src/components/scenes/Staking/StakeModifyScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { getPolicyIconUris, getPositionAllocations } from '../../../util/stakeUt
import { toBigNumberString } from '../../../util/toBigNumberString'
import { zeroString } from '../../../util/utils'
import { EdgeCard } from '../../cards/EdgeCard'
import { WarningCard } from '../../cards/WarningCard'
import { SceneWrapper } from '../../common/SceneWrapper'
import { withWallet } from '../../hoc/withWallet'
import { ButtonsModal } from '../../modals/ButtonsModal'
Expand Down Expand Up @@ -110,6 +111,12 @@ const StakeModifySceneComponent = (props: Props) => {
currencyCode: stakePolicy.rewardAssets[0].currencyCode,
nativeAmount: existingAllocations.earned[0].nativeAmount
})
} else if ((modification === 'stake' || modification === 'unstake') && stakePolicy.isLiquidStaking === true) {
setChangeQuoteRequest({
...changeQuoteRequest,
currencyCode: stakePolicy.rewardAssets[0].currencyCode,
nativeAmount: '1' // Amounts for liquid staking are a noop
})
} else if (modification === 'unstake' && mustMaxUnstake) {
setChangeQuoteRequest({
...changeQuoteRequest,
Expand Down Expand Up @@ -455,7 +462,8 @@ const StakeModifySceneComponent = (props: Props) => {
<EdgeCard icon={getCurrencyIconUris(wallet.currencyInfo.pluginId, null).symbolImage}>
<EdgeRow title={lstrings.wc_smartcontract_wallet} body={getWalletName(wallet)} />
</EdgeCard>
{stakeUnstakeAllocations.map(renderEditableQuoteAmountRow)}
{/* Editable rows are not show for liquid-staking policies */}
{stakePolicy.isLiquidStaking !== true ? stakeUnstakeAllocations.map(renderEditableQuoteAmountRow) : null}
{claimAllocations.map(renderEditableQuoteAmountRow)}
{
// Render stake/unstake fee tiles
Expand All @@ -476,6 +484,10 @@ const StakeModifySceneComponent = (props: Props) => {
stakePolicy.stakeAssets.map(asset => renderFutureUnstakeFeeAmountRow(modification, asset))
}
{quoteInfo?.breakEvenDays != null ? renderBreakEvenDays() : null}
{/* A warning card is show for liquid-staking policies, informing the user that staking is all-or-nothing. */}
{stakePolicy.isLiquidStaking === true && (modification === 'stake' || modification === 'unstake') ? (
<WarningCard title={lstrings.stake_liquid_staking_warning_title} header={sprintf(lstrings.stake_liquid_staking_warning_header, modification)} />
) : null}
{errorMessage === '' || sliderLocked ? null : <ErrorTile message={errorMessage} />}
</View>
)
Expand Down
6 changes: 4 additions & 2 deletions src/components/themed/TransactionListTop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,13 +170,15 @@ export class TransactionListTopComponent extends React.PureComponent<Props, Stat
let lockedNativeAmount = '0'
const stakePositionMap: StakePositionMap = {}
for (const stakePolicy of stakePolicies) {
// Don't show liquid staking positions as locked amount
if (stakePolicy.isLiquidStaking === true) continue

let total: string | undefined
const { stakePolicyId } = stakePolicy
const stakePlugin = getPluginFromPolicy(stakePlugins, stakePolicy)
if (stakePlugin == null) continue
try {
const stakePosition = await stakePlugin.fetchStakePosition({
stakePolicyId,
stakePolicyId: stakePolicy.stakePolicyId,
wallet: this.props.wallet,
account: this.props.account
})
Expand Down
3 changes: 2 additions & 1 deletion src/constants/WalletAndCurrencyConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,8 @@ export const SPECIAL_CURRENCY_INFO: {
noChangeMiningFee: true,
noMaxSpend: true,
dummyPublicAddress: 'addr1qyh498v7479sljadw8mdlmshnlt3n30ewzpqnmvrsz2v8rpqt56tgy6jhzgcc7v8mlh7lhw9a9j2hdlmek4arx2238us9e5fq0',
isImportKeySupported: true
isImportKeySupported: true,
isStakingSupported: true
},
cardanotestnet: {
initWalletName: lstrings.string_first_cardano_preprod_wallet_name,
Expand Down
2 changes: 2 additions & 0 deletions src/envConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,9 @@ export const asEnvConfig = asObject({
AZTECO_API_KEY: asNullable(asString),
STAKEKIT_API_KEY: asNullable(asString),
KILN_TESTNET_API_KEY: asNullable(asString),
KILN_TESTNET_ACCOUNT_ID: asNullable(asString),
KILN_MAINNET_API_KEY: asNullable(asString),
KILN_MAINNET_ACCOUNT_ID: asNullable(asString),

// Core plugin options:
ARBITRUM_INIT: asCorePluginInit(asEvmApiKeys),
Expand Down
2 changes: 2 additions & 0 deletions src/locales/en_US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1414,6 +1414,8 @@ const strings = {
stake_break_even_days_months_s: '%1$s days (%2$s months)',
stake_earn_button_label: 'Earn',
stake_unable_to_query_locked: 'Unable to query locked balance. Please try again later.',
stake_liquid_staking_warning_title: 'Liquid Staking Pool Notice',
stake_liquid_staking_warning_header: `This is a liquid-staking pool, meaning the entire wallet's balance is either staked/unstaked in the pool. Wallet funds will remain liquid (transferable), however all current and future funds will be exposed to the risks and rewards of the staking pool while staked.`,

// Tron resource staking
stake_resource_display_name: 'TRON Resources',
Expand Down
2 changes: 2 additions & 0 deletions src/locales/strings/enUS.json
Original file line number Diff line number Diff line change
Expand Up @@ -1242,6 +1242,8 @@
"stake_break_even_days_months_s": "%1$s days (%2$s months)",
"stake_earn_button_label": "Earn",
"stake_unable_to_query_locked": "Unable to query locked balance. Please try again later.",
"stake_liquid_staking_warning_title": "Liquid Staking Pool Notice",
"stake_liquid_staking_warning_header": "This is a liquid-staking pool, meaning the entire wallet's balance is either staked/unstaked in the pool. Wallet funds will remain liquid (transferable), however all current and future funds will be exposed to the risks and rewards of the staking pool while staked.",
"stake_resource_display_name": "TRON Resources",
"stake_resource_display_name_v2": "TRON Resources v2",
"stake_resource_bandwidth": "Bandwidth",
Expand Down
41 changes: 17 additions & 24 deletions src/plugins/stake-plugins/generic/GenericStakePlugin.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ChangeQuote, ChangeQuoteRequest, StakePlugin, StakePluginFactory, StakePolicy, StakePolicyFilter, StakePosition, StakePositionRequest } from '../types'
import { CardanoPooledKilnAdapterConfig, makeCardanoKilnAdapter } from './policyAdapters/CardanoKilnAdaptor'
import { CoreumNativeSkateKitAdapterConfig, makeSkateKitAdapter } from './policyAdapters/CoreumStakeKitAdaptor'
import { EthereumPooledKilnAdapterConfig, makeKilnAdapter } from './policyAdapters/EthereumKilnAdaptor'
import { EthereumPooledKilnAdapterConfig, makeEthereumKilnAdapter } from './policyAdapters/EthereumKilnAdaptor'
import { GlifInfinityPoolAdapterConfig, makeGlifInfinityPoolAdapter } from './policyAdapters/GlifInfinityPoolAdapter'
import { makeTarotPoolAdapter, TarotPoolAdapterConfig } from './policyAdapters/TarotPoolAdaptor'
import { StakeAdapterConfig, StakePolicyAdapter } from './policyAdapters/types'
Expand Down Expand Up @@ -69,30 +70,20 @@ export const makeGenericStakePlugin =
return instance
}

function isPolicyInfoForGlifInfinityPool(policyInfo: StakePolicyConfig<StakeAdapterConfig>): policyInfo is StakePolicyConfig<GlifInfinityPoolAdapterConfig> {
return policyInfo.adapterConfig.type === 'glif-infinity-pool'
}
function isPolicyInfoForTarotPool(policyInfo: StakePolicyConfig<StakeAdapterConfig>): policyInfo is StakePolicyConfig<TarotPoolAdapterConfig> {
return policyInfo.adapterConfig.type === 'tarot-velodrome-pool'
}
function isPolicyInfoForCoreumStakeKit(policyInfo: StakePolicyConfig<StakeAdapterConfig>): policyInfo is StakePolicyConfig<CoreumNativeSkateKitAdapterConfig> {
return policyInfo.adapterConfig.type === 'coreum-native-stake-kit'
}
function isPolicyInfoForEthereumKiln(policyInfo: StakePolicyConfig<StakeAdapterConfig>): policyInfo is StakePolicyConfig<EthereumPooledKilnAdapterConfig> {
return policyInfo.adapterConfig.type === 'ethereum-pooled-kiln'
}

const makePolicyAdapter = (policyInfo: StakePolicyConfig<StakeAdapterConfig>): StakePolicyAdapter => {
if (isPolicyInfoForGlifInfinityPool(policyInfo)) {
return makeGlifInfinityPoolAdapter(policyInfo)
} else if (isPolicyInfoForTarotPool(policyInfo)) {
return makeTarotPoolAdapter(policyInfo)
} else if (isPolicyInfoForCoreumStakeKit(policyInfo)) {
return makeSkateKitAdapter(policyInfo)
} else if (isPolicyInfoForEthereumKiln(policyInfo)) {
return makeKilnAdapter(policyInfo)
} else {
throw new Error('Unknown policyInfo')
switch (policyInfo.adapterConfig.type) {
case 'cardano-pooled-kiln':
return makeCardanoKilnAdapter(policyInfo as StakePolicyConfig<CardanoPooledKilnAdapterConfig>)
case 'coreum-native-stake-kit':
return makeSkateKitAdapter(policyInfo as StakePolicyConfig<CoreumNativeSkateKitAdapterConfig>)
case 'ethereum-pooled-kiln':
return makeEthereumKilnAdapter(policyInfo as StakePolicyConfig<EthereumPooledKilnAdapterConfig>)
case 'glif-infinity-pool':
return makeGlifInfinityPoolAdapter(policyInfo as StakePolicyConfig<GlifInfinityPoolAdapterConfig>)
case 'tarot-velodrome-pool':
return makeTarotPoolAdapter(policyInfo as StakePolicyConfig<TarotPoolAdapterConfig>)
default:
throw new Error('Unknown policyInfo')
}
}

Expand All @@ -103,6 +94,7 @@ const makeStakePolicy = async (policyConfig: StakePolicyConfig<StakeAdapterConfi
hideUnstakeAction = false,
hideUnstakeAndClaimAction = false,
isStablePool,
isLiquidStaking,
stakeProviderInfo,
stakeAssets,
rewardAssets,
Expand All @@ -124,6 +116,7 @@ const makeStakePolicy = async (policyConfig: StakePolicyConfig<StakeAdapterConfi
hideClaimAction,
hideUnstakeAction,
hideUnstakeAndClaimAction,
isLiquidStaking,
yieldType,
stakeAssets,
rewardAssets,
Expand Down
3 changes: 2 additions & 1 deletion src/plugins/stake-plugins/generic/pluginInfo.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { kilncardanopool } from './pluginInfo/cardanoKilnPool'
import { coreumnative } from './pluginInfo/coreumNativeStaking'
import { kilnpool } from './pluginInfo/ethereumKilnPool'
import { glifpoolCalibration } from './pluginInfo/filecoinCalibrationGlifpool'
import { glifpool } from './pluginInfo/filecoinGlifpool'
import { tarotpool } from './pluginInfo/optimismTarotPool'

export const genericPlugins = [glifpool, glifpoolCalibration, tarotpool, coreumnative, kilnpool]
export const genericPlugins = [glifpool, glifpoolCalibration, tarotpool, coreumnative, kilnpool, kilncardanopool]
195 changes: 195 additions & 0 deletions src/plugins/stake-plugins/generic/pluginInfo/cardanoKilnPool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
import { ENV } from '../../../../env'
import { CardanoPooledKilnAdapterConfig } from '../policyAdapters/CardanoKilnAdaptor'
import { StakePluginInfo, StakePolicyConfig } from '../types'

const kilnPolicyConfig: Array<StakePolicyConfig<CardanoPooledKilnAdapterConfig>> = [
{
stakePolicyId: 'cardano_kiln_pool0',
stakeProviderInfo: {
displayName: 'Cardano Staking Pool (KILN0)',
pluginId: 'cardano',
stakeProviderId: 'cardano_pooled_kiln'
},
parentPluginId: 'cardano',
parentCurrencyCode: 'ADA',
adapterConfig: {
type: 'cardano-pooled-kiln',
pluginId: 'cardano',

accountId: ENV.KILN_MAINNET_ACCOUNT_ID,
apiKey: ENV.KILN_MAINNET_API_KEY,
baseUrl: 'https://api.kiln.fi',
poolId: 'pool10rdglgh4pzvkf936p2m669qzarr9dusrhmmz9nultm3uvq4eh5k'
},
hideUnstakeAndClaimAction: true,
isLiquidStaking: true,
stakeAssets: [{ pluginId: 'cardano', currencyCode: 'ADA' }],
rewardAssets: [{ pluginId: 'cardano', currencyCode: 'ADA' }]
},
{
stakePolicyId: 'cardano_kiln_pool1',
stakeProviderInfo: {
displayName: 'Cardano Staking Pool (KILN1)',
pluginId: 'cardano',
stakeProviderId: 'cardano_pooled_kiln'
},
parentPluginId: 'cardano',
parentCurrencyCode: 'ADA',
adapterConfig: {
type: 'cardano-pooled-kiln',
pluginId: 'cardano',

accountId: ENV.KILN_MAINNET_ACCOUNT_ID,
apiKey: ENV.KILN_MAINNET_API_KEY,
baseUrl: 'https://api.kiln.fi',
poolId: 'pool1fcp4d2pxh0e7q5ju63sjqcdpxpr3pvxg6ykl23t6c97d7dnvjvw'
},
hideUnstakeAndClaimAction: true,
isLiquidStaking: true,
stakeAssets: [{ pluginId: 'cardano', currencyCode: 'ADA' }],
rewardAssets: [{ pluginId: 'cardano', currencyCode: 'ADA' }]
},
{
stakePolicyId: 'cardano_kiln_pool2',
stakeProviderInfo: {
displayName: 'Cardano Staking Pool (KILN2)',
pluginId: 'cardano',
stakeProviderId: 'cardano_pooled_kiln'
},
parentPluginId: 'cardano',
parentCurrencyCode: 'ADA',
adapterConfig: {
type: 'cardano-pooled-kiln',
pluginId: 'cardano',

accountId: ENV.KILN_MAINNET_ACCOUNT_ID,
apiKey: ENV.KILN_MAINNET_API_KEY,
baseUrl: 'https://api.kiln.fi',
poolId: 'pool1v62c7d92xv6gyh4x9rhfpkwzlpw2ypxk92xvzavakg3xypatklv'
},
hideUnstakeAndClaimAction: true,
isLiquidStaking: true,
stakeAssets: [{ pluginId: 'cardano', currencyCode: 'ADA' }],
rewardAssets: [{ pluginId: 'cardano', currencyCode: 'ADA' }]
},
{
stakePolicyId: 'cardano_kiln_pool3',
stakeProviderInfo: {
displayName: 'Cardano Staking Pool (KILN3)',
pluginId: 'cardano',
stakeProviderId: 'cardano_pooled_kiln'
},
parentPluginId: 'cardano',
parentCurrencyCode: 'ADA',
adapterConfig: {
type: 'cardano-pooled-kiln',
pluginId: 'cardano',

accountId: ENV.KILN_MAINNET_ACCOUNT_ID,
apiKey: ENV.KILN_MAINNET_API_KEY,
baseUrl: 'https://api.kiln.fi',
poolId: 'pool1mtxmk0skqkr5y0wxnxps4n35j6wn9q8dfr82y423vvlp53vccux'
},
hideUnstakeAndClaimAction: true,
isLiquidStaking: true,
stakeAssets: [{ pluginId: 'cardano', currencyCode: 'ADA' }],
rewardAssets: [{ pluginId: 'cardano', currencyCode: 'ADA' }]
},
{
stakePolicyId: 'cardano_kiln_pool4',
stakeProviderInfo: {
displayName: 'Cardano Staking Pool (KILN4)',
pluginId: 'cardano',
stakeProviderId: 'cardano_pooled_kiln'
},
parentPluginId: 'cardano',
parentCurrencyCode: 'ADA',
adapterConfig: {
type: 'cardano-pooled-kiln',
pluginId: 'cardano',

accountId: ENV.KILN_MAINNET_ACCOUNT_ID,
apiKey: ENV.KILN_MAINNET_API_KEY,
baseUrl: 'https://api.kiln.fi',
poolId: 'pool10d6mmw3mn9ku3r7uqqye672dz3sv76lh5kvh5rdpr9l5ug5yknr'
},
hideUnstakeAndClaimAction: true,
isLiquidStaking: true,
stakeAssets: [{ pluginId: 'cardano', currencyCode: 'ADA' }],
rewardAssets: [{ pluginId: 'cardano', currencyCode: 'ADA' }]
},
{
stakePolicyId: 'cardano_kiln_pool6',
stakeProviderInfo: {
displayName: 'Cardano Staking Pool (KILN6)',
pluginId: 'cardano',
stakeProviderId: 'cardano_pooled_kiln'
},
parentPluginId: 'cardano',
parentCurrencyCode: 'ADA',
adapterConfig: {
type: 'cardano-pooled-kiln',
pluginId: 'cardano',

accountId: ENV.KILN_MAINNET_ACCOUNT_ID,
apiKey: ENV.KILN_MAINNET_API_KEY,
baseUrl: 'https://api.kiln.fi',
poolId: 'pool1mtuhuh8hkf8am0qzx45y58kll8q83sjh6pwljrflcmw970d82f3'
},
hideUnstakeAndClaimAction: true,
isLiquidStaking: true,
stakeAssets: [{ pluginId: 'cardano', currencyCode: 'ADA' }],
rewardAssets: [{ pluginId: 'cardano', currencyCode: 'ADA' }]
},
{
stakePolicyId: 'cardano_kiln_pool7',
stakeProviderInfo: {
displayName: 'Cardano Staking Pool (KILN7)',
pluginId: 'cardano',
stakeProviderId: 'cardano_pooled_kiln'
},
parentPluginId: 'cardano',
parentCurrencyCode: 'ADA',
adapterConfig: {
type: 'cardano-pooled-kiln',
pluginId: 'cardano',

accountId: ENV.KILN_MAINNET_ACCOUNT_ID,
apiKey: ENV.KILN_MAINNET_API_KEY,
baseUrl: 'https://api.kiln.fi',
poolId: 'pool1aqg8vxzv75zhjzjjd9s20fu6r0xz70yl8lk3teacwy7qyc2p2j7'
},
hideUnstakeAndClaimAction: true,
isLiquidStaking: true,
stakeAssets: [{ pluginId: 'cardano', currencyCode: 'ADA' }],
rewardAssets: [{ pluginId: 'cardano', currencyCode: 'ADA' }]
},
{
stakePolicyId: 'cardano_kiln_pool8',
stakeProviderInfo: {
displayName: 'Cardano Staking Pool (KILN8)',
pluginId: 'cardano',
stakeProviderId: 'cardano_pooled_kiln'
},
parentPluginId: 'cardano',
parentCurrencyCode: 'ADA',
adapterConfig: {
type: 'cardano-pooled-kiln',
pluginId: 'cardano',

accountId: ENV.KILN_MAINNET_ACCOUNT_ID,
apiKey: ENV.KILN_MAINNET_API_KEY,
baseUrl: 'https://api.kiln.fi',
poolId: 'pool19kfm6lz5uw7nylq27swr367mqdycmug7tve94l6h3xsz64seqtc'
},
hideUnstakeAndClaimAction: true,
isLiquidStaking: true,
stakeAssets: [{ pluginId: 'cardano', currencyCode: 'ADA' }],
rewardAssets: [{ pluginId: 'cardano', currencyCode: 'ADA' }]
}
]

export const kilncardanopool: StakePluginInfo = {
pluginId: 'stake:cardano:kiln',
policyConfigs: [...kilnPolicyConfig]
}
Loading