-
Notifications
You must be signed in to change notification settings - Fork 10
3. Deploy Security Token
The form below let's token issuer configure the following token properties:
- Token Name: a human-friendly name of the token.
- Token details URL: a URL to a page or documentation with more information about the token.
- Treasury wallet: Address of a wallet to be used to store tokens for some operations. Defaults to current user (eg Token Issuer) address. Should be a valid ethereum address.
- Is Divisible: Divisible tokens may be used to represent divisible assets such as bonds. While indivisible tokens are typically used to represent an equity.
function App() {
const [state, dispatch] = useContext(Store)
const { sdk } = state.AppReducer
const form = useForm()
const { getFieldDecorator, resetFields, validateFields } = form
// ... previously added effects
// ...
return (
<Form onSubmit={createToken}>
<Title>Create Your Security Token</Title>
<Item
name="symbol"
label="Reservation">
{getFieldDecorator('symbol', {
rules: [{required: true, message: 'A token reservation is required'}],
})(<Select
placeholder="Select a reservation">
{reservations.map(({symbol}) =>
<Option key={symbol} value={symbol}>{symbol}</Option> )}
</Select>)}
</Item>
<Item
name="name"
label="Token Name">
{getFieldDecorator('name', {
rules: [{required: true, message: 'Token name is required'}, {max: 64}],
})(<Input placeholder="Enter Token Name"/>)}
</Item>
<Item
name="detailsUrl"
label="Token Details">
{getFieldDecorator('detailsUrl', {initialValue: ''})(<Input placeholder="Paste link here"/>)}
</Item>
<Item
name="treasuryWallet"
label="Treasury Wallet Address">
{getFieldDecorator('treasuryWallet', {initialValue: walletAddress,
rules: [
{ required: true },
{
validator: (rule, value, callback) => {
// Make sure it's a valid Ethereum address.
if (!web3Utils.isAddress(value)) {
callback('Address is invalid')
return
}
callback()
return
}
}
] })(<Input />)}
</Item>
<Item
name="divisible"
label="Divisible">
{getFieldDecorator('divisible', {
initialValue: false,
valuePropName: 'checked',
})(<Switch/>)}
</Item>
<Row>
<Col><Button htmlType="reset" onClick={() => resetFields()}>
Reset fields
</Button></Col>
<Col span={12}> <Button type="primary" htmlType="submit">
Create my token
</Button></Col>
</Row>
</Form>
)
}
On form submit, the following function is called. First, the function locates the relevant reservation object amongst other reservations in app state, using submitted symbol (ie values.symbol
). Then, it calls reservation.createSecurityToken(values)
to create our token.
async function createToken(e) {
e.preventDefault()
const fields = ['symbol', 'name', 'detailsUrl', 'treasuryWallet', 'divisible']
validateFields(fields, { force: true })
.then(async (values) => {
dispatch({type: 'CREATING_TOKEN'})
// Locate reservation object amongst the reservations in app state.
const reservation = reservations.filter(r => r.symbol === values.symbol)[0]
// Create security token.
try {
const q = await reservation.createSecurityToken(values)
const ret = await q.run()
dispatch({ type: 'CREATED_TOKEN'})
message.success(`Token ${reservation.symbol} has been created successfully!`)
resetFields()
}
catch (error) {
dispatch({ type: 'ERROR', error: error.message} )
}
})
}
As usual, we dispatch a few actions responsible for user feedback (eg spinners and error messages). Those actions are being handled in the reducer cases below.
export const reducer = (state, action) => {
....
switch (action.type) { case 'CREATING_TOKEN':
return {
...state,
loading: true,
loadingMessage: 'Creating token'
}
case 'CREATED_TOKEN':
return {
...state,
loading: true,
reservations: undefined,
loadingMessage: 'Refreshing reservations',
}
...
Once all pieces are in place, token creation form should look as follows.
Despite that the SDK summerises blockchain interactions into one method call (ie reservation.createSecurityToken
), the SDK will send, and ask you to sign up to 3 transactions:
- First transaction allows the
SecurityTokenRegistry
contract to withdraw a predetrmined fee that's required for token issuance (eg250 Poly
). - Second transaction creates the token with passed configuration such as token name, URL, and divisibility.
- On Kovan network, the SDK will check if the current user has enough balance of
POLY
to conduct token creation transaction. If not, it will ask Kovan's Poly faucet for the necessary amount of Poly.
Note on mainnet Ethereum network you have to ensure a sufficient balance of Poly yourself. Poly can be bought or exchanged on one of these exchanges https://coinmarketcap.com/currencies/polymath-network/#markets.
And Voila! Your token should be created as soon as the transactions above have confirmed! You can view using this simple app https://polymathnetwork.github.io/token-info/