Traducción y revisión: "Comunidad china de Starknet"
descripción general
La versión 2 del compilador Cairo introduce cambios en la sintaxis de Starknet para que el código sea más explícito y seguro. La interfaz pública del contrato inteligente se define mediante rasgos, y el acceso al almacenamiento se realiza a través del rasgo ContractState. Los métodos privados deben definirse con una implementación diferente a la interfaz pública. Los eventos ahora se definen como enumeraciones, donde cada variante es una estructura del mismo nombre.
Descargo de responsabilidad: los términos utilizados aquí se refieren a diferentes versiones del compilador Cairo, y la sintaxis es provisional ya que la comunidad de Starknet aún está debatiendo cuál es el mejor término a utilizar. Una vez determinado, este artículo se actualizará en consecuencia.
El compilador v2
La semana pasada, se lanzó en Github una nueva versión principal 2.0.0-rc0 del compilador Cairo. El nuevo compilador brinda mejoras significativas al complemento Starknet, lo que hace que nuestro código sea más seguro, más explícito y más reutilizable. Tenga en cuenta que esta nueva versión del compilador aún no es compatible con Starknet testnet o mainnet, ya que todavía se está trabajando en el entorno integrado.
El objetivo de este artículo es mostrarle cómo reescribir un contrato inteligente de Starknet creado para la versión 1.x del compilador de Cairo en un contrato inteligente compatible con la versión 2.x del compilador. Nuestro punto de partida es el contrato inteligente Ownable creado en el artículo anterior, que es compatible con la versión 1.x del compilador Cario.
[contract] mod Ownable {use starknet::ContractAddress;use starknet::get_caller_address;
[event] fn OwnershipTransferred(anterior_propietario: dirección del contrato, nuevo_propietario: dirección del contrato) {}
almacenamiento de estructura {propietario: ContractAddress,}
fn only_owner() {let caller = get_caller_address();assert(caller == propietario::read(), 'La persona que llama no es el propietario');
Configuración del proyecto
Dado que Protostar aún no admite el compilador v2, este artículo se basará en la versión preliminar de Scarb (versión 0.5.0-alpha.1) que lo admite. Para instalar esa versión específica de Scarb, puede usar el siguiente comando.
Una vez completada la configuración, podemos dirigirnos a src/lib.cairo y comenzar a escribir contratos inteligentes.
Almacenamiento y constructor
En la versión 2 del compilador de Cairo, los contratos inteligentes todavía están definidos por módulos anotados con un atributo de contrato, solo que esta vez el atributo lleva el nombre del complemento que lo define, en este caso, starknet.
#[starknet::contrato]mod Propiedad {}
El almacenamiento interno todavía se define como una estructura que debe llamarse Almacenamiento, solo que esta vez debe anotarse con un atributo de almacenamiento.
Para definir el constructor, anotamos la función con el atributo constructor, como hicimos en v1, la ventaja es que ahora la función puede tener cualquier nombre, no necesita llamarse "constructor" como en v1. Aunque no es obligatorio, me referiré a la función como un "constructor" por convención, pero puede llamarla de otra manera.
Otro cambio importante es que ahora el constructor pasa automáticamente una referencia a ContractState, que actúa como intermediario para almacenar variables, en este caso "propietario".
Tenga en cuenta que la sintaxis para escribir y leer el almacenamiento ha cambiado desde la v1. Antes hacíamos propietario::escribir(), ahora hacemos self.propietario.escribir(). Lo mismo se aplica a la lectura desde el almacenamiento.
Por cierto, no es necesario incluir el tipo ContractState en el ámbito manualmente, se incluye en el preludio.
Métodos públicos
Una diferencia importante con respecto a la versión 1 del compilador Cairo es que ahora necesitamos definir explícitamente la interfaz pública de un contrato inteligente usando características anotadas con el atributo starknet::interface.
Si recuerda el código original de v1, nuestro contrato inteligente tiene dos métodos "públicos" (obtener_propietario y transferir_propiedad) y un método "privado" (solo_propietario). Esta función solo trata con métodos públicos y no se basa en atributos "externos" o de "vista" para indicar qué métodos pueden modificar el estado del contrato y cuáles no. En cambio, esto ahora se hace explícito por el tipo del parámetro self.
Si un método requiere una referencia a ContractStorage (que, una vez implementado, lo hace la T genérica), ese método puede modificar el estado interno del contrato inteligente. Esto es lo que solíamos llamar un método "externo". Por otro lado, si un método requiere una instantánea de ContractStorage, solo puede leerla, no modificarla. Esto es lo que solíamos llamar el método "ver".
Ahora podemos crear una implementación para el rasgo que acabamos de definir usando la palabra clave impl. Recuerde, Cairo se diferencia de Rust en que las implementaciones tienen nombres.
Creamos una implementación para nuestro rasgo dentro del módulo que define el contrato inteligente, pasando el tipo ContractState como un tipo T genérico para que se pueda acceder al almacenamiento como un constructor.
Nuestra implementación está anotada con el atributo external(v0). La versión 0 en el atributo significa que el selector solo se deriva del nombre del método, como ocurría en el pasado. La desventaja es que si define otra implementación de un rasgo diferente para su contrato inteligente, y dos rasgos usan el mismo nombre para uno de sus métodos, el compilador arrojará un error debido al selector duplicado.
Una versión futura de esta propiedad puede agregar una nueva forma de evaluar los selectores para evitar conflictos, pero eso aún no funciona. Actualmente, solo podemos usar la versión 0 de las propiedades externas.
Métodos privados
También necesitamos definir otro método para el contrato inteligente, solo_propietario. Este método verifica si la persona que lo llama debe ser el propietario del contrato inteligente.
Debido a que este es un método privado al que no se permite llamar desde el exterior, no se puede definir como parte de OwnableTrait (la interfaz pública del contrato inteligente). En su lugar, usaremos el atributo generate_trait para crear una nueva implementación del rasgo generado automáticamente.
...#[starknet::contract]mod Ownable { ... #[generar_trait] impl PrivateMethods of PrivateMethodsTrait { fn only_owner(self: @ContractState) { let llamante = get_caller_address(); afirmar(persona que llama == self.propietario.leer(), 'La persona que llama no es el propietario'); }
El método only_owner ahora se puede usar llamando a self.only_owner() donde sea necesario.
En Cairo v1, un evento era solo una función sin cuerpo y anotada con el atributo de evento, mientras que en v2 un evento es una enumeración anotada con el mismo atributo, pero ahora implementada usando derivar algunas características adicionales.
#[derive(Drop, starknet::Event)] struct OwnershipTransferred { # [key] anterior_propietario: dirección del contrato, # [key] nuevo_propietario: dirección del contrato,
Cada variante de la enumeración de eventos debe ser una estructura con el mismo nombre. En esta estructura, usamos el atributo clave opcional para definir todos los valores que queremos emitir, para informar al sistema qué valores queremos que Starknet indexe, para que el indexador pueda buscar y recuperar más rápido. En este caso, queremos indexar dos valores (anterior_propietario y nuevo_propietario).
El rasgo ContractState define un método de emisión que se puede usar para emitir eventos.
Con esta característica final, hemos completado la migración del contrato inteligente Ownable de v1 a v2. El código completo se muestra a continuación.
#[generar_trait] impl PrivateMethods of PrivateMethodsTrait { fn only_owner(self: @ContractState) { let llamante = get_caller_address(); afirmar(persona que llama == self.propietario.leer(), 'La persona que llama no es el propietario'); }
También puede encontrar este código en Github.
en conclusión
La versión 2 del compilador de Cairo trae una nueva sintaxis a Starknet que hace que el código de contrato inteligente se vea más consistente con el propio Cairo y, por extensión, más parecido a Rust. Incluso a expensas de un código más engorroso, los beneficios de seguridad valen la pena.
En este artículo, no hemos tocado todo sobre la nueva sintaxis, especialmente cómo interactúa con otros contratos inteligentes, pero puede leer el registro de cambios del compilador, leer esta publicación en el foro o ver un video en el canal de YouTube de StarkWare para obtener más información. al respecto Para saber más información.
Esta nueva versión del compilador estará disponible en la red de prueba de Starknet en unas pocas semanas y en la red principal en unas pocas semanas, así que no intentes implementar este código todavía, todavía no funcionará.
El Cairo sigue mejorando.
recurso
Sintaxis del contrato - Guía de migración
Cairo 1: la sintaxis del contrato está evolucionando
Ver originales
This page may contain third-party content, which is provided for information purposes only (not representations/warranties) and should not be considered as an endorsement of its views by Gate, nor as financial or professional advice. See Disclaimer for details.
Interpretación completa de la gramática mejorada de Starknet
Original: Sintaxis de Starknet mejorada
Traducción y revisión: "Comunidad china de Starknet"
descripción general
La versión 2 del compilador Cairo introduce cambios en la sintaxis de Starknet para que el código sea más explícito y seguro. La interfaz pública del contrato inteligente se define mediante rasgos, y el acceso al almacenamiento se realiza a través del rasgo ContractState. Los métodos privados deben definirse con una implementación diferente a la interfaz pública. Los eventos ahora se definen como enumeraciones, donde cada variante es una estructura del mismo nombre.
Descargo de responsabilidad: los términos utilizados aquí se refieren a diferentes versiones del compilador Cairo, y la sintaxis es provisional ya que la comunidad de Starknet aún está debatiendo cuál es el mejor término a utilizar. Una vez determinado, este artículo se actualizará en consecuencia.
El compilador v2
La semana pasada, se lanzó en Github una nueva versión principal 2.0.0-rc0 del compilador Cairo. El nuevo compilador brinda mejoras significativas al complemento Starknet, lo que hace que nuestro código sea más seguro, más explícito y más reutilizable. Tenga en cuenta que esta nueva versión del compilador aún no es compatible con Starknet testnet o mainnet, ya que todavía se está trabajando en el entorno integrado.
El objetivo de este artículo es mostrarle cómo reescribir un contrato inteligente de Starknet creado para la versión 1.x del compilador de Cairo en un contrato inteligente compatible con la versión 2.x del compilador. Nuestro punto de partida es el contrato inteligente Ownable creado en el artículo anterior, que es compatible con la versión 1.x del compilador Cario.
[contract] mod Ownable {use starknet::ContractAddress;use starknet::get_caller_address;
[event] fn OwnershipTransferred(anterior_propietario: dirección del contrato, nuevo_propietario: dirección del contrato) {}
almacenamiento de estructura {propietario: ContractAddress,}
[constructor] fn constructor() {let deploymenter = get_caller_address();propietario::escribir(implementador);}
[view] fn obtener_propietario() -> Dirección del contrato {propietario::leer()}
[external] fn transferir_propiedad(nuevo_propietario: dirección del contrato) {solo_propietario(); dejar anterior_propietario = propietario::leer();propietario::escribir(nuevo_propietario);OwnershipTransferred(anterior_propietario, nuevo_propietario) ;}
fn only_owner() {let caller = get_caller_address();assert(caller == propietario::read(), 'La persona que llama no es el propietario');
Configuración del proyecto
Dado que Protostar aún no admite el compilador v2, este artículo se basará en la versión preliminar de Scarb (versión 0.5.0-alpha.1) que lo admite. Para instalar esa versión específica de Scarb, puede usar el siguiente comando.
$ --proto '=https' --tlsv1.2 -sSf | bash -s -- -v 0.5.0-alfa.1
Una vez finalizada la instalación, compruebe que tiene la versión correcta.
$ scarb --version>>>scarb 0.5.0-alpha.1 (546dad33d 2023-06-19)cairo:2.0.0-rc3()
Ahora se puede crear un proyecto Scarb.
$ marcar nuevo cairo1_v2$cdcairo1_v2
Debería obtener una estructura de carpetas como la siguiente.
$ árbol .>>>.├── Scarb.toml└── src└──lib.cairo
Para que Scarb compile los contratos inteligentes de Starknet, el complemento de Starknet debe estar habilitado como una dependencia.
// Cicatriz.toml... [dependencies] starknet="2.0.0-rc3"
Una vez completada la configuración, podemos dirigirnos a src/lib.cairo y comenzar a escribir contratos inteligentes.
Almacenamiento y constructor
En la versión 2 del compilador de Cairo, los contratos inteligentes todavía están definidos por módulos anotados con un atributo de contrato, solo que esta vez el atributo lleva el nombre del complemento que lo define, en este caso, starknet.
#[starknet::contrato]mod Propiedad {}
El almacenamiento interno todavía se define como una estructura que debe llamarse Almacenamiento, solo que esta vez debe anotarse con un atributo de almacenamiento.
#[starknet::contrato]mod Propiedad {use super::ContractAddress; # [storage] almacenamiento de estructura {propietario: ContractAddress,
Para definir el constructor, anotamos la función con el atributo constructor, como hicimos en v1, la ventaja es que ahora la función puede tener cualquier nombre, no necesita llamarse "constructor" como en v1. Aunque no es obligatorio, me referiré a la función como un "constructor" por convención, pero puede llamarla de otra manera.
Otro cambio importante es que ahora el constructor pasa automáticamente una referencia a ContractState, que actúa como intermediario para almacenar variables, en este caso "propietario".
#[starknet::contrato]mod Propiedad {use super::ContractAddress; # [storage] almacenamiento de estructura {propietario: ContractAddress,} # [constructor] fn constructor(ref self: ContractState) {let deploymenter = get_caller_address();self.owner.write(implementador);
Tenga en cuenta que la sintaxis para escribir y leer el almacenamiento ha cambiado desde la v1. Antes hacíamos propietario::escribir(), ahora hacemos self.propietario.escribir(). Lo mismo se aplica a la lectura desde el almacenamiento.
Por cierto, no es necesario incluir el tipo ContractState en el ámbito manualmente, se incluye en el preludio.
Métodos públicos
Una diferencia importante con respecto a la versión 1 del compilador Cairo es que ahora necesitamos definir explícitamente la interfaz pública de un contrato inteligente usando características anotadas con el atributo starknet::interface.
use starknet::ContractAddress;
#[starknet::interface]trait OwnableTrait { fn transfer_ownership(ref self: T, new_owner: ContractAddress); fn get_owner(self: @T) -> Dirección del contrato;}
#[starknet::contrato]mod Propiedad { ...}
Si recuerda el código original de v1, nuestro contrato inteligente tiene dos métodos "públicos" (obtener_propietario y transferir_propiedad) y un método "privado" (solo_propietario). Esta función solo trata con métodos públicos y no se basa en atributos "externos" o de "vista" para indicar qué métodos pueden modificar el estado del contrato y cuáles no. En cambio, esto ahora se hace explícito por el tipo del parámetro self.
Si un método requiere una referencia a ContractStorage (que, una vez implementado, lo hace la T genérica), ese método puede modificar el estado interno del contrato inteligente. Esto es lo que solíamos llamar un método "externo". Por otro lado, si un método requiere una instantánea de ContractStorage, solo puede leerla, no modificarla. Esto es lo que solíamos llamar el método "ver".
Ahora podemos crear una implementación para el rasgo que acabamos de definir usando la palabra clave impl. Recuerde, Cairo se diferencia de Rust en que las implementaciones tienen nombres.
use starknet::ContractAddress;
#[starknet::interface]trait OwnableTrait { fn transfer_ownership(ref self: T, new_owner: ContractAddress); fn get_owner(self: @T) -> Dirección del contrato;}
#[starknet::contract]mod Propiedad { ... #[externo(v0)] impl OwnableImpl of super::OwnableTrait { fn transfer_ownership(ref self: ContractState, new_owner: ContractAddress) { let prev_owner = self.propietario.leer(); self.propietario.escribir(nuevo_propietario); }
fn obtener_propietario(self: @ContractState) -> ContractAddress { self.propietario.leer() }
Creamos una implementación para nuestro rasgo dentro del módulo que define el contrato inteligente, pasando el tipo ContractState como un tipo T genérico para que se pueda acceder al almacenamiento como un constructor.
Nuestra implementación está anotada con el atributo external(v0). La versión 0 en el atributo significa que el selector solo se deriva del nombre del método, como ocurría en el pasado. La desventaja es que si define otra implementación de un rasgo diferente para su contrato inteligente, y dos rasgos usan el mismo nombre para uno de sus métodos, el compilador arrojará un error debido al selector duplicado.
Una versión futura de esta propiedad puede agregar una nueva forma de evaluar los selectores para evitar conflictos, pero eso aún no funciona. Actualmente, solo podemos usar la versión 0 de las propiedades externas.
Métodos privados
También necesitamos definir otro método para el contrato inteligente, solo_propietario. Este método verifica si la persona que lo llama debe ser el propietario del contrato inteligente.
Debido a que este es un método privado al que no se permite llamar desde el exterior, no se puede definir como parte de OwnableTrait (la interfaz pública del contrato inteligente). En su lugar, usaremos el atributo generate_trait para crear una nueva implementación del rasgo generado automáticamente.
...#[starknet::contract]mod Ownable { ... #[generar_trait] impl PrivateMethods of PrivateMethodsTrait { fn only_owner(self: @ContractState) { let llamante = get_caller_address(); afirmar(persona que llama == self.propietario.leer(), 'La persona que llama no es el propietario'); }
El método only_owner ahora se puede usar llamando a self.only_owner() donde sea necesario.
#[starknet::contract]mod Ownable { ... #[external(v0)] impl OwnableImpl of super::OwnableTrait { fn transfer_ownership(ref self: ContractState, new_owner: ContractAddress) { self.only_owner (); ... } ... }
#[generar_trait] impl PrivateMethods of PrivateMethodsTrait { fn only_owner(self: @ContractState) { ... }
evento
En Cairo v1, un evento era solo una función sin cuerpo y anotada con el atributo de evento, mientras que en v2 un evento es una enumeración anotada con el mismo atributo, pero ahora implementada usando derivar algunas características adicionales.
...#[starknet::contrato]mod Propiedad { ... # [event] #[derive(Drop, starknet::Event)] enum Event { OwnershipTransferred: OwnershipTransferred, }
#[derive(Drop, starknet::Event)] struct OwnershipTransferred { # [key] anterior_propietario: dirección del contrato, # [key] nuevo_propietario: dirección del contrato,
Cada variante de la enumeración de eventos debe ser una estructura con el mismo nombre. En esta estructura, usamos el atributo clave opcional para definir todos los valores que queremos emitir, para informar al sistema qué valores queremos que Starknet indexe, para que el indexador pueda buscar y recuperar más rápido. En este caso, queremos indexar dos valores (anterior_propietario y nuevo_propietario).
El rasgo ContractState define un método de emisión que se puede usar para emitir eventos.
...#[starknet::contract]mod Ownable { ... #[external(v0)] impl OwnableImpl of super::OwnableTrait { fn transfer_ownership(ref self: ContractState, new_owner: ContractAddress) { .. self.emit(Evento::PropiedadTransferida(PropiedadTransferida { anterior_propietario: anterior_propietario, nuevo_propietario: nuevo_propietario, })); }... }...}
Con esta característica final, hemos completado la migración del contrato inteligente Ownable de v1 a v2. El código completo se muestra a continuación.
use starknet::ContractAddress;
#[starknet::interface]trait OwnableTrait { fn transfer_ownership(ref self: T, new_owner: ContractAddress); fn get_owner(self: @T) -> Dirección del contrato;}
#[starknet::contrato]mod Propiedad { use super::ContractAddress; use starknet::get_caller_address;
[event] #[derive(Drop, starknet::Event)] enum Event { OwnershipTransferred: OwnershipTransferred, }
#[derive(Drop, starknet::Event)] struct OwnershipTransferred { # [key] anterior_propietario: dirección del contrato, # [key] nuevo_propietario: dirección del contrato, }
[storage] almacenamiento de estructura {propietario: ContractAddress,}
[constructor] fn constructor(ref self: ContractState) { let deploymentr = get_caller_address(); self.propietario.escribir(implementador); }
#[external(v0)] impl OwnableImpl of super::OwnableTrait { fn transfer_ownership(ref self: ContractState, new_owner: ContractAddress) { self.only_owner(); let anterior_propietario = self.propietario.leer(); self.propietario.escribir(nuevo_propietario); self.emit(Evento::PropiedadTransferida(PropiedadTransferida { anterior_propietario: anterior_propietario, nuevo_propietario: nuevo_propietario, })); }
fn obtener_propietario(self: @ContractState) -> ContractAddress { self.propietario.leer() } }
#[generar_trait] impl PrivateMethods of PrivateMethodsTrait { fn only_owner(self: @ContractState) { let llamante = get_caller_address(); afirmar(persona que llama == self.propietario.leer(), 'La persona que llama no es el propietario'); }
También puede encontrar este código en Github.
en conclusión
La versión 2 del compilador de Cairo trae una nueva sintaxis a Starknet que hace que el código de contrato inteligente se vea más consistente con el propio Cairo y, por extensión, más parecido a Rust. Incluso a expensas de un código más engorroso, los beneficios de seguridad valen la pena.
En este artículo, no hemos tocado todo sobre la nueva sintaxis, especialmente cómo interactúa con otros contratos inteligentes, pero puede leer el registro de cambios del compilador, leer esta publicación en el foro o ver un video en el canal de YouTube de StarkWare para obtener más información. al respecto Para saber más información.
Esta nueva versión del compilador estará disponible en la red de prueba de Starknet en unas pocas semanas y en la red principal en unas pocas semanas, así que no intentes implementar este código todavía, todavía no funcionará.
El Cairo sigue mejorando.
recurso