Toda la actividad económica se basa históricamente en intermediarios. Cualquier transacción, incluso simple entre las dos partes, va acompañada de la participación de varios intermediarios: bancos, casas de cambio, cámaras de compensación, etc. La exclusión de intermediarios probablemente haría que la interacción sea más eficiente. Entonces, ¿por qué no intentar construir una nueva infraestructura descentralizada sobre la base de blockchain, donde los participantes en la transacción pueden trabajar directamente? En esta publicación, hablaremos sobre cómo comenzamos nuestro viaje hacia dicha infraestructura: desarrollamos transacciones de blockchain y, como resultado, realizamos repos - préstamos de dinero contra valores.

Bonos a corto plazo
Nuestra primera transacción financiera OTC en blockchain fue la emisión de un bono a corto plazo del operador móvil MTS con la participación del Depósito Nacional de Liquidación (NSD). Este es un tipo de "banco central" de todos los depositarios. Los depositarios son intermediarios de infraestructura que mantienen registros de los propietarios de valores y los emiten.
En esa transacción, MTS, al llamar a la función del contrato inteligente, registró en la cadena de bloques una expresión de voluntad de vender valores a Sberbank, y confirmó en la cadena de bloques su acuerdo con los términos de la transacción. Las órdenes contrarias firmadas por ambas partes fueron recibidas por NSD, que las ejecutó en sus sistemas contables. Además, la cadena de bloques mostraba las cuentas de los participantes de la transacción en valores y dinero.
En ese proyecto, seleccionamos la plataforma
Hyperledger Fabric 1.1 de código abierto, diseñada para crear soluciones de blockchain empresariales cerradas. Las cadenas de bloques públicas no son adecuadas aquí, porque debemos garantizar la privacidad de los datos. Enfrentamos tales limitaciones en el piloto de factoring de Sberbank con M. Video, que se implementó en la cadena de bloques Ethereum. Por el contrario, Hyperledger Fabric le permite colocar a todos los participantes en una transacción en un canal dedicado, donde pueden intercambiar cualquier información necesaria y procesarla con contratos inteligentes con todas las funciones.
El código fuente del proyecto de emisión de bonos MTS se subió públicamente a GitHub. Sin siquiera entrar en el algoritmo de trabajo, puede comprender que en el ciclo de vida de una transacción, la cadena de bloques recibió un papel bastante modesto como transporte de órdenes de compensación. Por otro lado, sobre la base de estas instrucciones, los saldos de las cuentas cambiaron, por lo que desde el punto de vista de la lógica empresarial, esto fue más interesante que un simple servicio de gestión de documentos electrónicos.
La principal ventaja de la solución era la versatilidad. El esquema de “dos contrapartes y un registrador” cubre casi cualquier transacción en el mercado OTC, y con cambios menores, la mayoría de las transacciones comerciales en general.
REPO 1.0
En un nuevo proyecto en la cadena de bloques, decidimos mostrar cómo implementar un acuerdo de recompra en un sistema descentralizado: un préstamo de dinero contra valores. Por lo general, estas y otras transacciones OTC pasan por intermediarios: depositarios, cámaras de compensación, corredores.
En este proyecto, celebramos un acuerdo de recompra entre Sberbank y un socio extranjero. Ya utilizaba Hyperledger Fabric versión 1.2. En comparación con los bonos MTS, tuvimos dos diferencias:
- Solo dos participantes en la transacción se conectaron a la cadena de bloques, cuyos depositarios, Euroclear y Clearstream, recibieron todos los pedidos a través de los canales tradicionales de transmisión de datos desde las oficinas administrativas de Sberbank y su contraparte.
- En el contrato inteligente, implementamos una lógica comercial compleja: las cotizaciones diarias de la seguridad que sirvieron como garantía para el préstamo se descargaron a la cadena de bloques, y el contrato inteligente calculó la necesidad y el monto del reembolso anticipado, teniendo en cuenta el costo modificado de la garantía, el descuento, el calendario de los intercambios de salida y otros parámetros. Tal sincronización P2P de algoritmos de cálculo entre participantes no se puede obtener sin un registro distribuido. Esto es mucho más conveniente que un cálculo independiente de obligaciones y montos por cada lado: sin reconciliaciones que requieren mucho tiempo, sin confirmaciones.
Entre contrapartes organizó un chat y flujo de trabajo dentro del canal. Los datos sobre ellos se almacenaron en la cadena de bloques. Después de cada cambio en el registro distribuido, los miembros del canal recibieron una alerta por correo electrónico.
"REPO 1.0" trabajamos desde el lado legal. Con la ayuda de una gran firma de abogados, se realizó un análisis de los casos del Tribunal Superior de Londres. Además, el EDS del banco y su contraparte utilizaron diferentes algoritmos criptográficos.
¿Cómo funciona REPO 1.0?
Cada parte de la transacción tiene su propio nodo blockchain. Todos los nodos están conectados entre sí en una red P2P. Supongamos que necesita hacer un trato. Implementamos un contrato inteligente entre las partes de la transacción, donde se describe completamente el instrumento financiero.

Después de la creación del contrato de nuestra parte, el comerciante lo firma. El cliente también revisa y firma el contrato. Luego se revisan y verifican las firmas. En este caso, la transacción se realizó bajo la ley inglesa, los datos de la firma digital electrónica se ingresaron en el documento GMRA. Para la firma del cliente, se requiere verificación de que una persona autorizada esté presente en el certificado de firma. Finalmente, el cliente acepta el contrato y acepta todas las condiciones. Puede adjuntar cualquier número de documentos a un contrato firmado.
Después de eso, el contrato recibe el estado de "en el trabajo". El contrato "en curso" se recalcula automáticamente al cargar nuevos precios de mercado. Si hay un valor en el contrato, se toma el precio de mercado, se recalcula el Préstamo a Valor (LTV): la relación entre el monto del préstamo y el valor del valor en valores. LTV es uno de los términos clave en una transacción de repos, su significado se prescribe en el contrato. El precio de las acciones ha aumentado considerablemente, y el LTV se está volviendo menor que el indicado en GMRA (en lo que respecta a la ley inglesa). En consecuencia, el banco devuelve valores al cliente (como una de las opciones), ya que teniendo en cuenta los nuevos precios, resulta que el banco tiene una mayor seguridad.
Pero si LTV se hace más grande, entonces el programa le permite imprimir un aviso colateral, una notificación al cliente sobre la necesidad de hacer seguridad adicional (acciones o dinero) para que el valor de LTV vuelva al valor inicial. Anteriormente, la notificación colateral solo podía enviarse por correo, se creaban documentos separados para esto y durante la creación de estos documentos, LTV podía cambiar nuevamente. Ahora que vemos los mismos cálculos con el cliente en línea, podemos interactuar fácilmente.
Además, el programa todos los días fija el precio de la recompra de valores, teniendo en cuenta los intereses. Si el cliente no está de acuerdo con él al cargar el precio de mercado, mira el registro de recálculo completo: qué fue, qué se convirtió, qué precio se cargó, de dónde vino. Y luego comienza la discusión del chat.
REPO 2.0
Queríamos que nuestro REPO en la cadena de bloques pudiera iniciar el movimiento de activos reales en función de nuestra lógica interna. Pero en REPO 1.0, debido a las dificultades organizativas para conectar los depósitos occidentales, aún no hemos podido lograrlo. Entonces comenzamos el nuevo piloto Repo 2.0. Tenía dos objetivos:
- La transacción debe realizarse con la participación de dos partes y el depositario, para aprovechar al máximo la infraestructura del proyecto de bonos MTS.
- La cadena de bloques debe estar facultada para volver a evaluar la garantía y configurar una llamada de margen que podría ser ejecutada automáticamente por un depósito conectado a una red distribuida.
NSD inmediatamente quiso conectarse al proyecto. Para aterrizar una transacción iniciada en blockchain en el campo conservador de las leyes federales que rigen el mercado financiero nacional, trabajamos con abogados para un acuerdo complementario de cinco páginas para el acuerdo de gestión de documentos electrónicos. Fue firmado por todas las partes de la transacción y NSD.
NSD actuó como cámara de compensación en esta transacción. Realizó todas las instrucciones sobre el movimiento de fondos y valores. Esta transacción se concluyó bajo la ley rusa.
El cliente aceptó el contrato con una firma electrónica. Luego, el acuerdo fue aceptado por Sberbank con su firma: verificó el cumplimiento de todos los parámetros con los valores necesarios y la autoridad de la persona que aceptó del cliente. Después de eso, el contrato entró en funcionamiento. NSD subió datos de mercado, recálculo de contrato inteligente.
¿Cómo funciona REPO 2.0?
Para implementar la red e interactuar con la interfaz del cliente con el código de cadena, utilizamos la solución
Fabric Starter . En lugar de la interfaz grpc estándar para HLF, proporciona una API REST, que en nuestro caso redujo significativamente la complejidad de la integración.

La red subió de la siguiente manera. Cada uno de los tres lados después de la preinstalación en el servidor Docker lanzó Fabric Starter, que creó contenedores con los componentes del nodo. Estos componentes incluían un par externo para interactuar con otras organizaciones y un servicio API REST a través del cual el nodo interactuaba con la aplicación cliente. En el lanzamiento de Starter, la red blockchain también se configuró y se creó un canal privado en el que se instaló el código de la cadena con la política de respaldo. En nuestro caso, cada transacción debe tener las firmas de los tres participantes.
Durante la fase de prueba, Docker Swarm se utilizó para organizar la conexión de los servidores de los participantes, sin embargo, con el fin de hacer un trato real, cambiaron a DNS. La plataforma en sí es responsable del transporte de mensajes; los datos se transmiten a través de Internet con cifrado TLS.
El aspecto técnico del problema.
El proceso de desarrollo de una aplicación distribuida en HLF comienza de manera bastante tradicional, con estructuras de datos y un código de cadena (de hecho, un conjunto de procedimientos almacenados), cuya llamada conduce al almacenamiento, modificación o lectura de estas estructuras desde el libro mayor. La plataforma permite el uso de varios lenguajes de programación para el desarrollo de códigos de cadena y DBMS para almacenamiento local. Preferimos Go y CouchDB, respectivamente.
La esencia central de los proyectos de repos en nuestro modelo de datos es el contrato en sí y sus obligaciones subsidiarias. Fueron creados para cada uno de los dos pilotos, así como para llamadas de margen. Esta arquitectura fue un paso adelante en comparación con el modelo de enlace MTS, que se basó en la esencia de la "Orden". También se crearon objetos independientes para valores, que por lo tanto se tokenizaron parcialmente. Pero al desarrollar el experimento con la administración de cuentas y la tokenización virtual de dinero, decidimos posponer una de las próximas versiones de la solución.
Las principales funciones de nuestra solución:
- Crea un contrato.
- Firme un contrato con su EDS confirmando la aceptación de los términos del contrato.
- Descargue los precios de mercado y comience a recalcular el valor colateral. Su desviación del umbral establecido provocó la creación de una nueva obligación de llamada de margen.
- Reflejar el estado de la obligación.
En el aspecto técnico, el procedimiento de reevaluación es más interesante aquí. Analicémoslo con más detalle.
En el proceso comercial, el procedimiento debe iniciarse una vez al día, después de que Oracle (en la prueba piloto de "REPO 2.0" realizada por NSD) cargó las cotizaciones actualizadas de valores en el sistema.
func (t *CIBContract) recalculationData(stub shim.ChaincodeStubInterface, loadData *loadDataType, curDay string) pb.Response {...}
El ciclo principal del procedimiento pasa por todos los valores para los que se han actualizado las cotizaciones.
for _, securities := range loadData.Securities {...}
A continuación, se realizan varios controles. Por ejemplo, si el intercambio con el que se recibieron los datos del mercado es hoy un día libre, entonces el recuento no debería ocurrir.
if t.checkHoliday(stub, contract.Settings.Calendars) == "yes" { hisYes := historyType{curDay, "LoadData. Calendar", "System", "LoadData. Today is holiday ! No load market data to contract !"} ... contract.History = append(contract.History, hisYes) … err = stub.PutState(contrID, contractJSONasBytes) }
Para calcular el precio del bono actualizado, el rendimiento del cupón acumulado (NDC) se agrega al precio neto cargado. El piloto implementó el soporte para el esquema 30/360 para calcular NKD.
priceIzm = float64(securities.Price + float64(securities.CouponRate)*float64((int(settlementDate.Year()) - int(dateStart.Year()))*360 + (int(settlementDate.Month()) - int(dateStart.Month()))*30 + (int(settlementDate.Day()) - int(dateStart.Day())))*100/360/100) curCurrVal = priceIzm
Si la moneda de la transacción es diferente de la moneda en la que se cotiza el valor, se realiza una conversión de cambio.
if contract.GeneralTerms.PurchasePrice.Currency != securities.Currency { curCurrName = securities.Currency + "-" + contract.GeneralTerms.PurchasePrice.Currency for _, currency := range loadData.Currencies { if currency.Name == curCurrName { curCurrVal = priceIzm * currency.Value } } }
Ahora necesitamos calcular LTV. Mantenga el antiguo valor del coeficiente para la historia.
oldCurLTV := contract.MarginingTerms.CurrentLTV
Es necesario tener en cuenta las llamadas de margen ejecutadas durante la vida de la transacción. Los requisitos pueden provenir de ambos lados y en dos formas:
- Valores El prestatario otorga seguridad adicional en caso de una caída en el precio de mercado de la seguridad. El acreedor devuelve parte de la garantía en caso de aumento de precios.
- Dinero El prestatario antes de lo programado paga la parte del préstamo que ha dejado de estar cubierta por una garantía más barata. El prestamista aumenta el monto del préstamo en respuesta a un aumento en el valor de la garantía.
En el primer caso, la cantidad de valores en la garantía simplemente se actualiza. Y en caso de ganar dinero con ellos, también es necesario acumular la rentabilidad especificada en los términos adicionales de la transacción.
for _, addCollateral := range contract.MarginingTerms.AddCollateral { currSumCollateral := addCollateral.Sum + (addCollateral.Sum*contract.MarginingTerms.RateOnCashMargin*float64(deltaColDate) / float64(contract.MarginingTerms.Basis))/100 ... allSumCollateral = allSumCollateral + currSumCollateral ... ht := historyType{curDay, System", "LoadData. Recalculation data(addCollateral) Contract " + contrID + " - currSumCollateral: " + strconv.FormatFloat(float64(currSumCollateral), 'f', 2, 64) ... } ... contract.History = append(contract.History, ht) }
Calculamos el monto total de la recompra; de hecho, este es el monto del préstamo con intereses, que debemos pagar.
rePurchasePriceCur := contract.GeneralTerms.PurchasePrice.Sum + (contract.GeneralTerms.PurchasePrice.Sum*contract.GeneralTerms.RepoRate*float64(deltaSigningDate)/float64(contract.MarginingTerms.Basis))/100
Ahora calculamos el coeficiente LTV. Para hacer esto, reste el valor en efectivo del precio de recompra y divida el valor resultante por el valor total de los valores en el valor. Los montos acreditados por el acreedor están marcados con un "-" y se agregarán al precio de recompra.
contract.MarginingTerms.CurrentLTV = (rePurchasePriceCur - allSumCollateral) * float64(100) / (float64(contract.GeneralTerms.PurchasedSecurities.Quantity) * curCurrVal)
Finalmente, calculamos los desencadenantes en el contrato. El mismo procedimiento creará objetos de orden de llamada de margen si el valor de LTV se desvía del corredor especificado.
contract = t.checkTriggerEvents(stub, "LoadData", contract, curDay, securities)
Y escriba información en el historial para mostrarla en la interfaz de usuario.
ht := historyType{curDay, "System", "LoadData. Recalculation data(change curLTV, ADTV) Contract " + contrID + " - oldCurLTV: " + strconv.FormatFloat(float64(oldCurLTV), 'f', 2, 64) + ", newCurLTV: " + strconv.FormatFloat(float64(contract.MarginingTerms.CurrentLTV), 'f', 2, 64)...} contract.History = append(contract.History, ht)
Para resumir
Tal esquema puede funcionar no solo con valores y contratos, sino también en otros escenarios. Por ejemplo, con los suministros de electricidad, donde hay diferentes tarifas, diferentes conexiones en diferentes momentos. O con la factorización: préstamos a proveedores por señales de envío de mercancías. Hay muchos casos de usuarios en economía, cuando todos usan sus propias fuentes de datos que deben verificarse.
Nuestro objetivo es crear una red que conecte a los bancos entre sí y a sus clientes en todo el país, y que use contratos inteligentes para describir en él contratos no de criptografía, sino de la economía tradicional: instrumentos financieros. Dicha red será estable, abierta y, como debería estar en una red P2P, aquí nadie tendrá un estado especial.