Add controls for cancelling subscription and for withdrawing recieived funds
This commit is contained in:
parent
57caecc88b
commit
fe6ef494e3
2 changed files with 172 additions and 26 deletions
|
@ -43,8 +43,6 @@ export interface Subscription {
|
|||
tokenAddress: string;
|
||||
tokenSymbol: string;
|
||||
price: FixedNumber;
|
||||
senderAddress: string | null;
|
||||
senderBalance: FixedNumber | null;
|
||||
}
|
||||
|
||||
const SECONDS_IN_MONTH = 3600 * 24 * 30
|
||||
|
@ -64,27 +62,39 @@ export async function getSubscriptionInfo(
|
|||
const priceInt = await adapter.getSubscriptionPrice(recipientAddress)
|
||||
const pricePerMonth = priceInt.mul(SECONDS_IN_MONTH)
|
||||
const price = FixedNumber.fromValue(pricePerMonth, tokenDecimals).round(2)
|
||||
const signerAddress = await signer.getAddress()
|
||||
let senderAddress = null
|
||||
let senderBalance = null
|
||||
if (!ethereumAddressMatch(signerAddress, recipientAddress)) {
|
||||
senderAddress = signerAddress
|
||||
const [senderBalanceInt] = await adapter.getSubscriptionState(senderAddress, recipientAddress)
|
||||
senderBalance = FixedNumber.fromValue(senderBalanceInt, tokenDecimals).round(2)
|
||||
}
|
||||
return {
|
||||
recipientAddress,
|
||||
tokenAddress,
|
||||
tokenSymbol,
|
||||
price,
|
||||
senderAddress,
|
||||
senderBalance,
|
||||
}
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export interface SubscriptionState {
|
||||
senderAddress: string;
|
||||
senderBalance: FixedNumber;
|
||||
recipientBalance: FixedNumber;
|
||||
}
|
||||
|
||||
export async function getSubscriptionState(
|
||||
contractAddress: string,
|
||||
signer: Signer,
|
||||
senderAddress: string,
|
||||
recipientAddress: string,
|
||||
): Promise<SubscriptionState> {
|
||||
const adapter = await getContract(Contracts.Adapter, contractAddress, signer)
|
||||
const tokenAddress = await adapter.subscriptionToken()
|
||||
const token = await getContract(Contracts.ERC20, tokenAddress, signer)
|
||||
const tokenDecimals = await token.decimals()
|
||||
const [senderBalanceInt, recipientBalanceInt] = await adapter.getSubscriptionState(senderAddress, recipientAddress)
|
||||
const senderBalance = FixedNumber.fromValue(senderBalanceInt, tokenDecimals)
|
||||
const recipientBalance = FixedNumber.fromValue(recipientBalanceInt, tokenDecimals)
|
||||
return { senderAddress, senderBalance, recipientBalance }
|
||||
}
|
||||
|
||||
export async function makeSubscriptionPayment(
|
||||
contractAddress: string,
|
||||
signer: Signer,
|
||||
|
@ -112,3 +122,27 @@ export async function makeSubscriptionPayment(
|
|||
)
|
||||
return transaction
|
||||
}
|
||||
|
||||
export async function cancelSubscription(
|
||||
contractAddress: string,
|
||||
signer: Signer,
|
||||
recipientAddress: string,
|
||||
): Promise<TransactionResponse> {
|
||||
const adapter = await getContract(Contracts.Adapter, contractAddress, signer)
|
||||
const subscriptionAddress = await adapter.subscription()
|
||||
const subscription = await getContract(Contracts.Subscription, subscriptionAddress, signer)
|
||||
const transaction = await subscription.cancel(recipientAddress)
|
||||
return transaction
|
||||
}
|
||||
|
||||
export async function withdrawReceived(
|
||||
contractAddress: string,
|
||||
signer: Signer,
|
||||
senderAddress: string,
|
||||
): Promise<TransactionResponse> {
|
||||
const adapter = await getContract(Contracts.Adapter, contractAddress, signer)
|
||||
const subscriptionAddress = await adapter.subscription()
|
||||
const subscription = await getContract(Contracts.Subscription, subscriptionAddress, signer)
|
||||
const transaction = await subscription.withdrawReceived(senderAddress)
|
||||
return transaction
|
||||
}
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
<div>Token address: {{ subscription.tokenAddress }}</div>
|
||||
<div>Token symbol: {{ subscription.tokenSymbol }}</div>
|
||||
<div>Price of one month: {{ subscription.price }}</div>
|
||||
<template v-if="subscription.senderAddress">
|
||||
<div>Your address: {{ subscription.senderAddress }}</div>
|
||||
<div>Your balance: {{ subscription.senderBalance }}</div>
|
||||
<template v-if="!isRecipient() && subscriptionState">
|
||||
<div>Your address: {{ subscriptionState.senderAddress }}</div>
|
||||
<div>Your balance: {{ subscriptionState.senderBalance }}</div>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else-if="isCurrentUser()">
|
||||
|
@ -35,6 +35,18 @@
|
|||
Pay for subscription
|
||||
</button>
|
||||
</div>
|
||||
<div class="cancel" v-if="canCancel()">
|
||||
<button class="btn" @click="onCancelSubscription()">
|
||||
Cancel subscription
|
||||
</button>
|
||||
</div>
|
||||
<div class="withdraw" v-if="isRecipient()">
|
||||
<input v-model="subscriberAddress" placeholder="Subscriber address">
|
||||
<button class="btn" @click="onCheckSubsciptionState()">Check</button>
|
||||
<button class="btn" v-if="canWithdrawReceived()" @click="onWithdrawReceived()">
|
||||
Withdraw {{ subscriptionState.recipientBalance }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<sidebar></sidebar>
|
||||
</div>
|
||||
|
@ -52,24 +64,31 @@ import {
|
|||
Profile,
|
||||
} from "@/api/users"
|
||||
import {
|
||||
cancelSubscription,
|
||||
configureSubscription,
|
||||
getSubscriptionAuthorization,
|
||||
getSubscriptionInfo,
|
||||
getSubscriptionState,
|
||||
makeSubscriptionPayment,
|
||||
withdrawReceived,
|
||||
Subscription,
|
||||
SubscriptionState,
|
||||
} from "@/api/subscriptions"
|
||||
import Sidebar from "@/components/Sidebar.vue"
|
||||
import { useInstanceInfo } from "@/store/instance"
|
||||
import { useCurrentUser } from "@/store/user"
|
||||
import { getWallet, getWeb3Provider } from "@/utils/ethereum"
|
||||
import { ethereumAddressMatch, getWallet, getWeb3Provider } from "@/utils/ethereum"
|
||||
|
||||
const route = useRoute()
|
||||
const { currentUser, ensureAuthToken } = $(useCurrentUser())
|
||||
const { instance, getActorAddress } = $(useInstanceInfo())
|
||||
let profile = $ref<Profile | null>(null)
|
||||
let profileEthereumAddress = $ref<string | null>(null)
|
||||
let walletConnected = $ref(false)
|
||||
let subscriptionConfigured = $ref<boolean | null>(null)
|
||||
let subscription = $ref<Subscription | null>(null)
|
||||
let subscriptionState = $ref<SubscriptionState | null>(null)
|
||||
let subscriberAddress = $ref<string | null>(null)
|
||||
|
||||
onMounted(async () => {
|
||||
const { authToken } = useCurrentUser()
|
||||
|
@ -77,6 +96,7 @@ onMounted(async () => {
|
|||
authToken,
|
||||
route.params.profileId,
|
||||
)
|
||||
profileEthereumAddress = getVerifiedEthereumAddress(profile)
|
||||
})
|
||||
|
||||
function isCurrentUser(): boolean {
|
||||
|
@ -91,7 +111,7 @@ function canConnectWallet(): boolean {
|
|||
return (
|
||||
Boolean(instance?.blockchain_contract_address) &&
|
||||
profile !== null &&
|
||||
getVerifiedEthereumAddress(profile) !== null &&
|
||||
profileEthereumAddress !== null &&
|
||||
!walletConnected
|
||||
)
|
||||
}
|
||||
|
@ -99,6 +119,8 @@ function canConnectWallet(): boolean {
|
|||
function disconnectWallet() {
|
||||
subscriptionConfigured = null
|
||||
subscription = null
|
||||
subscriptionState = null
|
||||
subscriberAddress = null
|
||||
walletConnected = false
|
||||
}
|
||||
|
||||
|
@ -126,15 +148,12 @@ async function connectWallet() {
|
|||
async function checkSubscription() {
|
||||
if (
|
||||
!profile ||
|
||||
!profileEthereumAddress ||
|
||||
!instance ||
|
||||
!instance.blockchain_contract_address
|
||||
) {
|
||||
return
|
||||
}
|
||||
const profileEthereumAddress = getVerifiedEthereumAddress(profile)
|
||||
if (!profileEthereumAddress) {
|
||||
return
|
||||
}
|
||||
const signer = getWeb3Provider().getSigner()
|
||||
subscription = await getSubscriptionInfo(
|
||||
instance.blockchain_contract_address,
|
||||
|
@ -146,6 +165,16 @@ async function checkSubscription() {
|
|||
} else {
|
||||
subscriptionConfigured = false
|
||||
}
|
||||
const signerAddress = await signer.getAddress()
|
||||
if (!ethereumAddressMatch(signerAddress, profileEthereumAddress)) {
|
||||
// Connected wallet is a subscriber
|
||||
subscriptionState = await getSubscriptionState(
|
||||
instance.blockchain_contract_address,
|
||||
signer,
|
||||
signerAddress,
|
||||
profileEthereumAddress,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function canConfigureSubscription(): boolean {
|
||||
|
@ -188,15 +217,12 @@ function canSubscribe(): boolean {
|
|||
async function onMakeSubscriptionPayment() {
|
||||
if (
|
||||
!profile ||
|
||||
!profileEthereumAddress ||
|
||||
!instance ||
|
||||
!instance.blockchain_contract_address
|
||||
) {
|
||||
return
|
||||
}
|
||||
const profileEthereumAddress = getVerifiedEthereumAddress(profile)
|
||||
if (!profileEthereumAddress) {
|
||||
return
|
||||
}
|
||||
const signer = getWeb3Provider().getSigner()
|
||||
const transaction = await makeSubscriptionPayment(
|
||||
instance.blockchain_contract_address,
|
||||
|
@ -209,6 +235,81 @@ async function onMakeSubscriptionPayment() {
|
|||
signer,
|
||||
profileEthereumAddress,
|
||||
)
|
||||
subscriptionState = await getSubscriptionState(
|
||||
instance.blockchain_contract_address,
|
||||
signer,
|
||||
await signer.getAddress(),
|
||||
profileEthereumAddress,
|
||||
)
|
||||
}
|
||||
|
||||
function canCancel(): boolean {
|
||||
return !isCurrentUser() && subscription?.senderBalance && !subscription.senderBalance.isZero()
|
||||
}
|
||||
|
||||
async function onCancelSubscription() {
|
||||
if (
|
||||
!profile ||
|
||||
!profileEthereumAddress ||
|
||||
!instance?.blockchain_contract_address
|
||||
) {
|
||||
return
|
||||
}
|
||||
const signer = getWeb3Provider().getSigner()
|
||||
const transaction = await cancelSubscription(
|
||||
instance.blockchain_contract_address,
|
||||
signer,
|
||||
profileEthereumAddress,
|
||||
)
|
||||
await transaction.wait()
|
||||
subscription = await getSubscriptionInfo(
|
||||
instance.blockchain_contract_address,
|
||||
signer,
|
||||
profileEthereumAddress,
|
||||
)
|
||||
}
|
||||
|
||||
function isRecipient(): boolean {
|
||||
return isCurrentUser() && subscription
|
||||
}
|
||||
|
||||
async function onCheckSubsciptionState() {
|
||||
if (
|
||||
!profile ||
|
||||
!profileEthereumAddress ||
|
||||
!instance?.blockchain_contract_address ||
|
||||
!subscriberAddress
|
||||
) {
|
||||
return
|
||||
}
|
||||
const signer = getWeb3Provider().getSigner()
|
||||
subscriptionState = await getSubscriptionState(
|
||||
instance.blockchain_contract_address,
|
||||
signer,
|
||||
subscriberAddress,
|
||||
profileEthereumAddress,
|
||||
)
|
||||
}
|
||||
|
||||
function canWithdrawReceived(): boolean {
|
||||
return isRecipient() && subscriptionState !== null
|
||||
}
|
||||
|
||||
async function onWithdrawReceived() {
|
||||
if (
|
||||
!profile ||
|
||||
!instance?.blockchain_contract_address ||
|
||||
!subscriberAddress
|
||||
) {
|
||||
return
|
||||
}
|
||||
const signer = getWeb3Provider().getSigner()
|
||||
await withdrawReceived(
|
||||
instance.blockchain_contract_address,
|
||||
signer,
|
||||
subscriberAddress,
|
||||
)
|
||||
subscriptionState = null
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -224,7 +325,7 @@ async function onMakeSubscriptionPayment() {
|
|||
border-radius: $block-border-radius;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $block-inner-padding;
|
||||
gap: $block-inner-padding / 2;
|
||||
margin-bottom: $block-outer-padding;
|
||||
padding: $block-inner-padding;
|
||||
|
||||
|
@ -233,4 +334,15 @@ async function onMakeSubscriptionPayment() {
|
|||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.withdraw {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: $block-inner-padding / 2;
|
||||
|
||||
input {
|
||||
border: 1px solid $btn-background-hover-color;
|
||||
border-radius: $btn-border-radius;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in a new issue