Add Token image from URL (#4916)
This commit is contained in:
parent
f8aec7571f
commit
a25d935a1d
@ -19,7 +19,7 @@ import { Dialog, RaisedButton, FlatButton, SelectField, MenuItem } from 'materia
|
|||||||
import AddIcon from 'material-ui/svg-icons/content/add';
|
import AddIcon from 'material-ui/svg-icons/content/add';
|
||||||
|
|
||||||
import InputText from '../../Inputs/Text';
|
import InputText from '../../Inputs/Text';
|
||||||
import { ADDRESS_TYPE } from '../../Inputs/validation';
|
import { ADDRESS_TYPE, URL_TYPE } from '../../Inputs/validation';
|
||||||
|
|
||||||
import styles from './token.css';
|
import styles from './token.css';
|
||||||
|
|
||||||
@ -128,6 +128,22 @@ export default class AddMeta extends Component {
|
|||||||
|
|
||||||
renderForm () {
|
renderForm () {
|
||||||
const selectedMeta = metaDataKeys[this.state.metaKeyIndex];
|
const selectedMeta = metaDataKeys[this.state.metaKeyIndex];
|
||||||
|
const metaLabel = selectedMeta.label.toLowerCase();
|
||||||
|
let metaType;
|
||||||
|
|
||||||
|
switch (selectedMeta.validation) {
|
||||||
|
case ADDRESS_TYPE:
|
||||||
|
metaType = 'Address';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case URL_TYPE:
|
||||||
|
metaType = 'URL';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
metaType = 'URL Hint';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -145,7 +161,7 @@ export default class AddMeta extends Component {
|
|||||||
<InputText
|
<InputText
|
||||||
key={ selectedMeta.value }
|
key={ selectedMeta.value }
|
||||||
floatingLabelText={ `${selectedMeta.label} value` }
|
floatingLabelText={ `${selectedMeta.label} value` }
|
||||||
hintText={ `The value of the ${selectedMeta.label.toLowerCase()} (${selectedMeta.validation === ADDRESS_TYPE ? 'Address' : 'Url Hint'})` }
|
hintText={ `The value of the ${metaLabel} (${metaType})` }
|
||||||
|
|
||||||
validationType={ selectedMeta.validation }
|
validationType={ selectedMeta.validation }
|
||||||
onChange={ this.onChange }
|
onChange={ this.onChange }
|
||||||
@ -174,14 +190,20 @@ export default class AddMeta extends Component {
|
|||||||
|
|
||||||
onAdd = () => {
|
onAdd = () => {
|
||||||
const { index } = this.props;
|
const { index } = this.props;
|
||||||
|
const { form, metaKeyIndex } = this.state;
|
||||||
|
|
||||||
|
const selectedMeta = metaDataKeys[metaKeyIndex];
|
||||||
|
|
||||||
const keyIndex = this.state.metaKeyIndex;
|
const keyIndex = this.state.metaKeyIndex;
|
||||||
const key = metaDataKeys[keyIndex].value;
|
const key = metaDataKeys[keyIndex].value;
|
||||||
|
const value = form.value;
|
||||||
|
const validationType = selectedMeta.validation;
|
||||||
|
|
||||||
this.props.handleAddMeta(
|
this.props.handleAddMeta(
|
||||||
index,
|
index,
|
||||||
key,
|
key,
|
||||||
this.state.form.value
|
value,
|
||||||
|
validationType
|
||||||
);
|
);
|
||||||
|
|
||||||
this.setState({ complete: true });
|
this.setState({ complete: true });
|
||||||
|
@ -61,8 +61,8 @@ const mapDispatchToProps = (dispatch) => {
|
|||||||
dispatch(unregisterToken(index));
|
dispatch(unregisterToken(index));
|
||||||
},
|
},
|
||||||
|
|
||||||
handleAddMeta: (index, key, value) => {
|
handleAddMeta: (index, key, value, validationType) => {
|
||||||
dispatch(addTokenMeta(index, key, value));
|
dispatch(addTokenMeta(index, key, value, validationType));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -14,7 +14,8 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import { getTokenTotalSupply } from '../utils';
|
import { URL_TYPE } from '../Inputs/validation';
|
||||||
|
import { getTokenTotalSupply, urlToHash } from '../utils';
|
||||||
|
|
||||||
const { bytesToHex } = window.parity.api.util;
|
const { bytesToHex } = window.parity.api.util;
|
||||||
|
|
||||||
@ -178,40 +179,63 @@ export const queryTokenMeta = (index, query) => (dispatch, getState) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addTokenMeta = (index, key, value) => (dispatch, getState) => {
|
export const addTokenMeta = (index, key, value, validationType) => (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
||||||
const contractInstance = state.status.contract.instance;
|
const contractInstance = state.status.contract.instance;
|
||||||
|
const ghhInstance = state.status.githubhint.instance;
|
||||||
|
|
||||||
const token = state.tokens.tokens.find(t => t.index === index);
|
const token = state.tokens.tokens.find(t => t.index === index);
|
||||||
const options = { from: token.owner };
|
const options = { from: token.owner };
|
||||||
const values = [ index, key, value ];
|
let valuesPromise;
|
||||||
|
|
||||||
contractInstance
|
// Get the right values (could be a hashed URL from GHH)
|
||||||
.setMeta
|
if (validationType === URL_TYPE) {
|
||||||
.estimateGas(options, values)
|
valuesPromise = addGithubhintURL(ghhInstance, options, value)
|
||||||
.then((gasEstimate) => {
|
.then((hash) => [ index, key, hash ]);
|
||||||
options.gas = gasEstimate.mul(1.2).toFixed(0);
|
} else {
|
||||||
return contractInstance.setMeta.postTransaction(options, values);
|
valuesPromise = Promise.resolve([ index, key, value ]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return valuesPromise
|
||||||
|
.then((values) => {
|
||||||
|
return contractInstance
|
||||||
|
.setMeta
|
||||||
|
.estimateGas(options, values)
|
||||||
|
.then((gasEstimate) => {
|
||||||
|
options.gas = gasEstimate.mul(1.2).toFixed(0);
|
||||||
|
return contractInstance.setMeta.postTransaction(options, values);
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error(`addTokenMeta: #${index} error`, e);
|
console.error(`addTokenMeta: #${index} error`, e);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addGithubhintURL = (from, key, url) => (dispatch, getState) => {
|
export const addGithubhintURL = (ghhInstance, _options, url) => {
|
||||||
const state = getState();
|
return urlToHash(ghhInstance, url)
|
||||||
const contractInstance = state.status.githubhint.instance;
|
.then((result) => {
|
||||||
const options = { from };
|
const { hash, registered } = result;
|
||||||
const values = [ key, url ];
|
|
||||||
|
|
||||||
contractInstance
|
if (registered) {
|
||||||
.hintURL
|
return hash;
|
||||||
.estimateGas(options, values)
|
}
|
||||||
.then((gasEstimate) => {
|
|
||||||
options.gas = gasEstimate.mul(1.2).toFixed(0);
|
const options = { from: _options.from };
|
||||||
return contractInstance.hintURL.postTransaction(options, values);
|
const values = [ hash, url ];
|
||||||
})
|
|
||||||
.catch((e) => {
|
ghhInstance
|
||||||
console.error('addGithubhintURL error', e);
|
.hintURL
|
||||||
|
.estimateGas(options, values)
|
||||||
|
.then((gasEstimate) => {
|
||||||
|
options.gas = gasEstimate.mul(1.2).toFixed(0);
|
||||||
|
return ghhInstance.hintURL.postTransaction(options, values);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(`registering "${url}" to GHH`, error);
|
||||||
|
});
|
||||||
|
|
||||||
|
return hash;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,13 +14,13 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import { HEX_TYPE, ADDRESS_TYPE } from './Inputs/validation';
|
import { URL_TYPE, ADDRESS_TYPE } from './Inputs/validation';
|
||||||
|
|
||||||
export const metaDataKeys = [
|
export const metaDataKeys = [
|
||||||
{
|
{
|
||||||
label: 'Image',
|
label: 'Image',
|
||||||
value: 'IMG',
|
value: 'IMG',
|
||||||
validation: HEX_TYPE
|
validation: URL_TYPE
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Address',
|
label: 'Address',
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
const { api } = window.parity;
|
const api = window.parent.secureApi;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
api
|
api
|
||||||
|
@ -18,6 +18,45 @@ import { api } from './parity';
|
|||||||
|
|
||||||
import { eip20 as eip20Abi } from '~/contracts/abi';
|
import { eip20 as eip20Abi } from '~/contracts/abi';
|
||||||
|
|
||||||
|
export const INVALID_URL_HASH = '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470';
|
||||||
|
export const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the given URL to a content hash,
|
||||||
|
* and checks if it is already registered in GHH
|
||||||
|
*/
|
||||||
|
export const urlToHash = (ghhInstance, url) => {
|
||||||
|
if (!url || !url.length) {
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return api.parity
|
||||||
|
.hashContent(url)
|
||||||
|
.catch((error) => {
|
||||||
|
const message = error.text || error.message || error.toString();
|
||||||
|
|
||||||
|
throw new Error(`${message} (${url})`);
|
||||||
|
})
|
||||||
|
.then((contentHash) => {
|
||||||
|
console.log('lookupHash', url, contentHash);
|
||||||
|
|
||||||
|
if (contentHash === INVALID_URL_HASH) {
|
||||||
|
throw new Error(`"${url}" is not a valid URL`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ghhInstance.entries
|
||||||
|
.call({}, [contentHash])
|
||||||
|
.then(([accountSlashRepo, commit, contentHashOwner]) => {
|
||||||
|
const registered = (contentHashOwner !== ZERO_ADDRESS);
|
||||||
|
|
||||||
|
return {
|
||||||
|
hash: contentHash,
|
||||||
|
registered
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const getTokenTotalSupply = (tokenAddress) => {
|
export const getTokenTotalSupply = (tokenAddress) => {
|
||||||
return api
|
return api
|
||||||
.eth
|
.eth
|
||||||
|
@ -32,7 +32,8 @@
|
|||||||
"description": "A registry of transactable tokens on the network",
|
"description": "A registry of transactable tokens on the network",
|
||||||
"author": "Parity Team <admin@ethcore.io>",
|
"author": "Parity Team <admin@ethcore.io>",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"visible": true
|
"visible": true,
|
||||||
|
"secure": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "0xf49089046f53f5d2e5f3513c1c32f5ff57d986e46309a42d2b249070e4e72c46",
|
"id": "0xf49089046f53f5d2e5f3513c1c32f5ff57d986e46309a42d2b249070e4e72c46",
|
||||||
|
Loading…
Reference in New Issue
Block a user