forked from solana-labs/governance-ui
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Airdrop by dual finance (#7) (solana-labs#1422)
* Name token only after the mint has been initialized * Merkle airdrop in realms * Allow hex input * Fix validation * Fix validation * yarn lock * yarn lock * Change label for amount
- Loading branch information
Showing
8 changed files
with
265 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
105 changes: 105 additions & 0 deletions
105
pages/dao/[symbol]/proposal/components/instructions/Dual/DualAirdrop.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import React, { useContext, useEffect, useState } from 'react' | ||
import { ProgramAccount, Governance } from '@solana/spl-governance' | ||
import { | ||
UiInstruction, | ||
DualFinanceAirdropForm, | ||
} from '@utils/uiTypes/proposalCreationTypes' | ||
import { NewProposalContext } from '../../../new' | ||
import GovernedAccountSelect from '../../GovernedAccountSelect' | ||
import useGovernanceAssets from '@hooks/useGovernanceAssets' | ||
import Input from '@components/inputs/Input' | ||
import { getAirdropInstruction } from '@utils/instructions/Dual/airdrop' | ||
import useWalletStore from 'stores/useWalletStore' | ||
import { getDualFinanceAirdropSchema } from '@utils/validations' | ||
import Tooltip from '@components/Tooltip' | ||
|
||
const DualAirdrop = ({ | ||
index, | ||
governance, | ||
}: { | ||
index: number | ||
governance: ProgramAccount<Governance> | null | ||
}) => { | ||
const [form, setForm] = useState<DualFinanceAirdropForm>({ | ||
root: '', | ||
amount: 0, | ||
treasury: undefined, | ||
}) | ||
const connection = useWalletStore((s) => s.connection) | ||
const wallet = useWalletStore((s) => s.current) | ||
const shouldBeGoverned = !!(index !== 0 && governance) | ||
const { assetAccounts } = useGovernanceAssets() | ||
const [governedAccount, setGovernedAccount] = useState< | ||
ProgramAccount<Governance> | undefined | ||
>(undefined) | ||
const [formErrors, setFormErrors] = useState({}) | ||
const { handleSetInstructions } = useContext(NewProposalContext) | ||
const handleSetForm = ({ propertyName, value }) => { | ||
setFormErrors({}) | ||
setForm({ ...form, [propertyName]: value }) | ||
} | ||
function getInstruction(): Promise<UiInstruction> { | ||
return getAirdropInstruction({ | ||
connection, | ||
form, | ||
schema, | ||
setFormErrors, | ||
wallet, | ||
}) | ||
} | ||
useEffect(() => { | ||
handleSetInstructions( | ||
{ governedAccount: governedAccount, getInstruction }, | ||
index | ||
) | ||
}, [form]) | ||
useEffect(() => { | ||
setGovernedAccount(form.treasury?.governance) | ||
}, [form.treasury]) | ||
const schema = getDualFinanceAirdropSchema() | ||
|
||
return ( | ||
<> | ||
<Tooltip content="Merkle root of the airdrop. https://github.com/Dual-Finance/airdrop-sdk/blob/97d97492bdb926f150a6436a68a77eda35fc7095/src/utils/balance_tree.ts#L40"> | ||
<Input | ||
label="Root" | ||
value={form.root} | ||
type="text" | ||
onChange={(evt) => | ||
handleSetForm({ | ||
value: evt.target.value, | ||
propertyName: 'root', | ||
}) | ||
} | ||
error={formErrors['root']} | ||
/> | ||
</Tooltip> | ||
<Input | ||
label="Total number of tokens" | ||
value={form.amount} | ||
type="text" | ||
onChange={(evt) => | ||
handleSetForm({ | ||
value: evt.target.value, | ||
propertyName: 'amount', | ||
}) | ||
} | ||
error={formErrors['amount']} | ||
/> | ||
<GovernedAccountSelect | ||
label="Treasury" | ||
governedAccounts={assetAccounts} | ||
onChange={(value) => { | ||
handleSetForm({ value, propertyName: 'treasury' }) | ||
}} | ||
value={form.treasury} | ||
error={formErrors['treasury']} | ||
shouldBeGoverned={shouldBeGoverned} | ||
governance={governance} | ||
type="token" | ||
></GovernedAccountSelect> | ||
</> | ||
) | ||
} | ||
|
||
export default DualAirdrop |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import { | ||
serializeInstructionToBase64, | ||
} from '@solana/spl-governance' | ||
|
||
import { ConnectionContext } from '@utils/connection' | ||
import { validateInstruction } from '@utils/instructionTools' | ||
import { | ||
DualFinanceAirdropForm, | ||
UiInstruction, | ||
} from '@utils/uiTypes/proposalCreationTypes' | ||
import { WalletAdapter } from '@solana/wallet-adapter-base' | ||
import { Airdrop, AirdropConfigureContext } from '@dual-finance/airdrop' | ||
import { Keypair } from '@solana/web3.js' | ||
import { BN } from '@coral-xyz/anchor' | ||
import { getMintNaturalAmountFromDecimalAsBN } from '@tools/sdk/units' | ||
|
||
interface AirdropArgs { | ||
connection: ConnectionContext | ||
form: DualFinanceAirdropForm | ||
setFormErrors: any | ||
schema: any | ||
wallet: WalletAdapter | undefined | ||
} | ||
|
||
export async function getAirdropInstruction({ | ||
connection, | ||
wallet, | ||
form, | ||
schema, | ||
setFormErrors, | ||
}: AirdropArgs): Promise<UiInstruction> { | ||
const isValid = await validateInstruction({ schema, form, setFormErrors }) | ||
|
||
const serializedInstruction = '' | ||
const additionalSerializedInstructions: string[] = [] | ||
if (isValid && form.treasury && wallet?.publicKey && form.treasury.extensions.mint?.account.decimals) { | ||
const airdrop = new Airdrop(connection.endpoint) | ||
|
||
const amountNatural: BN = getMintNaturalAmountFromDecimalAsBN( | ||
form.amount, | ||
form.treasury.extensions.mint?.account.decimals | ||
); | ||
|
||
let root: number[] = []; | ||
try { | ||
root = Array.from(Uint8Array.from(Buffer.from(form.root, 'hex'))); | ||
} catch (err) { | ||
root = form.root.split(',').map(function(item) { | ||
return parseInt(item, 10); | ||
}); | ||
} | ||
const airdropTransactionContext: AirdropConfigureContext = await airdrop.createConfigMerkleTransactionFromRoot( | ||
form.treasury.pubkey, // source | ||
form.treasury.extensions.token!.account.owner!, // authority | ||
amountNatural, | ||
root, | ||
); | ||
|
||
for (const instruction of airdropTransactionContext.transaction.instructions) { | ||
additionalSerializedInstructions.push( | ||
serializeInstructionToBase64(instruction) | ||
) | ||
} | ||
|
||
return { | ||
serializedInstruction, | ||
additionalSerializedInstructions, | ||
signers: airdropTransactionContext.signers as Keypair[], | ||
isValid: true, | ||
governance: form.treasury?.governance, | ||
} | ||
} | ||
|
||
return { | ||
serializedInstruction, | ||
isValid: false, | ||
governance: form.treasury?.governance, | ||
additionalSerializedInstructions: [], | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -873,6 +873,16 @@ | |
js-sha256 "^0.9.0" | ||
tweetnacl "1.0.3" | ||
|
||
"@dual-finance/[email protected]": | ||
version "0.0.4" | ||
resolved "https://registry.yarnpkg.com/@dual-finance/airdrop/-/airdrop-0.0.4.tgz#12ee6f1a99f52725eaa783c522efd7021981db3c" | ||
integrity sha512-eLBC1pzJwqhniVvHm3b26RWcLEVcFRL3OA94FsagUiWzSY7uYLigo5phBvN153dviaI+AiNPc86aQ85IlY+AAA== | ||
dependencies: | ||
"@coral-xyz/anchor" "^0.26.0" | ||
"@solana/spl-token" "^0.3.6" | ||
"@solana/web3.js" "^1.73.2" | ||
js-sha3 "^0.8.0" | ||
|
||
"@dual-finance/[email protected]": | ||
version "0.0.17" | ||
resolved "https://registry.yarnpkg.com/@dual-finance/staking-options/-/staking-options-0.0.17.tgz#e56f7eb8be7d1364ac7fac6e0d0e8b79cab833cf" | ||
|
@@ -5011,7 +5021,7 @@ | |
"@wallet-standard/app" "^1.0.0" | ||
"@wallet-standard/base" "^1.0.0" | ||
|
||
"@solana/[email protected]", "@solana/[email protected]", "@solana/[email protected]", "@solana/web3.js@^1.16.1", "@solana/web3.js@^1.17.0", "@solana/web3.js@^1.20.0", "@solana/web3.js@^1.21.0", "@solana/web3.js@^1.22.0", "@solana/web3.js@^1.24.1", "@solana/web3.js@^1.29.2", "@solana/web3.js@^1.30.2", "@solana/web3.js@^1.31.0", "@solana/web3.js@^1.32.0", "@solana/web3.js@^1.35.0", "@solana/web3.js@^1.35.1", "@solana/web3.js@^1.36.0", "@solana/web3.js@^1.37.1", "@solana/web3.js@^1.42.0", "@solana/web3.js@^1.44.3", "@solana/web3.js@^1.48.0", "@solana/web3.js@^1.56.2", "@solana/web3.js@^1.59.1", "@solana/web3.js@^1.63.0", "@solana/web3.js@^1.63.1", "@solana/web3.js@^1.66.2", "@solana/web3.js@^1.68.0": | ||
"@solana/[email protected]", "@solana/[email protected]", "@solana/[email protected]", "@solana/web3.js@^1.16.1", "@solana/web3.js@^1.17.0", "@solana/web3.js@^1.20.0", "@solana/web3.js@^1.21.0", "@solana/web3.js@^1.22.0", "@solana/web3.js@^1.24.1", "@solana/web3.js@^1.29.2", "@solana/web3.js@^1.30.2", "@solana/web3.js@^1.31.0", "@solana/web3.js@^1.32.0", "@solana/web3.js@^1.35.0", "@solana/web3.js@^1.35.1", "@solana/web3.js@^1.36.0", "@solana/web3.js@^1.37.1", "@solana/web3.js@^1.42.0", "@solana/web3.js@^1.43.5", "@solana/web3.js@^1.44.3", "@solana/web3.js@^1.48.0", "@solana/web3.js@^1.56.2", "@solana/web3.js@^1.59.1", "@solana/web3.js@^1.63.0", "@solana/web3.js@^1.63.1", "@solana/web3.js@^1.66.2", "@solana/web3.js@^1.68.0", "@solana/web3.js@^1.73.2": | ||
version "1.66.2" | ||
resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.66.2.tgz#80b43c5868b846124fe3ebac7d3943930c3fa60c" | ||
integrity sha512-RyaHMR2jGmaesnYP045VLeBGfR/gAW3cvZHzMFGg7bkO+WOYOYp1nEllf0/la4U4qsYGKCsO9eEevR5fhHiVHg== | ||
|