Init splits contract helpers
This commit is contained in:
parent
8255c8dd92
commit
6914a40258
165
contracts/splits/contract.ts
Normal file
165
contracts/splits/contract.ts
Normal file
@ -0,0 +1,165 @@
|
||||
import type { SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate'
|
||||
import type { Coin } from '@cosmjs/proto-signing'
|
||||
|
||||
export interface InstantiateResponse {
|
||||
readonly contractAddress: string
|
||||
readonly transactionHash: string
|
||||
}
|
||||
|
||||
export interface SplitsInstance {
|
||||
readonly contractAddress: string
|
||||
//Query
|
||||
getAdmin: () => Promise<string>
|
||||
getMemberWeight: (member: string) => Promise<string>
|
||||
listMembers: (startAfter?: string, limit?: number) => Promise<string[]>
|
||||
getGroup: () => Promise<string>
|
||||
|
||||
//Execute
|
||||
updateAdmin: (admin: string) => Promise<string>
|
||||
distribute: () => Promise<string>
|
||||
}
|
||||
|
||||
export interface SplitsMessages {
|
||||
updateAdmin: (admin: string) => UpdateAdminMessage
|
||||
distribute: () => DistributeMessage
|
||||
}
|
||||
|
||||
export interface UpdateAdminMessage {
|
||||
sender: string
|
||||
contract: string
|
||||
msg: {
|
||||
update_admin: { admin: string }
|
||||
}
|
||||
funds: Coin[]
|
||||
}
|
||||
|
||||
export interface DistributeMessage {
|
||||
sender: string
|
||||
contract: string
|
||||
msg: { distribute: Record<string, never> }
|
||||
funds: Coin[]
|
||||
}
|
||||
|
||||
export interface SplitsContract {
|
||||
instantiate: (
|
||||
codeId: number,
|
||||
initMsg: Record<string, unknown>,
|
||||
label: string,
|
||||
admin?: string,
|
||||
) => Promise<InstantiateResponse>
|
||||
|
||||
use: (contractAddress: string) => SplitsInstance
|
||||
|
||||
messages: (contractAddress: string) => SplitsMessages
|
||||
}
|
||||
|
||||
export const Splits = (client: SigningCosmWasmClient, txSigner: string): SplitsContract => {
|
||||
const use = (contractAddress: string): SplitsInstance => {
|
||||
///QUERY
|
||||
const listMembers = async (startAfter?: string, limit?: number): Promise<string[]> => {
|
||||
return client.queryContractSmart(contractAddress, {
|
||||
list_members: { limit, start_after: startAfter },
|
||||
})
|
||||
}
|
||||
|
||||
const getMemberWeight = async (address: string): Promise<string> => {
|
||||
return client.queryContractSmart(contractAddress, {
|
||||
member: { address },
|
||||
})
|
||||
}
|
||||
|
||||
const getAdmin = async (): Promise<string> => {
|
||||
return client.queryContractSmart(contractAddress, {
|
||||
admin: {},
|
||||
})
|
||||
}
|
||||
|
||||
const getGroup = async (): Promise<string> => {
|
||||
return client.queryContractSmart(contractAddress, {
|
||||
group: {},
|
||||
})
|
||||
}
|
||||
/// EXECUTE
|
||||
const updateAdmin = async (admin: string): Promise<string> => {
|
||||
const res = await client.execute(
|
||||
txSigner,
|
||||
contractAddress,
|
||||
{
|
||||
update_admin: {
|
||||
admin,
|
||||
},
|
||||
},
|
||||
'auto',
|
||||
)
|
||||
return res.transactionHash
|
||||
}
|
||||
|
||||
const distribute = async (): Promise<string> => {
|
||||
const res = await client.execute(
|
||||
txSigner,
|
||||
contractAddress,
|
||||
{
|
||||
distribute: {},
|
||||
},
|
||||
'auto',
|
||||
)
|
||||
return res.transactionHash
|
||||
}
|
||||
return {
|
||||
contractAddress,
|
||||
updateAdmin,
|
||||
distribute,
|
||||
getMemberWeight,
|
||||
getAdmin,
|
||||
listMembers,
|
||||
getGroup,
|
||||
}
|
||||
}
|
||||
|
||||
const instantiate = async (
|
||||
codeId: number,
|
||||
initMsg: Record<string, unknown>,
|
||||
label: string,
|
||||
admin?: string,
|
||||
): Promise<InstantiateResponse> => {
|
||||
const result = await client.instantiate(txSigner, codeId, initMsg, label, 'auto', {
|
||||
admin,
|
||||
})
|
||||
|
||||
return {
|
||||
contractAddress: result.contractAddress,
|
||||
transactionHash: result.transactionHash,
|
||||
}
|
||||
}
|
||||
|
||||
const messages = (contractAddress: string) => {
|
||||
const updateAdmin = (admin: string) => {
|
||||
return {
|
||||
sender: txSigner,
|
||||
contract: contractAddress,
|
||||
msg: {
|
||||
update_admin: { admin },
|
||||
},
|
||||
funds: [],
|
||||
}
|
||||
}
|
||||
|
||||
const distribute = () => {
|
||||
return {
|
||||
sender: txSigner,
|
||||
contract: contractAddress,
|
||||
msg: {
|
||||
distribute: {},
|
||||
},
|
||||
funds: [],
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
updateAdmin,
|
||||
distribute,
|
||||
}
|
||||
}
|
||||
|
||||
return { use, instantiate, messages }
|
||||
}
|
2
contracts/splits/index.ts
Normal file
2
contracts/splits/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './contract'
|
||||
export * from './useContract'
|
77
contracts/splits/messages/execute.ts
Normal file
77
contracts/splits/messages/execute.ts
Normal file
@ -0,0 +1,77 @@
|
||||
import type { SplitsInstance } from '../index'
|
||||
import { useSplitsContract } from '../index'
|
||||
|
||||
export type ExecuteType = typeof EXECUTE_TYPES[number]
|
||||
|
||||
export const EXECUTE_TYPES = ['update_admin', 'distribute'] as const
|
||||
|
||||
export interface ExecuteListItem {
|
||||
id: ExecuteType
|
||||
name: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
export const EXECUTE_LIST: ExecuteListItem[] = [
|
||||
{
|
||||
id: 'update_admin',
|
||||
name: 'Update Admin',
|
||||
description: `Update the splits contract admin`,
|
||||
},
|
||||
{
|
||||
id: 'distribute',
|
||||
name: 'Distribute',
|
||||
description: `Distribute the revenue to the group members`,
|
||||
},
|
||||
]
|
||||
|
||||
export interface DispatchExecuteProps {
|
||||
type: ExecuteType
|
||||
[k: string]: unknown
|
||||
}
|
||||
|
||||
type Select<T extends ExecuteType> = T
|
||||
|
||||
/** @see {@link SplitsInstance} */
|
||||
export type DispatchExecuteArgs = {
|
||||
contract: string
|
||||
messages?: SplitsInstance
|
||||
} & ({ type: Select<'update_admin'>; admin: string } | { type: Select<'distribute'> })
|
||||
|
||||
export const dispatchExecute = async (args: DispatchExecuteArgs) => {
|
||||
const { messages } = args
|
||||
if (!messages) {
|
||||
throw new Error('Cannot dispatch execute, messages are not defined')
|
||||
}
|
||||
switch (args.type) {
|
||||
case 'update_admin': {
|
||||
return messages.updateAdmin(args.admin)
|
||||
}
|
||||
case 'distribute': {
|
||||
return messages.distribute()
|
||||
}
|
||||
default: {
|
||||
throw new Error('Unknown execution type')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const previewExecutePayload = (args: DispatchExecuteArgs) => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
const { messages } = useSplitsContract()
|
||||
const { contract } = args
|
||||
switch (args.type) {
|
||||
case 'update_admin': {
|
||||
return messages(contract)?.updateAdmin(args.admin)
|
||||
}
|
||||
case 'distribute': {
|
||||
return messages(contract)?.distribute()
|
||||
}
|
||||
default: {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const isEitherType = <T extends ExecuteType>(type: unknown, arr: T[]): type is T => {
|
||||
return arr.some((val) => type === val)
|
||||
}
|
43
contracts/splits/messages/query.ts
Normal file
43
contracts/splits/messages/query.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import type { SplitsInstance } from '../contract'
|
||||
|
||||
export type QueryType = typeof QUERY_TYPES[number]
|
||||
|
||||
export const QUERY_TYPES = ['admin', 'group', 'member', 'list_members'] as const
|
||||
|
||||
export interface QueryListItem {
|
||||
id: QueryType
|
||||
name: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
export const QUERY_LIST: QueryListItem[] = [
|
||||
{ id: 'admin', name: 'Query Admin', description: 'View the splits contract admin' },
|
||||
{ id: 'member', name: 'Query Member Weight', description: 'Check the weight of a member in the group' },
|
||||
{ id: 'list_members', name: 'Query Members', description: 'View the group members' },
|
||||
{ id: 'group', name: 'Query Group Contract Address', description: 'View the group contract address' },
|
||||
]
|
||||
|
||||
export interface DispatchQueryProps {
|
||||
messages: SplitsInstance | undefined
|
||||
type: QueryType
|
||||
address: string
|
||||
startAfter: string
|
||||
limit: number
|
||||
}
|
||||
|
||||
export const dispatchQuery = (props: DispatchQueryProps) => {
|
||||
const { messages, type, address, startAfter, limit } = props
|
||||
switch (type) {
|
||||
case 'list_members':
|
||||
return messages?.listMembers(startAfter, limit)
|
||||
case 'admin':
|
||||
return messages?.getAdmin()
|
||||
case 'member':
|
||||
return messages?.getMemberWeight(address)
|
||||
case 'group':
|
||||
return messages?.getGroup()
|
||||
default: {
|
||||
throw new Error('unknown query type')
|
||||
}
|
||||
}
|
||||
}
|
76
contracts/splits/useContract.ts
Normal file
76
contracts/splits/useContract.ts
Normal file
@ -0,0 +1,76 @@
|
||||
/* eslint-disable eslint-comments/disable-enable-pair */
|
||||
|
||||
import { useWallet } from 'contexts/wallet'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
|
||||
import type { InstantiateResponse, SplitsContract, SplitsInstance, SplitsMessages } from './contract'
|
||||
import { Splits as initContract } from './contract'
|
||||
|
||||
export interface UseSplitsContractProps {
|
||||
instantiate: (
|
||||
codeId: number,
|
||||
initMsg: Record<string, unknown>,
|
||||
label: string,
|
||||
admin?: string,
|
||||
) => Promise<InstantiateResponse>
|
||||
|
||||
use: (customAddress?: string) => SplitsInstance | undefined
|
||||
|
||||
updateContractAddress: (contractAddress: string) => void
|
||||
|
||||
messages: (contractAddress: string) => SplitsMessages | undefined
|
||||
}
|
||||
|
||||
export function useSplitsContract(): UseSplitsContractProps {
|
||||
const wallet = useWallet()
|
||||
|
||||
const [address, setAddress] = useState<string>('')
|
||||
const [splits, setSplits] = useState<SplitsContract>()
|
||||
|
||||
useEffect(() => {
|
||||
setAddress(localStorage.getItem('contract_address') || '')
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const splitsContract = initContract(wallet.getClient(), wallet.address)
|
||||
setSplits(splitsContract)
|
||||
}, [wallet])
|
||||
|
||||
const updateContractAddress = (contractAddress: string) => {
|
||||
setAddress(contractAddress)
|
||||
}
|
||||
|
||||
const instantiate = useCallback(
|
||||
(codeId: number, initMsg: Record<string, unknown>, label: string, admin?: string): Promise<InstantiateResponse> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!splits) {
|
||||
reject(new Error('Contract is not initialized.'))
|
||||
return
|
||||
}
|
||||
splits.instantiate(codeId, initMsg, label, admin).then(resolve).catch(reject)
|
||||
})
|
||||
},
|
||||
[splits],
|
||||
)
|
||||
|
||||
const use = useCallback(
|
||||
(customAddress = ''): SplitsInstance | undefined => {
|
||||
return splits?.use(address || customAddress)
|
||||
},
|
||||
[splits, address],
|
||||
)
|
||||
|
||||
const messages = useCallback(
|
||||
(customAddress = ''): SplitsMessages | undefined => {
|
||||
return splits?.messages(address || customAddress)
|
||||
},
|
||||
[splits, address],
|
||||
)
|
||||
|
||||
return {
|
||||
instantiate,
|
||||
use,
|
||||
updateContractAddress,
|
||||
messages,
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user