Add Token image from URL (#4916)

This commit is contained in:
Nicolas Gotchac 2017-03-15 16:49:47 +01:00 committed by Gav Wood
parent f8aec7571f
commit a25d935a1d
7 changed files with 118 additions and 32 deletions

View File

@ -19,7 +19,7 @@ import { Dialog, RaisedButton, FlatButton, SelectField, MenuItem } from 'materia
import AddIcon from 'material-ui/svg-icons/content/add';
import InputText from '../../Inputs/Text';
import { ADDRESS_TYPE } from '../../Inputs/validation';
import { ADDRESS_TYPE, URL_TYPE } from '../../Inputs/validation';
import styles from './token.css';
@ -128,6 +128,22 @@ export default class AddMeta extends Component {
renderForm () {
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 (
<div>
@ -145,7 +161,7 @@ export default class AddMeta extends Component {
<InputText
key={ selectedMeta.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 }
onChange={ this.onChange }
@ -174,14 +190,20 @@ export default class AddMeta extends Component {
onAdd = () => {
const { index } = this.props;
const { form, metaKeyIndex } = this.state;
const selectedMeta = metaDataKeys[metaKeyIndex];
const keyIndex = this.state.metaKeyIndex;
const key = metaDataKeys[keyIndex].value;
const value = form.value;
const validationType = selectedMeta.validation;
this.props.handleAddMeta(
index,
key,
this.state.form.value
value,
validationType
);
this.setState({ complete: true });

View File

@ -61,8 +61,8 @@ const mapDispatchToProps = (dispatch) => {
dispatch(unregisterToken(index));
},
handleAddMeta: (index, key, value) => {
dispatch(addTokenMeta(index, key, value));
handleAddMeta: (index, key, value, validationType) => {
dispatch(addTokenMeta(index, key, value, validationType));
}
};
};

View File

@ -14,7 +14,8 @@
// You should have received a copy of the GNU General Public License
// 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;
@ -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 contractInstance = state.status.contract.instance;
const ghhInstance = state.status.githubhint.instance;
const token = state.tokens.tokens.find(t => t.index === index);
const options = { from: token.owner };
const values = [ index, key, value ];
let valuesPromise;
contractInstance
// Get the right values (could be a hashed URL from GHH)
if (validationType === URL_TYPE) {
valuesPromise = addGithubhintURL(ghhInstance, options, value)
.then((hash) => [ index, key, hash ]);
} else {
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) => {
console.error(`addTokenMeta: #${index} error`, e);
});
};
export const addGithubhintURL = (from, key, url) => (dispatch, getState) => {
const state = getState();
const contractInstance = state.status.githubhint.instance;
const options = { from };
const values = [ key, url ];
export const addGithubhintURL = (ghhInstance, _options, url) => {
return urlToHash(ghhInstance, url)
.then((result) => {
const { hash, registered } = result;
contractInstance
if (registered) {
return hash;
}
const options = { from: _options.from };
const values = [ hash, url ];
ghhInstance
.hintURL
.estimateGas(options, values)
.then((gasEstimate) => {
options.gas = gasEstimate.mul(1.2).toFixed(0);
return contractInstance.hintURL.postTransaction(options, values);
return ghhInstance.hintURL.postTransaction(options, values);
})
.catch((e) => {
console.error('addGithubhintURL error', e);
.catch((error) => {
console.error(`registering "${url}" to GHH`, error);
});
return hash;
});
};

View File

@ -14,13 +14,13 @@
// You should have received a copy of the GNU General Public License
// 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 = [
{
label: 'Image',
value: 'IMG',
validation: HEX_TYPE
validation: URL_TYPE
},
{
label: 'Address',

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
const { api } = window.parity;
const api = window.parent.secureApi;
export {
api

View File

@ -18,6 +18,45 @@ import { api } from './parity';
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) => {
return api
.eth

View File

@ -32,7 +32,8 @@
"description": "A registry of transactable tokens on the network",
"author": "Parity Team <admin@ethcore.io>",
"version": "1.0.0",
"visible": true
"visible": true,
"secure": true
},
{
"id": "0xf49089046f53f5d2e5f3513c1c32f5ff57d986e46309a42d2b249070e4e72c46",