From 310626d64bb059478140813a9d2f9f9097fd3a98 Mon Sep 17 00:00:00 2001 From: Bernardo Vieira Date: Thu, 29 Jun 2023 14:22:31 +0100 Subject: [PATCH] useBorrower and useLoanManager --- .../components/MicroCredit/UserLoans.tsx | 4 +- package.json | 2 +- src/abi/MicroCreditABI.json | 33 ++++++++ src/contracts.ts | 26 +++++- src/index.ts | 3 +- src/{useMicroCredit.tsx => useBorrower.tsx} | 21 ++--- src/useLoanManager.tsx | 81 +++++++++++++++++++ yarn.lock | 22 +---- 8 files changed, 149 insertions(+), 43 deletions(-) rename src/{useMicroCredit.tsx => useBorrower.tsx} (92%) create mode 100644 src/useLoanManager.tsx diff --git a/example-web/pages/components/MicroCredit/UserLoans.tsx b/example-web/pages/components/MicroCredit/UserLoans.tsx index ecdec9f..7c899e6 100644 --- a/example-web/pages/components/MicroCredit/UserLoans.tsx +++ b/example-web/pages/components/MicroCredit/UserLoans.tsx @@ -1,9 +1,9 @@ -import { useMicroCredit } from '@impact-market/utils/useMicroCredit'; +import { useBorrower } from '@impact-market/utils/useBorrower'; import React, { useState } from 'react'; import { useAccount } from 'wagmi'; const UserLoans = () => { - const { userLoans, claimLoan, approve, repayLoan, getActiveLoanId, loan } = useMicroCredit(); + const { userLoans, claimLoan, approve, repayLoan, getActiveLoanId, loan } = useBorrower(); const { address } = useAccount(); const [amount, setAmount] = useState('0'); diff --git a/package.json b/package.json index 710f89a..64e105b 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "ts-node": "10.9.1", "typedoc": "0.24.7", "typescript": "4.9.5", - "viem": "1.2.5", + "viem": "1.2.1", "wagmi": "1.3.3" }, "peerDependencies": { diff --git a/src/abi/MicroCreditABI.json b/src/abi/MicroCreditABI.json index 911669c..b4c21a3 100644 --- a/src/abi/MicroCreditABI.json +++ b/src/abi/MicroCreditABI.json @@ -48,5 +48,38 @@ ], "name": "walletMetadata", "inputs": [{ "type": "address", "name": "_userAddress", "internalType": "address" }] + }, + { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "addLoans", + "inputs": [ + { "type": "address[]", "name": "_userAddresses", "internalType": "address[]" }, + { "type": "uint256[]", "name": "_amounts", "internalType": "uint256[]" }, + { "type": "uint256[]", "name": "_periods", "internalType": "uint256[]" }, + { "type": "uint256[]", "name": "_dailyInterests", "internalType": "uint256[]" }, + { "type": "uint256[]", "name": "_claimDeadlines", "internalType": "uint256[]" } + ] + }, + { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "cancelLoans", + "inputs": [ + { "type": "address[]", "name": "_userAddresses", "internalType": "address[]" }, + { "type": "uint256[]", "name": "_loansIds", "internalType": "uint256[]" } + ] + }, + { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "changeUserAddress", + "inputs": [ + { "type": "address", "name": "_oldWalletAddress", "internalType": "address" }, + { "type": "address", "name": "_newWalletAddress", "internalType": "address" } + ] } ] diff --git a/src/contracts.ts b/src/contracts.ts index e072c88..4b62c3a 100644 --- a/src/contracts.ts +++ b/src/contracts.ts @@ -38,11 +38,33 @@ export interface IDepositRedirect extends Contract { interest(depositorAddress: string, tokenAddress: string, amount: string): Promise; } +export type UserLoans = { + amountBorrowed: BigNumber; + period: BigNumber; + dailyInterest: BigNumber; + claimDeadline: BigNumber; + startDate: BigNumber; + currentDebt: BigNumber; + lastComputedDebt: BigNumber; + amountRepayed: BigNumber; + repaymentsLength: BigNumber; + lastComputedDate: BigNumber; +}; + export interface IMicroCredit extends Contract { approve(loanId: string, amount: string): Promise; - userLoans(userAddress: string, loanId: string): Promise; + userLoans(userAddress: string, loanId: number | string): Promise; claimLoan(loanId: string): Promise; repayLoan(loanId: string, amount: string): Promise; + addLoans( + userAddresses: string[], + amounts: number[], + periods: number[], + dailyInterests: number[], + startDates: number[] + ): Promise; + cancelLoans(userAddresses: string[], loansIds: number[]): Promise; + changeUserAddress(oldWalletAddress: string, newWalletAddress: string): Promise; } export const getContracts = (provider: BaseProvider, networkId: number) => { @@ -92,7 +114,7 @@ export const getContracts = (provider: BaseProvider, networkId: number) => { const merkleDistributor = new Contract(addresses.merkleDistributor, MerkleDistributorABI, provider); - const microCredit = new Contract(addresses.microCredit, MicroCreditABI, provider); + const microCredit = new Contract(addresses.microCredit, MicroCreditABI, provider) as IMicroCredit; const donationMiner = new Contract(addresses.donationMiner, DonationMinerABI, provider); diff --git a/src/index.ts b/src/index.ts index 870c9f7..c338ac6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,7 +11,8 @@ export * from './useManager'; export * from './useEpoch'; export * from './useRewards'; export * from './useMerkleDistributor'; -export * from './useMicroCredit'; +export * from './useBorrower'; +export * from './useLoanManager'; export * from './useAmbassador'; export * from './useImpactMarketCouncil'; export * from './useStaking'; diff --git a/src/useMicroCredit.tsx b/src/useBorrower.tsx similarity index 92% rename from src/useMicroCredit.tsx rename to src/useBorrower.tsx index 647190d..76315ad 100644 --- a/src/useMicroCredit.tsx +++ b/src/useBorrower.tsx @@ -1,6 +1,6 @@ import { Contract } from '@ethersproject/contracts'; import { ImpactProviderContext } from './ImpactProvider'; -import { getContracts } from './contracts'; +import { UserLoans, getContracts } from './contracts'; import { internalUseTransaction } from './internalUseTransaction'; import { toNumber } from './toNumber'; import { toToken } from './toToken'; @@ -27,19 +27,8 @@ export type Loan = { repaymentsLength: number; startDate: number; }; -type RawLoan = { - amountBorrowed: BigNumber; - amountRepayed: BigNumber; - currentDebt: BigNumber; - dailyInterest: BigNumber; - lastComputedDate: BigNumber; - lastComputedDebt: BigNumber; - period: BigNumber; - repaymentsLength: BigNumber; - startDate: BigNumber; -}; -export const useMicroCredit = () => { +export const useBorrower = () => { const { provider, address, signer, networkId } = React.useContext(ImpactProviderContext); const executeTransaction = internalUseTransaction(); const [loan, setLoan] = useState({ @@ -114,10 +103,10 @@ export const useMicroCredit = () => { /** * Private method to dedut loan status - * @param {RawLoan} loan Loan raw data from smart-contract + * @param {UserLoans} loan Loan raw data from smart-contract * @returns {number} loan status */ - const _loanStatus = (loan: RawLoan): number => { + const _loanStatus = (loan: UserLoans): number => { if (loan.lastComputedDebt.toString() === '0') { if (loan.period.toNumber() === 0) { return LoanStatus.NO_LOAN; @@ -131,7 +120,7 @@ export const useMicroCredit = () => { return LoanStatus.LOAN_CLAIMED; }; - const updateLoan = (data: RawLoan) => { + const updateLoan = (data: UserLoans) => { const { amountBorrowed, amountRepayed, diff --git a/src/useLoanManager.tsx b/src/useLoanManager.tsx new file mode 100644 index 0000000..1c0482c --- /dev/null +++ b/src/useLoanManager.tsx @@ -0,0 +1,81 @@ +import { ImpactProviderContext } from './ImpactProvider'; +import { getContracts } from './contracts'; +import { internalUseTransaction } from './internalUseTransaction'; +import { toToken } from './toToken'; +import React from 'react'; + +export const useLoanManager = () => { + const { provider, address, signer, networkId } = React.useContext(ImpactProviderContext); + const executeTransaction = internalUseTransaction(); + + /** + * Add loans + * @param {string[]} userAddresses addresses to add loans to + * @param {number[]} amounts amount of each loan + * @param {number[]} periods periods of each loan + * @param {number[]} dailyInterests daily interests of each loan + * @param {number[]} startDates start dates of each loan + * @returns {Promise} tx details + */ + const addLoans = async ( + userAddresses: string[], + amounts: number[], + periods: number[], + dailyInterests: number[], + startDates: number[] + ) => { + if (!address || !signer) { + throw new Error('No wallet connected'); + } + + const { microCredit } = getContracts(provider, networkId); + const tx = await microCredit.populateTransaction.addLoans( + userAddresses, + amounts.map(amount => toToken(amount)), + periods, + dailyInterests.map(interest => toToken(interest)), + startDates + ); + const response = await executeTransaction(tx); + + return response; + }; + + /** + * Cancel loans + * @param {string[]} userAddresses addresses to cancel loans + * @param {number[]} loansIds ids of each loan + * @returns {Promise} tx details + */ + const cancelLoans = async (userAddresses: string[], loansIds: number[]) => { + if (!address || !signer) { + throw new Error('No wallet connected'); + } + + const { microCredit } = getContracts(provider, networkId); + const tx = await microCredit.populateTransaction.cancelLoans(userAddresses, loansIds); + const response = await executeTransaction(tx); + + return response; + }; + + /** + * Change user address + * @param {string} oldWalletAddress old wallet address + * @param {string} newWalletAddress new wallet address + * @returns {Promise} tx details + */ + const changeUserAddress = async (oldWalletAddress: string, newWalletAddress: string) => { + if (!address || !signer) { + throw new Error('No wallet connected'); + } + + const { microCredit } = getContracts(provider, networkId); + const tx = await microCredit.populateTransaction.changeUserAddress(oldWalletAddress, newWalletAddress); + const response = await executeTransaction(tx); + + return response; + }; + + return { addLoans, cancelLoans, changeUserAddress }; +}; diff --git a/yarn.lock b/yarn.lock index a007264..7a4ae0b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2445,11 +2445,6 @@ abab@^2.0.5, abab@^2.0.6: resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== -abitype@0.8.11: - version "0.8.11" - resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.8.11.tgz#66e1cf2cbf46f48d0e57132d7c1c392447536cc1" - integrity sha512-bM4v2dKvX08sZ9IU38IN5BKmN+ZkOSd2oI4a9f0ejHYZQYV6cDr7j+d95ga0z2XHG36Y4jzoG5Z7qDqxp7fi/A== - abitype@0.8.7: version "0.8.7" resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.8.7.tgz#e4b3f051febd08111f486c0cc6a98fa72d033622" @@ -6922,22 +6917,7 @@ valtio@1.10.6: proxy-compare "2.5.1" use-sync-external-store "1.2.0" -viem@1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/viem/-/viem-1.2.5.tgz#e9f80a57b80d8749624b4b31a98041549a25c5ad" - integrity sha512-AeQ1hiyPKXnWb/KTsxRLt7KZUmLgd6NTCe/GyQf+8TZO7ndXmSZf88swE+60v1bLT+FDUWXufKGJ2oNT129wXw== - dependencies: - "@adraffy/ens-normalize" "1.9.0" - "@noble/curves" "1.0.0" - "@noble/hashes" "1.3.0" - "@scure/bip32" "1.3.0" - "@scure/bip39" "1.2.0" - "@wagmi/chains" "1.2.0" - abitype "0.8.11" - isomorphic-ws "5.0.0" - ws "8.12.0" - -viem@^1.0.0: +viem@1.2.1, viem@^1.0.0: version "1.2.1" resolved "https://registry.yarnpkg.com/viem/-/viem-1.2.1.tgz#88ea214b50ce6c74b0173c1cdfb5bb4bc7f6134d" integrity sha512-45eyE1QsPzUTJqslOD8SVAF3Nn3QMLZIKTu/YzaPPe8UuDMwrmvAWlfDole2kBzFAM8B6sXsQeZBQKYwtb7dVQ==