From 8be2309393eb6e7efc096932c150b155bed85212 Mon Sep 17 00:00:00 2001
From: Renzo <rontivero@ultimamillasa.com.ar>
Date: Thu, 30 Apr 2020 17:15:00 -0300
Subject: [PATCH] Habilitando red Rinkeby

---
 api/controllers/AccountController.js     |  14 +-
 api/controllers/BfaController.js         | 150 ++++++++++++++++++++
 api/controllers/BlockchainController.js  |  25 ++--
 api/controllers/RinkebyController.js     | 169 +++++++++++++++++++++++
 api/controllers/TransactionController.js |  14 +-
 api/helpers/get-block-number.js          |  22 ++-
 api/helpers/get-block.js                 |   9 +-
 api/helpers/get-hash.js                  |  22 ++-
 api/helpers/get-ots.js                   |  14 +-
 api/helpers/verify-hash.js               |  43 ++++--
 api/models/Bfa.js                        |  29 ++++
 api/models/Rinkeby.js                    |  29 ++++
 config/custom.js                         |  27 ++--
 config/routes.js                         |   5 +
 14 files changed, 507 insertions(+), 65 deletions(-)
 create mode 100755 api/controllers/BfaController.js
 create mode 100755 api/controllers/RinkebyController.js
 create mode 100755 api/models/Bfa.js
 create mode 100755 api/models/Rinkeby.js

diff --git a/api/controllers/AccountController.js b/api/controllers/AccountController.js
index 017cc8d..c4cc5fb 100755
--- a/api/controllers/AccountController.js
+++ b/api/controllers/AccountController.js
@@ -7,16 +7,16 @@
 
 const Web3 = require('web3');
 const Tx = require('ethereumjs-tx');
-const url = sails.config.custom.urlRpc;
+const url = sails.config.custom.urlRpcRopsten;
 const web3 = new Web3(url);
-const accountAddress = sails.config.custom.accountAddress;
-const contractABI = sails.config.custom.contractABI;
-const contractAddress = sails.config.custom.contractAddress;
-const privateKey = Buffer.from(
-  sails.config.custom.privateKey,
+const accountAddressRopsten = sails.config.custom.accountAddressRopsten;
+const contractABIRopsten = sails.config.custom.contractABIRopsten;
+const contractAddressRopsten = sails.config.custom.contractAddressRopsten;
+const privateKeyRopsten = Buffer.from(
+  sails.config.custom.privateKeyRopsten,
   'hex',
 );
-const contract = new web3.eth.Contract(contractABI, contractAddress);
+const contract = new web3.eth.Contract(contractABIRopsten, contractAddressRopsten);
 
 module.exports = {
   create : async function (req, res){
diff --git a/api/controllers/BfaController.js b/api/controllers/BfaController.js
new file mode 100755
index 0000000..5c1e907
--- /dev/null
+++ b/api/controllers/BfaController.js
@@ -0,0 +1,150 @@
+/**
+ * BfaController
+ *
+ * @description :: Server-side actions for handling incoming requests.
+ * @help        :: See https://sailsjs.com/docs/concepts/actions
+ */
+const Web3 = require('web3');
+const Tx = require('ethereumjs-tx');
+const base64 = require('nodejs-base64-encode');
+const url = sails.config.custom.urlRpcRopsten;
+const web3 = new Web3(url);
+const accountAddress = sails.config.custom.accountAddressRopsten;
+const contractABI = sails.config.custom.contractABIRopsten;
+const contractAddress = sails.config.custom.contractAddressRopsten;
+const privateKey = Buffer.from(
+  sails.config.custom.privateKeyRopsten,
+  'hex',
+);
+const contract = new web3.eth.Contract(contractABI, contractAddress);
+
+module.exports = {
+  
+  verify : async function (req, res){  
+	  	sails.log("Verify("+req.params.ots+", "+req.params.file_hash+")");
+	  	const file_hash = req.params.file_hash;
+	  	const base64_ots = req.params.ots;	  	
+
+	  	// Transformo datos
+	  	const aux_ots = base64.decode(base64_ots.toString(), 'base64');
+	  	var array_ots = aux_ots.split('-');
+	  	
+	  	// OTS definitivo  	
+	  	var permanent_ots;
+
+		if(array_ots.length != 2){
+	  		return res.json('El OTS enviado es inválido');
+	  	}
+	  	
+	  	const ots = array_ots[0]; // Este es el  OpenTimeStamp (OTS) original creado en el método stamp() con el helper getOts(); Es un ID único para cada request.
+	  	const tx_hash = array_ots[1]; // Hash de la TX obtenida de la blockchain
+
+	  	// Antes de verificar el contenido del OTS y el HASH
+	  	// Verifico el estado de la transacción
+		var tx = await web3.eth.getTransaction(tx_hash, async (err, _tx) => {
+	  		if(err){
+				return res.json(err.toString());
+			}
+			
+			// Significa que la TX aún no se incluye en un bloque.
+			if(!_tx.blockNumber){
+				return res.json({
+					status : 'pending',
+					tx_hash : tx_hash,					
+					file_hash : file_hash,
+					ots : ots,
+					msg : 'La Transacción aún no es incluida en un Bloque. Intente nuevamente en unos minutos.'
+				});			
+			}
+
+			// Verifico si el OTS + File_Hash enviado son válidos
+			const result_verify = await sails.helpers.verifyHash(ots, file_hash, url, accountAddress, contractABI, contractAddress, privateKey);
+
+			
+			if(result_verify){
+
+				const block_number = await sails.helpers.getBlockNumber(ots, url, contractABI, contractAddress);
+
+				// Tengo que obtener el bloque entero, para sacar su timestamp
+				const block = await sails.helpers.getBlock(block_number, url);
+				
+				return res.json({
+					status : 'success',
+					tx_hash : tx_hash,
+					block_number : block_number,
+					file_hash : file_hash,
+					ots : ots,
+					contract_address: contractAddress,
+					timestamp : block.timestamp,
+					block_hash : block.hash
+				});
+			} else {
+							
+				var file_hash_by_ots = await sails.helpers.getHash(ots, accountAddress, contractAddress);
+				
+				return res.json({
+					status : 'fail',
+					file_hash_by_ots : file_hash_by_ots,
+					file_hash_send : file_hash,
+					tx_hash : tx_hash,					
+					ots : ots,
+					msg : 'El HASH del archivo enviado no se corresponde con el OTS.'
+				});	 
+				
+				
+			}
+			
+	  	});
+  	
+  },
+
+  stamp : async function (req, res){
+  		sails.log("Stamp("+req.body.file_hash+")");
+	  	const file_hash = req.body.file_hash;
+	  	// A partir del Hash recibido, genero el OpenTimeStamp (OTS)
+	  	const ots = await sails.helpers.getOts(file_hash, accountAddress, contractAddress);
+	  	var comprobante_ots;
+
+	  	web3.eth.getTransactionCount(accountAddress, (err, txCount) => {
+
+			const data = contract.methods.stamp(ots, file_hash).encodeABI();
+
+			// Construir la transaccion
+			const txObject = {
+				nonce: web3.utils.toHex(txCount),
+				to: contractAddress,		
+				gasLimit: web3.utils.toHex(800000),
+				// TODO: revisar que el precio sea automático
+				gasPrice: web3.utils.toHex(web3.utils.toWei('1000', 'gwei')),
+				data: data
+			}
+
+			// Firmar la transaccion
+			const tx = new Tx(txObject);
+			tx.sign(privateKey);
+
+			const serializeTransaction = tx.serialize();
+			const raw = '0x' + serializeTransaction.toString('hex');
+
+			// Transmitir la transacción
+			web3.eth.sendSignedTransaction(raw, (err, tx_hash) => {
+				
+				if(err){					
+					return res.json(err.toString());
+				}
+
+				comprobante_ots = ots + '-' + tx_hash;
+
+				// Si está todo bien, retorno el OpenTimeStamp definitivo para luego comprobar si el hash del archivo junto con este comprobante son válidos
+				comprobante_ots = base64.encode(comprobante_ots.toString(), 'base64');
+
+				return res.json({
+					comprobante_ots : comprobante_ots,
+					tx_hash : tx_hash
+				});
+			});
+		});
+	  
+  },
+};
+
diff --git a/api/controllers/BlockchainController.js b/api/controllers/BlockchainController.js
index 35f5023..cd32393 100755
--- a/api/controllers/BlockchainController.js
+++ b/api/controllers/BlockchainController.js
@@ -7,13 +7,13 @@
 const Web3 = require('web3');
 const Tx = require('ethereumjs-tx');
 const base64 = require('nodejs-base64-encode');
-const url = sails.config.custom.urlRpc;
+const url = sails.config.custom.urlRpcRopsten;
 const web3 = new Web3(url);
-const accountAddress = sails.config.custom.accountAddress;
-const contractABI = sails.config.custom.contractABI;
-const contractAddress = sails.config.custom.contractAddress;
+const accountAddress = sails.config.custom.accountAddressRopsten;
+const contractABI = sails.config.custom.contractABIRopsten;
+const contractAddress = sails.config.custom.contractAddressRopsten;
 const privateKey = Buffer.from(
-  sails.config.custom.privateKey,
+  sails.config.custom.privateKeyRopsten,
   'hex',
 );
 const contract = new web3.eth.Contract(contractABI, contractAddress);
@@ -23,7 +23,7 @@ module.exports = {
   verify : async function (req, res){  
 	  	sails.log("Verify("+req.params.ots+", "+req.params.file_hash+")");
 	  	const file_hash = req.params.file_hash;
-	  	const base64_ots = req.params.ots;
+	  	const base64_ots = req.params.ots;	  	
 
 	  	// Transformo datos
 	  	const aux_ots = base64.decode(base64_ots.toString(), 'base64');
@@ -58,18 +58,15 @@ module.exports = {
 			}
 
 			// Verifico si el OTS + File_Hash enviado son válidos
-			const result_verify = await sails.helpers.verifyHash.with({
-				ots: ots,
-				file_hash: file_hash,
-			});
+			const result_verify = await sails.helpers.verifyHash(ots, file_hash, url, accountAddress, contractABI, contractAddress, privateKey);
 
 			
 			if(result_verify){
 
-				const block_number = await sails.helpers.getBlockNumber(ots);
+				const block_number = await sails.helpers.getBlockNumber(ots, url, contractABI, contractAddress);
 
 				// Tengo que obtener el bloque entero, para sacar su timestamp
-				const block = await sails.helpers.getBlock(block_number);
+				const block = await sails.helpers.getBlock(block_number, url);
 				
 				return res.json({
 					status : 'success',
@@ -83,7 +80,7 @@ module.exports = {
 				});
 			} else {
 							
-				var file_hash_by_ots = await sails.helpers.getHash(ots);
+				var file_hash_by_ots = await sails.helpers.getHash(ots, accountAddress, contractAddress);
 				
 				return res.json({
 					status : 'fail',
@@ -105,7 +102,7 @@ module.exports = {
   		sails.log("Stamp("+req.body.file_hash+")");
 	  	const file_hash = req.body.file_hash;
 	  	// A partir del Hash recibido, genero el OpenTimeStamp (OTS)
-	  	const ots = await sails.helpers.getOts(file_hash);
+	  	const ots = await sails.helpers.getOts(file_hash, accountAddress, contractAddress);
 	  	var comprobante_ots;
 
 	  	web3.eth.getTransactionCount(accountAddress, (err, txCount) => {
diff --git a/api/controllers/RinkebyController.js b/api/controllers/RinkebyController.js
new file mode 100755
index 0000000..24d1c79
--- /dev/null
+++ b/api/controllers/RinkebyController.js
@@ -0,0 +1,169 @@
+/**
+ * Rinkebyontroller
+ *
+ * @description :: Server-side actions for handling incoming requests.
+ * @help        :: See https://sailsjs.com/docs/concepts/actions
+ */
+const Web3 = require('web3');
+const Tx = require('ethereumjs-tx');
+const base64 = require('nodejs-base64-encode');
+const url = sails.config.custom.urlRpcRinkeby;
+const web3 = new Web3(url);
+const accountAddress = sails.config.custom.accountAddressRinkeby;
+const contractABI = sails.config.custom.contractABIRinkeby;
+const contractAddress = sails.config.custom.contractAddressRinkeby;
+const privateKey = Buffer.from(
+  sails.config.custom.privateKeyRinkeby,
+  'hex',
+);
+const contract = new web3.eth.Contract(contractABI, contractAddress);
+
+module.exports = {
+  
+  verify : async function (req, res){  
+	  	sails.log("Verify("+req.params.ots+", "+req.params.file_hash+")");
+	  	const file_hash = req.params.file_hash;
+	  	const base64_ots = req.params.ots;	  	
+
+	  	// Transformo datos
+	  	const aux_ots = base64.decode(base64_ots.toString(), 'base64');
+	  	var array_ots = aux_ots.split('-');
+	  	
+	  	// OTS definitivo  	
+	  	var permanent_ots;
+
+		if(array_ots.length != 2){
+	  		return res.json('El OTS enviado es inválido');
+	  	}
+	  	
+	  	const ots = array_ots[0]; // Este es el  OpenTimeStamp (OTS) original creado en el método stamp() con el helper getOts(); Es un ID único para cada request.
+	  	const tx_hash = array_ots[1]; // Hash de la TX obtenida de la blockchain
+
+	  	// Antes de verificar el contenido del OTS y el HASH
+	  	// Verifico el estado de la transacción
+		var tx = await web3.eth.getTransaction(tx_hash, async (err, _tx) => {
+	  		if(err){
+				return res.json(err.toString());
+			}
+			
+			// Significa que la TX aún no se incluye en un bloque.
+			if(!_tx.blockNumber){
+				return res.json({
+					status : 'pending',
+					tx_hash : tx_hash,					
+					file_hash : file_hash,
+					ots : ots,
+					msg : 'La Transacción aún no es incluida en un Bloque. Intente nuevamente en unos minutos.'
+				});			
+			}
+
+			// Verifico si el OTS + File_Hash enviado son válidos
+			const result_verify = await sails.helpers.verifyHash(ots, file_hash, url, accountAddress, contractABI, contractAddress, privateKey);
+
+			
+			if(result_verify){
+
+				const block_number = await sails.helpers.getBlockNumber(ots, url, contractABI, contractAddress);
+
+				// Tengo que obtener el bloque entero, para sacar su timestamp
+				const block = await sails.helpers.getBlock(block_number, url);
+				
+				return res.json({
+					status : 'success',
+					tx_hash : tx_hash,
+					block_number : block_number,
+					file_hash : file_hash,
+					ots : ots,
+					contract_address: contractAddress,
+					timestamp : block.timestamp,
+					block_hash : block.hash
+				});
+			} else {
+							
+				var file_hash_by_ots = await sails.helpers.getHash(ots, accountAddress, contractAddress);
+				
+				return res.json({
+					status : 'fail',
+					file_hash_by_ots : file_hash_by_ots,
+					file_hash_send : file_hash,
+					tx_hash : tx_hash,					
+					ots : ots,
+					msg : 'El HASH del archivo enviado no se corresponde con el OTS.'
+				});	 
+				
+				
+			}
+			
+	  	});
+  	
+  },
+
+  stamp : async function (req, res){
+  		sails.log("Stamp("+req.body.file_hash+")");
+	  	const file_hash = req.body.file_hash;
+	  	// A partir del Hash recibido, genero el OpenTimeStamp (OTS)
+	  	const ots = await sails.helpers.getOts(file_hash, accountAddress, contractAddress);
+	  	var comprobante_ots;
+
+	  	web3.eth.getTransactionCount(accountAddress, (err, txCount) => {
+
+			const data = contract.methods.stamp(ots, file_hash).encodeABI();
+
+			// Construir la transaccion
+			const txObject = {
+				nonce: web3.utils.toHex(txCount),
+				to: contractAddress,		
+				gasLimit: web3.utils.toHex(800000),
+				// TODO: revisar que el precio sea automático
+				gasPrice: web3.utils.toHex(web3.utils.toWei('1000', 'gwei')),
+				data: data
+			}
+
+			// Firmar la transaccion
+			const tx = new Tx(txObject);
+			tx.sign(privateKey);
+
+			const serializeTransaction = tx.serialize();
+			const raw = '0x' + serializeTransaction.toString('hex');
+
+			// Transmitir la transacción
+			web3.eth.sendSignedTransaction(raw, (err, tx_hash) => {
+				
+				if(err){					
+					return res.json(err.toString());
+				}
+
+				comprobante_ots = ots + '-' + tx_hash;
+
+				// Si está todo bien, retorno el OpenTimeStamp definitivo para luego comprobar si el hash del archivo junto con este comprobante son válidos
+				comprobante_ots = base64.encode(comprobante_ots.toString(), 'base64');
+
+				return res.json({
+					comprobante_ots : comprobante_ots,
+					tx_hash : tx_hash
+				});
+			});
+		});
+	  
+  },
+
+  createAccount : async function (req, res){
+  	sails.log("createAccount()");
+  	var account_data = web3.eth.accounts.create();
+  	return res.json(account_data);
+  },
+
+  getBalance : async function (req, res){
+  	var account = req.params.account;
+
+  	web3.eth.getBalance(account, (err, bal) => {
+  		if(err){
+  			return res.json(err.toString());
+  		}
+  		var balanceToEther = web3.utils.fromWei(bal, 'ether')
+  		return res.json(balanceToEther);
+  		
+  	});
+  }
+};
+
diff --git a/api/controllers/TransactionController.js b/api/controllers/TransactionController.js
index 8a3afb3..b39f55f 100755
--- a/api/controllers/TransactionController.js
+++ b/api/controllers/TransactionController.js
@@ -7,16 +7,16 @@
 
  const Web3 = require('web3');
  const Tx = require('ethereumjs-tx');
- const url = sails.config.custom.urlRpc;
+ const url = sails.config.custom.urlRpcRopsten;
  const web3 = new Web3(url);
- const accountAddress = sails.config.custom.accountAddress;
- const contractABI = sails.config.custom.contractABI;
- const contractAddress = sails.config.custom.contractAddress;
- const privateKey = Buffer.from(
-  sails.config.custom.privateKey,
+ const accountAddressRopsten = sails.config.custom.accountAddressRopsten;
+ const contractABIRopsten = sails.config.custom.contractABIRopsten;
+ const contractAddressRopsten = sails.config.custom.contractAddressRopsten;
+ const privateKeyRopsten = Buffer.from(
+  sails.config.custom.privateKeyRopsten,
   'hex',
   );
- const contract = new web3.eth.Contract(contractABI, contractAddress);
+ const contract = new web3.eth.Contract(contractABIRopsten, contractAddressRopsten);
 
  module.exports = {
 
diff --git a/api/helpers/get-block-number.js b/api/helpers/get-block-number.js
index 8d37e2f..331bed4 100755
--- a/api/helpers/get-block-number.js
+++ b/api/helpers/get-block-number.js
@@ -1,9 +1,4 @@
 const Web3 = require('web3');
-const url = sails.config.custom.urlRpc;
-const web3 = new Web3(url);
-const contractABI = sails.config.custom.contractABI;
-const contractAddress = sails.config.custom.contractAddress;
-const contract = new web3.eth.Contract(contractABI, contractAddress);
 
 module.exports = {
 
@@ -19,6 +14,18 @@ module.exports = {
       type: 'string',
       require: true,
     },
+    url : {
+      type : 'string',
+      require : true,
+    },    
+    contractABI : {
+      type : 'ref',
+      require : true,
+    },
+    contractAddress : {
+      type : 'string',
+      require : true,
+    },
   },
 
 
@@ -32,6 +39,11 @@ module.exports = {
 
 
   fn: async function (inputs) {
+    const url = inputs.url;
+    const web3 = new Web3(url);    
+    const contractABI = inputs.contractABI;
+    const contractAddress = inputs.contractAddress;    
+    const contract = new web3.eth.Contract(contractABI, contractAddress);
     
     var result = await contract.methods.getBlockNumber(inputs.ots).call((err, result) => {
       if(err){
diff --git a/api/helpers/get-block.js b/api/helpers/get-block.js
index b821ed4..8126740 100755
--- a/api/helpers/get-block.js
+++ b/api/helpers/get-block.js
@@ -1,6 +1,4 @@
 const Web3 = require('web3');
-const url = sails.config.custom.urlRpc;
-const web3 = new Web3(url);
 
 module.exports = {
 
@@ -16,6 +14,10 @@ module.exports = {
       type: 'number',
       require: true,
     },
+    url : {
+      type : 'string',
+      require : true,
+    },
   },
 
 
@@ -30,6 +32,9 @@ module.exports = {
 
   fn: async function (inputs) {
 
+    const url = inputs.url;
+    const web3 = new Web3(url);
+
     var result = await web3.eth.getBlock(inputs.block_number, (err, result) => {
       if(err){
         return err.toString();
diff --git a/api/helpers/get-hash.js b/api/helpers/get-hash.js
index 608ac4b..4dfe9e9 100755
--- a/api/helpers/get-hash.js
+++ b/api/helpers/get-hash.js
@@ -1,9 +1,4 @@
 const Web3 = require('web3');
-const url = sails.config.custom.urlRpc;
-const web3 = new Web3(url);
-const contractABI = sails.config.custom.contractABI;
-const contractAddress = sails.config.custom.contractAddress;
-const contract = new web3.eth.Contract(contractABI, contractAddress);
 
 module.exports = {
 
@@ -19,6 +14,18 @@ module.exports = {
       type: 'string',
       require: true,
     },
+    url : {
+      type : 'string',
+      require : true,
+    },    
+    contractABI : {
+      type : 'ref',
+      require : true,
+    },
+    contractAddress : {
+      type : 'string',
+      require : true,
+    },
   },
 
 
@@ -32,6 +39,11 @@ module.exports = {
 
 
   fn: async function (inputs) {
+    const url = inputs.url;
+    const web3 = new Web3(url);    
+    const contractABI = inputs.contractABI;
+    const contractAddress = inputs.contractAddress;    
+    const contract = new web3.eth.Contract(contractABI, contractAddress);
 
     var result = await contract.methods.getHash(inputs.ots).call((err, result) => {
       if(err){
diff --git a/api/helpers/get-ots.js b/api/helpers/get-ots.js
index 871790e..0dbab58 100755
--- a/api/helpers/get-ots.js
+++ b/api/helpers/get-ots.js
@@ -13,7 +13,15 @@ module.exports = {
     file_hash : {
       type : 'string',
       required : true
-    }
+    },
+    accountAddress : {
+      type : 'string',
+      require : true,
+    },
+    contractAddress : {
+      type : 'string',
+      require : true,
+    },
   },
 
 
@@ -30,8 +38,8 @@ module.exports = {
 
     var ots;
     const file_hash = inputs.file_hash;
-    const accountAddress = sails.config.custom.accountAddress;
-    const contractAddress = sails.config.custom.contractAddress;
+    const accountAddress = inputs.accountAddress;
+    const contractAddress = inputs.contractAddress;
     const now = new Date();
     const timeStamp = now.getTime();
     
diff --git a/api/helpers/verify-hash.js b/api/helpers/verify-hash.js
index e2c4e9f..04ba27f 100755
--- a/api/helpers/verify-hash.js
+++ b/api/helpers/verify-hash.js
@@ -1,15 +1,4 @@
 const Web3 = require('web3');
-const Tx = require('ethereumjs-tx');
-const url = sails.config.custom.urlRpc;
-const web3 = new Web3(url);
-const accountAddress = sails.config.custom.accountAddress;
-const contractABI = sails.config.custom.contractABI;
-const contractAddress = sails.config.custom.contractAddress;
-const privateKey = Buffer.from(
-  sails.config.custom.privateKey,
-  'hex',
-);
-const contract = new web3.eth.Contract(contractABI, contractAddress);
 
 module.exports = {
 
@@ -29,7 +18,27 @@ module.exports = {
     file_hash : {
       type : 'string',
       require : true
-    }
+    },
+    url : {
+      type : 'string',
+      require : true,
+    },
+    accountAddress : {
+      type : 'string',
+      require : true,
+    },
+    contractABI : {
+      type : 'ref',
+      require : true,
+    },
+    contractAddress : {
+      type : 'string',
+      require : true,
+    },
+    privateKey : {
+      type : 'ref',
+      require : true,
+    },
   },
 
 
@@ -43,6 +52,16 @@ module.exports = {
 
 
   fn: async function (inputs) {
+    const url = inputs.url;
+    const web3 = new Web3(url);
+    const accountAddress = inputs.accountAddress;
+    const contractABI = inputs.contractABI;
+    const contractAddress = inputs.contractAddress;
+    const privateKey = Buffer.from(
+      inputs.privateKey,
+      'hex',
+    );
+    const contract = new web3.eth.Contract(contractABI, contractAddress);
     
     var result = await contract.methods.verify(inputs.ots,inputs.file_hash).call({from: accountAddress}, (err, result) => {
       if(err){
diff --git a/api/models/Bfa.js b/api/models/Bfa.js
new file mode 100755
index 0000000..2ddc953
--- /dev/null
+++ b/api/models/Bfa.js
@@ -0,0 +1,29 @@
+/**
+ * Bfa.js
+ *
+ * @description :: A model definition represents a database table/collection.
+ * @docs        :: https://sailsjs.com/docs/concepts/models-and-orm/models
+ */
+
+module.exports = {
+
+  attributes: {
+
+    //  ╔═╗╦═╗╦╔╦╗╦╔╦╗╦╦  ╦╔═╗╔═╗
+    //  ╠═╝╠╦╝║║║║║ ║ ║╚╗╔╝║╣ ╚═╗
+    //  ╩  ╩╚═╩╩ ╩╩ ╩ ╩ ╚╝ ╚═╝╚═╝
+
+
+    //  ╔═╗╔╦╗╔╗ ╔═╗╔╦╗╔═╗
+    //  ║╣ ║║║╠╩╗║╣  ║║╚═╗
+    //  ╚═╝╩ ╩╚═╝╚═╝═╩╝╚═╝
+
+
+    //  ╔═╗╔═╗╔═╗╔═╗╔═╗╦╔═╗╔╦╗╦╔═╗╔╗╔╔═╗
+    //  ╠═╣╚═╗╚═╗║ ║║  ║╠═╣ ║ ║║ ║║║║╚═╗
+    //  ╩ ╩╚═╝╚═╝╚═╝╚═╝╩╩ ╩ ╩ ╩╚═╝╝╚╝╚═╝
+
+  },
+
+};
+
diff --git a/api/models/Rinkeby.js b/api/models/Rinkeby.js
new file mode 100755
index 0000000..b2ef54f
--- /dev/null
+++ b/api/models/Rinkeby.js
@@ -0,0 +1,29 @@
+/**
+ * Rinkeby.js
+ *
+ * @description :: A model definition represents a database table/collection.
+ * @docs        :: https://sailsjs.com/docs/concepts/models-and-orm/models
+ */
+
+module.exports = {
+
+  attributes: {
+
+    //  ╔═╗╦═╗╦╔╦╗╦╔╦╗╦╦  ╦╔═╗╔═╗
+    //  ╠═╝╠╦╝║║║║║ ║ ║╚╗╔╝║╣ ╚═╗
+    //  ╩  ╩╚═╩╩ ╩╩ ╩ ╩ ╚╝ ╚═╝╚═╝
+
+
+    //  ╔═╗╔╦╗╔╗ ╔═╗╔╦╗╔═╗
+    //  ║╣ ║║║╠╩╗║╣  ║║╚═╗
+    //  ╚═╝╩ ╩╚═╝╚═╝═╩╝╚═╝
+
+
+    //  ╔═╗╔═╗╔═╗╔═╗╔═╗╦╔═╗╔╦╗╦╔═╗╔╗╔╔═╗
+    //  ╠═╣╚═╗╚═╗║ ║║  ║╠═╣ ║ ║║ ║║║║╚═╗
+    //  ╩ ╩╚═╝╚═╝╚═╝╚═╝╩╩ ╩ ╩ ╩╚═╝╝╚╝╚═╝
+
+  },
+
+};
+
diff --git a/config/custom.js b/config/custom.js
index d168a0e..f494b67 100755
--- a/config/custom.js
+++ b/config/custom.js
@@ -21,19 +21,26 @@ module.exports.custom = {
   // …
 
   //Datos para Ropsten 
-  urlRpc: 'https://ropsten.infura.io/v3/a59f70f1e62e4db4babb69284e37672f',
-  accountAddress : '0x59060CF376DeB6729da45C729EbecC171C2c16b9',
-  contractABI : [{"constant":true,"inputs":[{"name":"ots","type":"string"}],"name":"getHash","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"ots","type":"string"}],"name":"getBlockNumber","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"ots","type":"string"},{"name":"file_hash","type":"string"}],"name":"verify","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"selfDestroy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"ots","type":"string"},{"name":"file_hash","type":"string"}],"name":"stamp","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"hash","type":"string"},{"indexed":true,"name":"ots","type":"string"}],"name":"Stamped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"}],"name":"Deploy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"}],"name":"SelfDestroy","type":"event"}],
-  contractAddress: '0x96a716f91da961639f685100b12d13ef30ba89dc',
-  privateKey: 'D51E9F04E45381E1CC3C450CB296E73BBD0BDFCA7EE22FF2533D71631B9F536C',  
+  urlRpcRopsten: 'https://ropsten.infura.io/v3/a59f70f1e62e4db4babb69284e37672f',
+  accountAddressRopsten : '0x59060CF376DeB6729da45C729EbecC171C2c16b9',
+  contractABIRopsten : [{"constant":true,"inputs":[{"name":"ots","type":"string"}],"name":"getHash","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"ots","type":"string"}],"name":"getBlockNumber","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"ots","type":"string"},{"name":"file_hash","type":"string"}],"name":"verify","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"selfDestroy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"ots","type":"string"},{"name":"file_hash","type":"string"}],"name":"stamp","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"hash","type":"string"},{"indexed":true,"name":"ots","type":"string"}],"name":"Stamped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"}],"name":"Deploy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"}],"name":"SelfDestroy","type":"event"}],
+  contractAddressRopsten: '0x96a716f91da961639f685100b12d13ef30ba89dc',
+  privateKeyRopsten: 'D51E9F04E45381E1CC3C450CB296E73BBD0BDFCA7EE22FF2533D71631B9F536C',  
   
 
+  //Datos para Rinkeby
+  urlRpcRinkeby: 'https://rinkeby.infura.io/v3/8ac5540878e1481b81c84362c03b8d49',
+  accountAddressRinkeby : '0xFA2BE13EcF2774e574Dfb640b3510ffe2Fe0C131',
+  contractABIRinkeby : [{"constant":true,"inputs":[{"name":"ots","type":"string"}],"name":"getHash","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"ots","type":"string"}],"name":"getBlockNumber","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"ots","type":"string"},{"name":"file_hash","type":"string"}],"name":"verify","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"selfDestroy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"ots","type":"string"},{"name":"file_hash","type":"string"}],"name":"stamp","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"hash","type":"string"},{"indexed":true,"name":"ots","type":"string"}],"name":"Stamped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"}],"name":"Deploy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"}],"name":"SelfDestroy","type":"event"}],
+  contractAddressRinkeby: '0xffD8331172E17227B553F91eA98142d9a5739bb8',
+  privateKeyRinkeby: 'cea30502b47213f5076ea716c9dc3df078056439b9498b9904f2183cabedf3fd',
+
 
   /* Datos para localhost
-  urlRpc: 'http://localhost:8545',
-  accountAddress : '0xDBF0C927F9E92dFE7C31e045e0Ba1067Ee205f73',
-  contractABI : [{"constant":true,"inputs":[{"name":"ots","type":"string"}],"name":"getHash","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"ots","type":"string"}],"name":"getBlockNumber","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"ots","type":"string"},{"name":"file_hash","type":"string"}],"name":"verify","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"selfDestroy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"ots","type":"string"},{"name":"file_hash","type":"string"}],"name":"stamp","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"accountAddress"},{"indexed":true,"name":"hash","type":"string"},{"indexed":true,"name":"ots","type":"string"}],"name":"Stamped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"accountAddress"}],"name":"Deploy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"accountAddress"}],"name":"SelfDestroy","type":"event"}],
-  contractAddress: '0xBD89a34041190439d43ec391486819eF5CBfBDBe',
-  privateKey: '6671485e4250881473c639465464148b5a0285461f136b585623333f22f7ca3f', 
+  urlRpc_: 'http://localhost:8545',
+  accountAddress_ : '0xDBF0C927F9E92dFE7C31e045e0Ba1067Ee205f73',
+  contractABI_ : [{"constant":true,"inputs":[{"name":"ots","type":"string"}],"name":"getHash","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"ots","type":"string"}],"name":"getBlockNumber","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"ots","type":"string"},{"name":"file_hash","type":"string"}],"name":"verify","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"selfDestroy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"ots","type":"string"},{"name":"file_hash","type":"string"}],"name":"stamp","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"accountAddress"},{"indexed":true,"name":"hash","type":"string"},{"indexed":true,"name":"ots","type":"string"}],"name":"Stamped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"accountAddress"}],"name":"Deploy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"accountAddress"}],"name":"SelfDestroy","type":"event"}],
+  contractAddress_ : '0xBD89a34041190439d43ec391486819eF5CBfBDBe',
+  privateKey_ : '6671485e4250881473c639465464148b5a0285461f136b585623333f22f7ca3f', 
   */
 };
diff --git a/config/routes.js b/config/routes.js
index 5fb752e..be87ce0 100755
--- a/config/routes.js
+++ b/config/routes.js
@@ -24,9 +24,14 @@ module.exports.routes = {
   'GET /account/create' : 'AccountController.create',
   'GET /account/get_balance/:account' : 'AccountController.getBalance',
 
+  'GET /rinkeby/verify/:ots/:file_hash' : 'RinkebyController.verify',
+  'GET /rinkeby/createAccount' : 'RinkebyController.createAccount',
+  'GET /rinkeby/get_balance/:account' : 'RinkebyController.getBalance',
+
 
   'POST /transaction/send' : 'TransactionController.send',
   'POST /blockchain/stamp' : 'BlockchainController.stamp',
+  'POST /rinkeby/stamp' : 'RinkebyController.stamp',
 
 
   /***************************************************************************
-- 
GitLab