Add controls for cancelling subscription and for withdrawing recieived funds

This commit is contained in:
silverpill 2022-05-23 22:40:18 +00:00
parent 57caecc88b
commit fe6ef494e3
2 changed files with 172 additions and 26 deletions

View file

@ -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
}

View file

@ -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>