diff --git a/.gitignore b/.gitignore index f18b582..2ac6f23 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ settings/Mainnet.toml settings/Testnet.toml history.txt + +client/node_modules +client/yarn-error.log diff --git a/client/README.md b/client/README.md new file mode 100644 index 0000000..4512dd1 --- /dev/null +++ b/client/README.md @@ -0,0 +1,18 @@ +# Token Vesting client application + +## Instructions + +``` +$ yarn install +``` + +``` +$ npm run serve +``` +to run the development mode. + + +``` +$ yarn build +``` +to bundle the application. diff --git a/client/index.html b/client/index.html new file mode 100644 index 0000000..c9e2cce --- /dev/null +++ b/client/index.html @@ -0,0 +1,12 @@ + + + + + Vesting Client + + + + +
+ + diff --git a/client/package.json b/client/package.json new file mode 100644 index 0000000..9b092ad --- /dev/null +++ b/client/package.json @@ -0,0 +1,34 @@ +{ + "dependencies": { + "@stacks/blockchain-api-client": "^1.0.4", + "@stacks/network": "^3.0.0", + "@stacks/transactions": "^3.1.0", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "tsconfig-paths-webpack-plugin": "^3.5.2" + }, + "devDependencies": { + "@types/react": "^17.0.38", + "@types/react-dom": "^17.0.11", + "@webpack-cli/generators": "^2.4.1", + "css-loader": "^6.5.1", + "html-webpack-plugin": "^5.5.0", + "prettier": "^2.5.1", + "style-loader": "^3.3.1", + "ts-loader": "^9.2.6", + "typescript": "^4.5.4", + "webpack": "^5.65.0", + "webpack-cli": "^4.9.1", + "webpack-dev-server": "^4.7.1" + }, + "version": "0.0.1", + "description": "Vesting Client", + "name": "vesting-client", + "scripts": { + "build": "webpack --mode=production --node-env=production", + "build:dev": "webpack --mode=development", + "build:prod": "webpack --mode=production --node-env=production", + "watch": "webpack --watch", + "serve": "webpack serve" + } +} diff --git a/client/src/App.tsx b/client/src/App.tsx new file mode 100644 index 0000000..1835871 --- /dev/null +++ b/client/src/App.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import "./index.css"; + +import { VestingSection } from '@components/VestingSection'; + +const App = () => { + return ( +
+
+
+
Arkadiko - Vesting Contract
+
+
+
+ +
+ ); +} + +export default App; diff --git a/client/src/components/ContractDetail.tsx b/client/src/components/ContractDetail.tsx new file mode 100644 index 0000000..c41d6cd --- /dev/null +++ b/client/src/components/ContractDetail.tsx @@ -0,0 +1,112 @@ +import React from 'react'; + +import { + makeContractCall, + broadcastTransaction, + AnchorMode, + standardPrincipalCV, + contractPrincipalCV, + uintCV, + listCV, + tupleCV +} from '@stacks/transactions'; + +import { + StacksMainnet, + StacksTestnet, + StacksMocknet +} from '@stacks/network'; + +interface InputProps { + txIdFromLocking: any +} + +export const ContractDetail: React.FC = (props) => { + const [contract, setContract] = React.useState(''); + const [token, setToken] = React.useState(''); + const [amount, setAmount] = React.useState(''); + const [lockingPeriod, setLockingPeriod] = React.useState(''); + const [assignees, setAssignees] = React.useState(''); + + const handleAssignees = () => { + let assigneesList: any[] = []; + assignees.split(' ').join('').split(',').forEach((assignee) => { + assigneesList.push( + tupleCV({ + address: standardPrincipalCV(assignee), + amount: uintCV(123) + }) + ); + }); + + return listCV(assigneesList); + }; + + const lock = async () => { + let assigneesList = handleAssignees(); + // TODO set url dynamically + const network = new StacksMocknet({ url: 'http://localhost:3999' }); + const txOptions = { + contractAddress: contract, + contractName: "token-vesting", + functionName: "deposit", + functionArgs: [ + contractPrincipalCV(contract, token), + uintCV(amount), + uintCV(lockingPeriod), + assigneesList + ], + // TODO set senderKey from an environment variable? + senderKey: '753b7cc01a1a2e86221266a154af739463fce51219d97e4f856cd7200c3bd2a601', + validateWithAbi: true, + network, + postConditionMode: 1, + anchorMode: AnchorMode.Any, + fee: 300n + }; + + const transaction = await makeContractCall(txOptions); + const broadcastResponse = await broadcastTransaction(transaction, network); + const txId = broadcastResponse.txid; + props.txIdFromLocking(txId); + }; + + return ( +
+
+
+
+ Vesting Contract +

Add vesting details and click "Lock Tokens" to finish

+
+ + setContract(e.target.value)}/> +
+
+ + setToken(e.target.value)}/> +
+
+ + setAmount(e.target.value)}/> +
+
+ + setLockingPeriod(e.target.value)}/> +
+
+ +