WEB3DEV

Cover image for Implementando Transações Imobiliárias com Contratos Inteligentes no Solidity
Diogo Jorge
Diogo Jorge

Posted on

Implementando Transações Imobiliárias com Contratos Inteligentes no Solidity

Image description

Gostaria de compartilhar como os contratos inteligentes podem ser implementados no ramo imobiliário, para fins de aprendizagem e diversão. Acredito que existe um potencial significativo para contratos inteligentes em transações imobiliárias. Para este caso de uso simples, desenvolvi três cenários diferentes para ilustrar as interações básicas entre o proprietário do contrato, compradores e vendedores no processo de transferência de terras. É essencial reconhecer que as implementações reais de contratos inteligentes para o setor imobiliário podem exigir considerações adicionais, medidas de segurança e interações do usuário além desses cenários simplificados. No entanto, para o escopo do nosso tutorial atual, vamos nos concentrar nos cenários básicos fornecidos.

Cenário para o Proprietário do Contrato:

  1. Implantação do contrato: O governo, como proprietário do contrato, implanta o contrato inteligente na blockchain para criar um sistema descentralizado de registro de terras.
  2. Adição de terreno: O proprietário do contrato adiciona terrenos ao contrato chamando a função addLand com a localização e o custo de cada terreno.
  3. Acordo sobre Aprovadores: O proprietário do contrato facilita o acordo entre compradores e vendedores sobre um aprovador comum para cada transferência de terreno chamando a função agreeOnApprover.

Cenário para um comprador:

  1. Encontrando um Terreno: O comprador identifica um terreno disponível para venda no contrato verificando os detalhes do terreno usando a função getLand.
  2. Concordar com um aprovador: O comprador se comunica com o vendedor e ambas as partes concordam com um aprovador comum para a transferência do terreno.
  3. Iniciando a transferência: Oo comprador chama a função activateTransfer, fornecendo o ID do terreno e o endereço do aprovador acordado como argumentos.
  4. Aprovação: O comprador aprova a transferência chamando a função aproveTransferAsBuyer.
  5. Conclusão da transferência: Sse o vendedor também aprovar a transferência chamando a função aproveTransferAsSeller, a transferência será concluída e a propriedade do terreno será transferida para o aprovador.

Cenário para um vendedor:

  1. Verificação de propriedade: O vendedor confirma a propriedade do terreno verificando o token que representa o terreno e garantindo que este pertence a ele.
  2. Concordar com um aprovador: O vendedor se comunica com o comprador e ambas as partes concordam com um aprovador comum para a transferência do terreno.
  3. Iniciando Transferência: O vendedor chama a função generateTransfer, fornecendo o ID do terreno e o endereço do aprovador acordado como argumentos.
  4. Aprovação: O vendedor então aprova a transferência chamando a função aproveTransferAsSeller.
  5. Conclusão da transferência:S se o comprador também aprovar a transferência chamando a função aproveTransferAsBuyer, a transferência será concluída e a propriedade do terreno será transferida para o aprovador.

Este é o código do contrato inteligente no Solidity que implementa os cenários descritos acima:

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract MyLandContract is ERC721Enumerable, Ownable {
   struct Land {
       string location;
       uint cost;
       uint landID;
       uint wantSell;
       address approver;
       bool buyerApproved;
       bool sellerApproved;
   }

   uint public totalLandsCounter; // número total de terras através deste contrato

   mapping (uint => Land) public lands;

   constructor() ERC721("MyContract", "LAND") {
       totalLandsCounter = 0;
   }

   //Evento de adição de terreno
   event Add(address indexed _owner, uint _landID);

   // Evento de transferência de terreno
   event Transfer(address indexed _from, address indexed _to, uint _landID);


   // Modificador para verificar se o chamador é dono de um terreno específico
   modifier isLandOwner(uint _landID) {
       require(_exists(_landID), "Land with this ID does not exist");
       require(ownerOf(_landID) == msg.sender, "Caller is not the owner of this land");
       _;
   }

   // Modificador para verificar se o chamador é o aprovador acordado para uma transferência de terreno específica
   modifier isAgreedApprover(uint _landID) {
       require(_exists(_landID), "Land with this ID does not exist");
       require(lands[_landID].approver == msg.sender, "Caller is not the agreed approver for this land transfer");
       require(lands[_landID].buyerApproved == false && lands[_landID].sellerApproved == false, "Approval already given");
       require(lands[_landID].wantSell == 1, "Land is not available for sale");
       require(lands[_landID].cost <= msg.value, "Insufficient payment");
       _;
   }

   // O proprietário deve adicionar terrenos através desta função
   function addLand(string memory _location, uint _cost) public onlyOwner {
       totalLandsCounter++;
       uint landID = totalLandsCounter;
       lands[landID] = Land({
           location: _location,
           cost: _cost,
           landID: landID,
           wantSell: 1,
           approver: address(0),
           buyerApproved: false,
           sellerApproved: false
       });

       _mint(msg.sender, landID);
       emit Add(msg.sender, landID);
   }

   // Comprador e Vendedor concordam com o aprovador antes de iniciar o processo de transferência
   function agreeOnApprover(uint _landID, address _approver) public isLandOwner(_landID) {
       require(lands[_landID].approver == address(0), "Approver already set");
       lands[_landID].approver = _approver;
   }

   //O comprador aprova a transferência
   function approveTransferAsBuyer(uint _landID) public {
       require(lands[_landID].approver == msg.sender, "Caller is not the agreed approver for this land transfer");
       require(lands[_landID].buyerApproved == false, "Transfer already approved by the buyer");
       lands[_landID].buyerApproved = true;
       checkAndCompleteTransfer(_landID);
   }

   // Vendedor aprova a transferência
   function approveTransferAsSeller(uint _landID) public isLandOwner(_landID) {
       require(lands[_landID].sellerApproved == false, "Transfer already approved by the seller");
       lands[_landID].sellerApproved = true;
       checkAndCompleteTransfer(_landID);
   }

   //Função para verificar se comprador e vendedor aprovaram a transferência
   // Se aprovado, concluia a transferência
   function checkAndCompleteTransfer(uint _landID) private {
       if (lands[_landID].buyerApproved && lands[_landID].sellerApproved) {
           _transfer(ownerOf(_landID), lands[_landID].approver, _landID);
           lands[_landID].ownerAddress = lands[_landID].approver;
           lands[_landID].wantSell = 0;
           address payable seller = payable(ownerOf(_landID));
           seller.transfer(lands[_landID].cost);
           emit Transfer(ownerOf(_landID), lands[_landID].approver, _landID);
       }
   }

   // Obtém detalhes do terreno de uma conta
   function getLand(uint _landID) public view returns (string memory, uint, address, uint, uint) {
       require(_exists(_landID), "Land with this ID does not exist");
       Land memory land = lands[_landID];
       return (land.location, land.cost, ownerOf(_landID), land.landID, land.wantSell);
   }

   //Retirar o terreno da venda
   function removeFromSale(uint _landID) public isLandOwner(_landID) {
       lands[_landID].wantSell = 0;
   }
}
Enter fullscreen mode Exit fullscreen mode

Vamos decompor o código para explicar as principais funções:

Em primeiro lugar, o contrato herda dois contratos importantes do OpenZeppelin: ERC721Enumerable e Ownable. Ao aproveitar o padrão ERC-721, o contrato permite a criação de tokens únicos e não fungíveis. Cada token serve como representação de uma parcela distinta de terreno.

A função addLand concede ao proprietário do contrato (governo) a capacidade de adicionar terras ao contrato. Esta função é definida como pública e vem com o modificador onlyOwner, que garante que somente o proprietário do contrato possa utilizá-la. Quando invocada, a função requer dois parâmetros: _location (a localização do terreno) e _cost (o custo do terreno).

Como parte do processo, totalLandsCounter é incrementado em um para gerar um landID exclusivo para o terreno recém-adicionado. Uma nova struct Land é então criada, capturando os atributos fornecidos, como localização e preço, juntamente com as configurações padrão para aprovador, buyerApproved e sellerApproved.

Em seguida, a estrutura Land recentemente formada é incluída no mapeamento das terras usando o landID como chave. Isso garante que todos os detalhes essenciais do terreno recém-adicionado sejam armazenados com segurança.

Para finalizar o processo, a função _mint do ERC721 é chamada para estabelecer um novo token ERC-721 que representa com precisão o terreno. A propriedade do token é atribuída ao proprietário do contrato (governo), e todos os detalhes pertinentes do terreno são mantidos com segurança no mapeamento do terreno. Isso permite referência futura e transferência contínua dos tokens de terreno.

Por fim, o evento Add é acionado, notificando imediatamente os ouvintes de que um novo terreno foi adicionado com sucesso ao contrato. O evento contém o endereço do proprietário do contrato (msg.sender) e o landID do terreno recentemente adicionado.

Deixe-me explicar melhor como funciona a venda e transferência de um token de terreno no contrato inteligente:

  1. Venda do terreno (acordo com um aprovador)

Digamos que um vendedor queira vender seu terreno a um comprador e ambas as partes cheguem a um acordo sobre um aprovador antes de iniciar o processo de transferência.

  • O vendedor chama a função agreeOnApprover e fornece o landID do terreno que deseja vender, juntamente com o endereço do aprovador acordado.
  • A função agreeOnApprover verifica se o chamador é o proprietário do terreno (o vendedor) e define o aprovador para aquele terreno específico.
  1. Iniciando a transferência (comprador inicia transferência)

Após concordar com o aprovador, o comprador toma a iniciativa de iniciar a transferência do terreno:

  • O comprador chama a função initiateTransfer e fornece o landID do terreno que pretende comprar, juntamente com o endereço do aprovador acordado.
  • A função initiateTransfer verifica se quem chama é o comprador e se o terreno está disponível para venda.
  • A função atualiza o sinalizador buyerApproved para indicar que o comprador iniciou a transferência.
  1. Aprovação do Vendedor e do Comprador

Tanto o vendedor quanto o comprador precisam aprovar a transferência antes que ela possa ser concluída:

  • O vendedor aprova a transferência chamando a função approveTransferAsSeller e fornecendo o landID.
  • O comprador aprova a transferência chamando a função approveTransferAsBuyer e fornecendo o landID.
  1. Concluindo a transferência

Depois que o comprador e o vendedor aprovarem a transferência, a transferência será concluída:

  • A função checkAndCompleteTransfer é invocada, verificando se buyerApproved e sellerApproved estão definidos como verdadeiros.
  • Se ambas as aprovações forem verdadeiras, a função transfere a propriedade do terreno do vendedor para o “aprovador” acordado.
  • O sinalizador wantSell do terreno é definido como 0, indicando que o terreno não está mais disponível para venda.
  • O “aprovador” acordado assume a propriedade do token do terreno e o custo do terreno é transferido para o vendedor.

Desta forma, o token de terreno é vendido e transferido com sucesso do vendedor para o comprador, com o envolvimento do aprovador acordado.

Em conclusão, o contrato inteligente apresentado demonstra como a tecnologia blockchain, através do uso de Solidity e OpenZeppelin, pode ser aproveitada para implementar um sistema descentralizado de registo imobiliário. O contrato utiliza o padrão ERC-721 para criar tokens únicos e não fungíveis, cada um representando uma parcela distinta de terreno.

O proprietário do contrato, normalmente uma entidade governamental, tem autoridade para adicionar terras ao contrato, facilitando a criação de um registo imobiliário digital. Compradores e vendedores interagem com o contrato para iniciar transferências de terras, e um aprovador acordado desempenha um papel crucial na conclusão do processo de transferência.

Embora o contrato aqui apresentado sirva como um exemplo simplificado para fins educativos e ilustrativos, em implementações no mundo real, deve ser dada especial atenção à segurança, auditabilidade e conformidade com os regulamentos relevantes para garantir a praticidade e fiabilidade do contrato no tratamento de transações imobiliárias.

Num futuro próximo, os contratos inteligentes têm o potencial de revolucionar o setor imobiliário, oferecendo transparência, imutabilidade e automação nas transferências de propriedade de terras, simplificando e melhorando a eficiência do processo.

Se você achar esta informação útil, considere me apoiar e me seguir para obter mais atualizações.🙂

Tutorial Solidity

Blockchain de contrato inteligente

Este artigo foi escrito por Brian e traduzido por Diogo Jorge. O artigo original pode ser encontrado aqui.

Oldest comments (0)