Solidity Una introduccin y ejemplos de algunos contratos

  • Slides: 65
Download presentation
Solidity Una introducción y ejemplos de algunos contratos Francisco Moreno

Solidity Una introducción y ejemplos de algunos contratos Francisco Moreno

Introducción • Solidity es un lenguaje de programación para la gestión de smart contracts.

Introducción • Solidity es un lenguaje de programación para la gestión de smart contracts. • Un smart contract es código que se ejecuta en una plataforma blockchain. • Está enfocado a la máquina virtual de Ethereum (EVM) • Un programa de Solidity se puede ejecutar en línea en el sitio: http: //remix. ethereum. org

Ejemplo 1 a: Contrato con los métodos get y set típicos de una clase

Ejemplo 1 a: Contrato con los métodos get y set típicos de una clase de la programación orientada a objetos. • El contrato, llamado Simple. Storage tiene un valor llamado mi. Valor • El contrato tiene tres funciones (métodos): • constructor: se inicia mi. Valor en 100 • get: permite leer el valor de mi. Valor • set: permite modificar el valor de mi. Valor Levemente modificado a partir de: https: //docs. soliditylang. org/en/v 0. 4. 21/introduction-to-smartcontracts. html

pragma solidity ^0. 4. 0; Versión de Solidity a usar contract Simple. Storage {

pragma solidity ^0. 4. 0; Versión de Solidity a usar contract Simple. Storage { //Declaración de variable uint mi. Valor; // Función constructor() public {mi. Valor = 100; } //Función set view: indica que la función function set(uint x) public {mi. Valor = x; } no modifica los datos del contrato //Función get function get() public view returns (uint) {return mi. Valor; } }

 • Brevemente sobre la visibilidad: - public: all - private: only this contract

• Brevemente sobre la visibilidad: - public: all - private: only this contract - internal: only this contract and contracts deriving from it - external: Cannot be accessed internally, only externally

Ejemplo 1 b: Ejemplo con un arreglo de estructuras. pragma solidity ^0. 4. 0;

Ejemplo 1 b: Ejemplo con un arreglo de estructuras. pragma solidity ^0. 4. 0; contract miarreglo { //Declaración de una estructura struct persona { uint cc; string nombre; } //Declaración del arreglo de estructuras persona[] public estudiantes; uint 256 public totalest;

function inserta(uint ced, string memory nom) public { estudiantes. push(persona(ced, nom)); memory: used to

function inserta(uint ced, string memory nom) public { estudiantes. push(persona(ced, nom)); memory: used to hold totalest +=1; temporary values. It is cheaper to use. . . } “constructor” de la } struct Nota: En remix para consultar una posición del arreglo poner el índice (desde 0)

Ejemplo 2: Un “acuñador” de moneda. Contrato Coin • En este ejemplo, una persona

Ejemplo 2: Un “acuñador” de moneda. Contrato Coin • En este ejemplo, una persona (el “minter”, acuñador), que es la dueña del contrato, puede acuñar dinero y enviarlo a otros usuarios. Esto lo puede hacer mediante la función mint. • El dinero (“amount”) que el minter envía a un receptor (“receiver”) mediante mint, queda almacenado en una estructura de datos de tipo mapping (es como un arreglo cuyo índice es la dirección del receptor y el contenido es el balance) llamada balances. • En la función mint se controla que solamente el minter puede hacer lo anterior (en el Ejemplo 3, este tipo de situaciones se controla con un modifier). Levemente modificado a partir de: https: //docs. soliditylang. org/en/v 0. 4. 21/introduction-to-smartcontracts. html

 • Mediante la función send, un usuario (el “sender”) puede enviar dinero a

• Mediante la función send, un usuario (el “sender”) puede enviar dinero a otro usuario (el “receiver”). La función: - Valida que el sender tenga suficiente saldo para enviar la cantidad que pretende enviar. - Si tiene suficiente saldo (balance), decrementa su saldo en la cantidad enviada y aumenta el saldo en la misma cantidad del otro usuario - Note que esta función permite que el sender sea igual que el receiver, esto se podría controlar o dejar que ocurra. . .

pragma solidity ^0. 4. 21; contract Coin { //Variable para guardar la dirección del

pragma solidity ^0. 4. 21; contract Coin { //Variable para guardar la dirección del minter address public minter; //mapping para guardar los saldos de cada dirección (usuario) mapping (address => uint) public balances; // Evento, se emiten con emit. //Queda grabado (log) en la transacción que lo emite, ver función send event Sent(address from, address to, uint amount); El contrato continua en la siguiente diapositiva

// Constructor: se inicializa la variable minter con la dirección del // creador del

// Constructor: se inicializa la variable minter con la dirección del // creador del contrato (msg. sender) constructor() public { minter = msg. sender; } //Función mint function mint(address receiver, uint amount) public { //Se controla que el invocador de la función sea el minter if (msg. sender != minter) return; balances[receiver] += amount; } El contrato continua en la siguiente diapositiva

El invocador de la función es el sender //Función send function send(address receiver, uint

El invocador de la función es el sender //Función send function send(address receiver, uint amount) public { //Se verifica que el sender tenga suficiente dinero if (balances[msg. sender] < amount) return; balances[msg. sender] -= amount; //Decrementa saldo del sender balances[receiver] += amount; //Aumenta saldo del receiver emit Sent(msg. sender, receiver, amount); //Genera evento } } Acá termina el contrato

msg, block, tx: variables globales del entorno. Por ejemplo: • msg. sender (address): sender

msg, block, tx: variables globales del entorno. Por ejemplo: • msg. sender (address): sender of the message (current call). • msg. value (uint): number of wei sent with the message. • block. gaslimit (uint): current block gaslimit. • block. number (uint): current block number. • block. timestamp (uint): current block timestamp as seconds since unix epoch. • tx. gasprice (uint): gas price of the transaction. entre otras. . . Nota: tomado de la documentación oficial de Solidity.

Ejemplo 3: Contrato dueño (“Owner”) • En este ejemplo, un usuario crea un contrato

Ejemplo 3: Contrato dueño (“Owner”) • En este ejemplo, un usuario crea un contrato llamado Owner. • El creador del contrato queda establecido como el dueño (del contrato). • El contrato incluye una función llamada change. Owner que permite cambiar el dueño del contrato. La función verifica mediante un modificador (“modifier”) que el invocador de esta función sea el dueño actual. • Finalmente, el contrato incluye una función get. Owner que permite consultar el dueño actual. Levemente modificado a partir de: http: //remix. ethereum. org

Comentario sobre licencia, evita warning a partir de ^0. 6. 8 // SPDX-License-Identifier: GPL-3.

Comentario sobre licencia, evita warning a partir de ^0. 6. 8 // SPDX-License-Identifier: GPL-3. 0 pragma solidity >=0. 7. 0 <0. 8. 0; contract Owner { address private owner; event Owner. Set(address old. Owner, address new. Owner); //modifier: para verificar que el invocador sea el dueño actual modifier is. Owner() { require(msg. sender == owner, "Caller is not owner"); _; //Indica que se continua la función (si require fue true) //Si require fue false, se genera error, se revierte la transacción } El contrato continua en la siguiente diapositiva

constructor() { owner = msg. sender; // El creador del contrato es el primer

constructor() { owner = msg. sender; // El creador del contrato es el primer dueño //Generar evento: como es la primera vez, no hay dueño viejo // (old. Owner), para ello se usa la dirección address(0) emit Owner. Set(address(0), owner); Modificador } //Función para cambiar de dueño function change. Owner(address new. Owner) public is. Owner { emit Owner. Set(owner, new. Owner); owner = new. Owner; //Se establece el nuevo dueño } El contrato continua en la siguiente diapositiva

//Función para consultar el dueño actual function get. Owner() external view returns (address) {

//Función para consultar el dueño actual function get. Owner() external view returns (address) { return owner; } } Acá termina el contrato

Ejemplo 4: Contrato de votación • En este ejemplo se simula un sistema de

Ejemplo 4: Contrato de votación • En este ejemplo se simula un sistema de votación. • Una persona (el presidente, dueño de la votación) crea la votación con su nombre (del presidente) y con la propuesta (texto de la propuesta). • La votación queda entonces en el estado de Created (creada). • Cuando la votación está en estado Created, los usuarios se pueden registrar para la votación mediante la función add. Voter (todavía no han votado, solo se están registrando). Un usuario se registra con su dirección y nombre. Solo el presidente puede registrar votantes. Levemente modificado a partir de: https: //medium. com/coinmonks/voting-on-a-blockchain-soliditycontract-codes-explained-c 677996 d 94 f 2

 • En algún momento, mediante la función start. Vote, el presidente indica que

• En algún momento, mediante la función start. Vote, el presidente indica que la votación entra en un estado = Voting, es decir, a partir de ese momento: • Los votantes registrados pueden emitir su voto. • No se pueden registrar más votantes. • El voto emitido por un votante, mediante la función do. Vote, es simplemente true o false (voto a favor o en contra de la propuesta). • En algún momento, mediante la función end. Vote, el presidente indica que la votación finaliza (estado = Ended) y se entregan los resultados de la votación (ver el valor de la variable final. Result).

Elementos del contrato: variables, eventos, modificadores y funciones 1. Estructura de un voto struct

Elementos del contrato: variables, eventos, modificadores y funciones 1. Estructura de un voto struct vote{ address voter. Address; //Dirección del votante bool choice; //Voto: Falso o Verdadero }

2. Estructura de un votante struct voter{ string voter. Name; //Nombre del votante bool

2. Estructura de un votante struct voter{ string voter. Name; //Nombre del votante bool voted; //Indica si ya ha votado o no }

3. Mappings //Mapping para almacenar los votos; es una variable privada //Note que en

3. Mappings //Mapping para almacenar los votos; es una variable privada //Note que en cada posición se guarda un objeto de tipo vote mapping(uint => vote) private votes; //Mapping para almacenar los votantes (los “voters”) //Note que en cada posición se guarda un objeto de tipo voter mapping(address => voter) public voter. Register;

4. Otras variables //Número total de votos que (hasta el momento) han sido true.

4. Otras variables //Número total de votos que (hasta el momento) han sido true. //Note que es una variable privada uint private count. Result = 0; //Número total (definitivo) de votos que fueron true. Es igual al valor de count. Result cuando las votaciones se cierran uint public final. Result = 0;

//Número total de votantes registrados en el mapping de voters //(voter. Register) uint public

//Número total de votantes registrados en el mapping de voters //(voter. Register) uint public total. Voter = 0; //Número total de votos (hasta el momento) ya sean true o false. uint public total. Vote = 0;

//Dirección del presidente (chairman) de la votación. address public ballot. Official. Address; //Nombre del

//Dirección del presidente (chairman) de la votación. address public ballot. Official. Address; //Nombre del presidente (chairman) de la votación. string public ballot. Official. Name; //Texto de la propuesta que se va someter a votación. string public proposal;

//Declaración de enumeración con los estados válidos de la votación. enum State { Created,

//Declaración de enumeración con los estados válidos de la votación. enum State { Created, Voting, Ended } State public state; Se corresponden con los valores 0, 1 y 2 así: 0 = Created 1 = Voting 2 = Ended

5. Eventos event voter. Added(address voter); //Indica que se agregó un votante event vote.

5. Eventos event voter. Added(address voter); //Indica que se agregó un votante event vote. Started(); //Indica que la votación comenzó (estado = Voting) event vote. Ended(uint final. Result); //Indica que la votación finalizó //(estado = Ended) event vote. Done(address voter); //Indica que el votante votó

6. Modificadores modifier only. Official() { //Verifica que el invocador sea el presidente require(msg.

6. Modificadores modifier only. Official() { //Verifica que el invocador sea el presidente require(msg. sender ==ballot. Official. Address); _; } modifier in. State(State _state) { //Verifica un estado require(state == _state); _; }

En remix. ethereum. org al momento de hacer el deploy, poner al frente los

En remix. ethereum. org al momento de hacer el deploy, poner al frente los valores para los parámetros: nombre y propuesta 7. Constructor: se crea la votación. constructor( //Parámetros: nombre del presidente y texto de la propuesta string memory _ballot. Official. Name, string memory _proposal) public { ballot. Official. Address = msg. sender; //Dirección del invocador ballot. Official. Name = _ballot. Official. Name; proposal = _proposal; state = State. Created; //Se pone el estado de votación en Created }

8. Función para registrar votantes en el mapping voter. Register function add. Voter(address _voter.

8. Función para registrar votantes en el mapping voter. Register function add. Voter(address _voter. Address, string memory _voter. Name) public in. State(State. Created) //Requisito: el estado de la votación debe ser Created only. Official //Requisito: solo el presidente puede registrar votantes { Tener cuidado al invocar voter memory v; //Variable de tipo voter esta función, debe ser v. voter. Name = _voter. Name; //Nombre del votante invocada con la dirección del presidente v. voted = false; //Se indica que no ha votado voter. Register[_voter. Address] = v; //Se lleva el votante al mapping total. Voter++; //Se aumenta el número de votantes registrados emit voter. Added(_voter. Address); //Se emite este evento (votante agregado) }

Tener cuidado al invocar esta función, debe ser invocada con la dirección del presidente

Tener cuidado al invocar esta función, debe ser invocada con la dirección del presidente 9. Función para comenzar la votación function start. Vote() public in. State(State. Created) //Requisito: el estado de la votación debe ser Created only. Official //Requisito: solo el presidente puede iniciar la votación { state = State. Voting; //Se pone el estado de votación en Voting emit vote. Started(); //Se emite este evento (la votación comenzó) }

10. Función mediante la cual un votante vota function do. Vote(bool _choice) public in.

10. Función mediante la cual un votante vota function do. Vote(bool _choice) public in. State(State. Voting) //Requisito: el estado de la votación debe ser Voting returns (bool voted) //Retorno de la función: true indica que //el votante estaba inscrito y que no había votado { bool found = false; La función continua en la siguiente diapositiva

Dirección del votante (invocador) Verifica que el votante esté inscrito: tamaño del nombre no

Dirección del votante (invocador) Verifica que el votante esté inscrito: tamaño del nombre no es 0 if (bytes(voter. Register[msg. sender]. voter. Name). length != 0 && !voter. Register[msg. sender]. voted){ voter. Register[msg. sender]. voted = true; //Indica que el votante //acaba de votar vote memory v; //Variable de tipo vote v. voter. Address = msg. sender; //Dirección del votante v. choice = _choice; //Elección del votante (o sea, su voto) Verifica que el votante no haya votado La función continua en la siguiente diapositiva

if (_choice){ //Verifica si el voto fue true count. Result++; //Se aumenta el número

if (_choice){ //Verifica si el voto fue true count. Result++; //Se aumenta el número de votos que han sido true } votes[total. Vote] = v; //Se lleva el voto al mapping en la pos. total. Vote++; //Se aumenta el número de votos que hay hasta ahora found = true; //Indica que el votante acaba de votar } emit vote. Done(msg. sender); //Se emite este evento (el votante votó) return found; } Acá termina la función do. Vote

Tener cuidado al invocar esta función, debe ser invocada con la dirección del presidente

Tener cuidado al invocar esta función, debe ser invocada con la dirección del presidente 11. Función para finalizar la votación function end. Vote() public in. State(State. Voting) //Requisito: el estado de la votación debe ser Voting only. Official //Requisito: solo el presidente puede finalizar la votación { state = State. Ended; //Se pone el estado de votación en Ended final. Result = count. Result; //Número total (definitivo) de votos que fueron true //se copian de la vble. privada count. Result a la vble pública final. Result emit vote. Ended(final. Result); //Se emite este evento (la votación finalizó) }

 • El código completo se puede ver en: https: //github. com/jacksonng 77/ballot/blob/master/ballot. sol

• El código completo se puede ver en: https: //github. com/jacksonng 77/ballot/blob/master/ballot. sol

Ejemplo 5: Subasta • En este ejemplo se simula una subasta. • La subasta

Ejemplo 5: Subasta • En este ejemplo se simula una subasta. • La subasta se crea para un usuario (el vendedor, beneficiario) y queda abierta durante un tiempo especificado (en segundos). • Mientras la subasta esté abierta, los usuarios (ofertantes) pueden someter ofertas mediante la función bid • El contrato lleva el registro del ofertante actual más alto y el valor (variables highest. Bidder y highest. Bid) https: //docs. soliditylang. org/en/v 0. 8. 1/solidity-by-example. html

 • Si una oferta recien enviada supera a la oferta actual más alta,

• Si una oferta recien enviada supera a la oferta actual más alta, entonces al anterior ofertante cuya oferta era la más alta se le guarda su dinero (el el mapping pending. Returns) para serle devuelto mediante la función withdraw. • Luego de que el tiempo de la subasta termine, mediante la función auction. End se cierra la subasta y se le transfiere el dinero (valor de la oferta más alta) al beneficiario. Nota: para facilitar la visualización de los resultados, hacer el ejemplo seleccionando en remix ether en vez de wei.

// SPDX-License-Identifier: GPL-3. 0 pragma solidity >=0. 7. 0 <0. 9. 0; contract Simple.

// SPDX-License-Identifier: GPL-3. 0 pragma solidity >=0. 7. 0 <0. 9. 0; contract Simple. Auction { //Dirección del usuario (vendedor, beneficiario) de la subasta address payable public beneficiary; //Tiempo en que finaliza la subasta uint public auction. End. Time;

//Dirección del actual ofertante más alto address public highest. Bidder; //Valor ofertado actual más

//Dirección del actual ofertante más alto address public highest. Bidder; //Valor ofertado actual más alto uint public highest. Bid; //Mapping para devolver el dinero de los ofertantes que no ganaron, //pero que en algún momento llegaron a ser los ofertantes más altos mapping(address => uint) pending. Returns; //Bandera para indicar cuando la subasta ha terminado bool ended;

//Evento para indicar que se acaba de producir una oferta mayor event Highest. Bid.

//Evento para indicar que se acaba de producir una oferta mayor event Highest. Bid. Increased(address bidder, uint amount); //Evento para indicar que la subasta ha terminado event Auction. Ended(address winner, uint amount);

//Función constructor( //Parámetros del constructor uint _bidding. Time, //Tiempo para terminar la subasta address

//Función constructor( //Parámetros del constructor uint _bidding. Time, //Tiempo para terminar la subasta address payable _beneficiary //Dirección del vendedor ) { beneficiary = _beneficiary; //Al tiempo actual se le suma el tiempo para terminar la subasta auction. End. Time = block. timestamp + _bidding. Time; }

payable indica que la función recibe Ether (ver msg. value más adelante): the function

payable indica que la función recibe Ether (ver msg. value más adelante): the function can process transactions with non-zero Ether value. //Función para hacer una oferta function bid() public payable { //Verifica que el tiempo de la subasta no haya terminado require( block. timestamp <= auction. End. Time, "Auction already ended. " ); //Verifica que la oferta enviada sea superior a la oferta más alta actual require( msg. value > highest. Bid, "There already is a higher bid. " ); La función continua en la siguiente diapositiva

//Si la función llega acá es porque la oferta enviada es mayor que la

//Si la función llega acá es porque la oferta enviada es mayor que la actual if (highest. Bid != 0) { //Se guarda el dinero ofertado del ofertante que era el más alto pending. Returns[highest. Bidder] += highest. Bid; } //Se actualizan el nuevo ofertante más alto y su dinero ofertado highest. Bidder = msg. sender; highest. Bid = msg. value; //Se emite este evento (nueva oferta más alta) emit Highest. Bid. Increased(msg. sender, msg. value); }

//Función para que un ofertante recupere su dinero (dado que fue superado) function withdraw()

//Función para que un ofertante recupere su dinero (dado que fue superado) function withdraw() public returns (bool) { uint amount = pending. Returns[msg. sender]; if (amount > 0) { //Se verifica si tiene dinero para serle devuelto pending. Returns[msg. sender] = 0; //Se pone en cero if (!payable(msg. sender). send(amount)) { //Si no se le puede devolver, se vuelve a poner en el mapping pending. Returns[msg. sender] = amount; return false; } } return true; }

//Función para indicar que la subasta ha terminado y enviarle //el dinero al vendedor

//Función para indicar que la subasta ha terminado y enviarle //el dinero al vendedor (beneficiario) function auction. End() public { //Verifica que el tiempo ya haya terminado require(block. timestamp >= auction. End. Time, "Auction not yet ended. "); //Verifica que no haya sido cerrada ya require(!ended, "Auction. End has already been called. "); ended = true; //Indica que la subasta se ha cerrado //Se emite este evento (la subasta ha terminado) emit Auction. Ended(highest. Bidder, highest. Bid); beneficiary. transfer(highest. Bid); //Envía el dinero al beneficiario } }

Ejemplo 6: Transferir fondos a y desde un contrato • Transferir fondos (dinero) de

Ejemplo 6: Transferir fondos a y desde un contrato • Transferir fondos (dinero) de cuentas hacia el contrato. • Transferir fondos del contrato hacia la cuenta del dueño del contrato. • Payable permite recibir Ether: Código implícito: address(this). balance += msg. value this se refiere al contrato • Mediante address(this). balance se puede obtener el balance del contrato. Gráficamente: Ejemplo tomado y levemente modificado a partir de: A hands-on tutorial: Working with Smart Contracts in Ethereum. Mohammad H. Tabatabaei et al. https: //blockchain-conf. github. io/files/blockchain-hands-on-Tutorial. pdf

Tomado de: A hands-on tutorial: Working with Smart Contracts in Ethereum. Mohammad H. Tabatabaei

Tomado de: A hands-on tutorial: Working with Smart Contracts in Ethereum. Mohammad H. Tabatabaei et al.

pragma solidity ^0. 5. 0; contract financial. Contract{ address owner; //Función constructor() public {

pragma solidity ^0. 5. 0; contract financial. Contract{ address owner; //Función constructor() public { owner = msg. sender; //Se guarda la dirección del creador del contrato } //Modificador modifier if. Owner(){ //Verifica que el invocador sea el dueño require(msg. sender ==owner); _; }

//Función que recibe Ether function receive. Deposit() payable public{ } //Función para consultar el

//Función que recibe Ether function receive. Deposit() payable public{ } //Función para consultar el balance del contrato function get. Balance() public view returns(uint){ return address(this). balance; } //Función para transferir Ether del contrato hacia la cuenta del dueño function withdraw(uint funds) public if. Owner{ msg. sender. transfer(funds); } }

Ejemplo 7: Compra segura remota • En este contrato se muestra el proceso de

Ejemplo 7: Compra segura remota • En este contrato se muestra el proceso de intercambio de dinero entre un comprador (buyer) y un vendedor (seller) para llevar a cabo una venta de un artículo (ítem). • En la creación del contrato (función constructor), el vendedor envía (deposita) en el contrato el doble del dinero estipulado para la venta y el contrato queda en estado Created (valor predeterminado de la enum). • Ahora, un comprador, mediante la función confirm. Purchase, envía también el doble del dinero estipulado para la venta y el contrato queda en estado Locked (bloqueado). Levemente modificado a partir de https: //docs. soliditylang. org/en/v 0. 6. 8/solidity-by-example. html

 • Así, en este momento el balance del contrato es 4 veces el

• Así, en este momento el balance del contrato es 4 veces el valor pactado para la venta. • Los dos interesados han depositado cada uno el doble del dinero pactado. • Ahora, cuando el comprador reciba el artículo, puede mediante la función confirm. Received, recuperar la mitad del dinero que él puso y además se le transfiere al vendedor el resto del dinero del contrato. El contrato queda en estado Inactive. • El contrato incluye una función abort que permite que el vendedor recupere su depósito en caso de que no “aparezca” ningún comprador. Sin esta función el vendedor no podría recuperar su depósito (se pierde el dinero).

// SPDX-License-Identifier: GPL-3. 0 pragma solidity >=0. 5. 0 <0. 7. 0; contract Purchase

// SPDX-License-Identifier: GPL-3. 0 pragma solidity >=0. 5. 0 <0. 7. 0; contract Purchase { uint public value; address payable public seller; //Dirección del Vendedor address payable public buyer; //Dirección del comprador enum State { Created, Locked, Inactive } State public state; //Variable de tipo enum, queda en estado Created

modifier condition(bool _condition) { //Verifica una condición require(_condition); _; } modifier in. State(State _state)

modifier condition(bool _condition) { //Verifica una condición require(_condition); _; } modifier in. State(State _state) { //Verifica un estado require(state == _state, "Invalid state. "); _; }

modifier only. Buyer() { //Verifica que sea el comprador require(msg. sender == buyer, "Only

modifier only. Buyer() { //Verifica que sea el comprador require(msg. sender == buyer, "Only buyer can call this. "); _; } modifier only. Seller() { //Verifica que sea el vendedor require(msg. sender == seller, "Only seller can call this. " ); _; }

event Aborted(); event Purchase. Confirmed(); event Item. Received(); constructor() public payable { seller =

event Aborted(); event Purchase. Confirmed(); event Item. Received(); constructor() public payable { seller = msg. sender; //Establece el vendedor (creador del contrato) value = msg. value / 2; //Value queda con la mitad del dinero enviado //Verifica que la cantidad enviada por el vendedor sea par require((2 * value) == msg. value, "Value has to be even. "); }

Pero siempre y cuando no haya ya un comprador, ver siguiente función function abort()

Pero siempre y cuando no haya ya un comprador, ver siguiente función function abort() public only. Seller //Solo el vendedor puede abortar la compra in. State(State. Created) //El contrato debe estar creado { emit Aborted(); //Se emite evento (venta abortada) state = State. Inactive; //El contrato queda en estado Inactivo //El vendedor recupera el dinero depositado seller. transfer(address(this). balance); }

function confirm. Purchase() public in. State(State. Created) //El contrato debe estar creado //Verifica que

function confirm. Purchase() public in. State(State. Created) //El contrato debe estar creado //Verifica que el valor enviado por el comprador sea igual al del vendedor condition(msg. value == (2 * value)) payable { emit Purchase. Confirmed(); //Se emite evento (compra confirmada) buyer = msg. sender; //Establece el comprador state = State. Locked; //El contrato queda en estado bloqueado }

function confirm. Received() public only. Buyer //Solo el comprador puede confirmar que recibió el

function confirm. Received() public only. Buyer //Solo el comprador puede confirmar que recibió el producto in. State(State. Locked) //El contrato debe estar bloqueado { emit Item. Received(); //Se emite evento (producto recibido) state = State. Inactive; //El contrato queda en estado Inactivo buyer. transfer(value); //El comprador recupera la mitad de su dinero //El vendedor recupera el dinero depositado + el valor del artículo seller. transfer(address(this). balance); } O alternativamente: 3 * value }

 • Preguntas, mejoras a estos contratos. . .

• Preguntas, mejoras a estos contratos. . .

Ejemplo sencillo de una librería pragma solidity ^0. 5. 1; library mat { function

Ejemplo sencillo de una librería pragma solidity ^0. 5. 1; library mat { function fact(uint val) internal pure returns(uint) { uint f = 1; for (uint k = 2; k <= val; k++) { f = f*k; } return f; } }

contract micalc{ uint public v; function factorial(uint _val) public { v = mat. fact(_val);

contract micalc{ uint public v; function factorial(uint _val) public { v = mat. fact(_val); } } Nota: en el momento de hacer el deploy hay que tener cuidado y hacer el deploy a micalc no a mat

 • La librería también se puede importar. Poner en un archivo, por ejemplo,

• La librería también se puede importar. Poner en un archivo, por ejemplo, llamado mat. sol la librería: pragma solidity ^0. 5. 1; library mat { function fact(uint val) internal pure returns(uint) { uint f = 1; for (uint k = 2; k <= val; k++) {f = f*k; } return f; } }

 • Y en otro archivo, por ej. , calc. sol el contrato que

• Y en otro archivo, por ej. , calc. sol el contrato que la invoca así: pragma solidity ^0. 5. 1; import ". /mat. sol"; contract micalc{ uint public v; function factorial(uint _val) public { v = mat. fact(_val); } }

Ejercicios • Hacer la función fact de forma recursiva en la librería. Nota: tenga

Ejercicios • Hacer la función fact de forma recursiva en la librería. Nota: tenga en cuenta que la recursión puede consumir mucho “gas”. • Explorar el tema de la herencia (inheritance) de contratos. • Explorar el tema de comunicación entre contratos (contratos que instancian contratos e invocan funciones de estos. . . ) y la aplicación, utilidad de este aspecto. . .